blob: a6bad51d1337fc7556905ea7513aff5d58376d4d [file] [log] [blame]
Daniel Dunbara5677512009-01-05 19:53:30 +00001class Option(object):
2 """Root option class."""
3 def __init__(self, name):
4 self.name = name
5
6 def accept(self, index, arg, it):
7 """accept(index, arg, iterator) -> Arg or None
8
9 Accept the argument at the given index, returning an Arg, or
10 return None if the option does not accept this argument.
11
12 May raise MissingArgumentError.
13 """
14 abstract
15
16 def __repr__(self):
17 return '<%s name=%r>' % (self.__class__.__name__,
18 self.name)
19
Daniel Dunbar5039f212009-01-06 02:30:10 +000020# Dummy options
21
22class InputOption(Option):
23 def __init__(self):
24 super(InputOption, self).__init__('<input>')
25
26 def accept(self):
27 raise RuntimeError,"accept() should never be used on InputOption instance."
28
29class UnknownOption(Option):
30 def __init__(self):
31 super(UnknownOption, self).__init__('<unknown>')
32
33 def accept(self):
34 raise RuntimeError,"accept() should never be used on UnknownOption instance."
35
36# Normal options
37
Daniel Dunbara5677512009-01-05 19:53:30 +000038class FlagOption(Option):
39 """An option which takes no arguments."""
40
41 def accept(self, index, arg, it):
42 if arg == self.name:
43 return Arg(index, self)
44
45class JoinedOption(Option):
46 """An option which literally prefixes its argument."""
47
48 def accept(self, index, arg, it):
49 if arg.startswith(self.name):
50 return JoinedValueArg(index, self)
51
52class SeparateOption(Option):
53 """An option which is followed by its value."""
54
55 def accept(self, index, arg, it):
56 if arg == self.name:
57 try:
58 _,value = it.next()
59 except StopIteration:
60 raise MissingArgumentError,self
61 return SeparateValueArg(index, self)
62
63class MultiArgOption(Option):
64 """An option which takes multiple arguments."""
65
66 def __init__(self, name, numArgs):
67 assert numArgs > 1
68 super(MultiArgOption, self).__init__(name)
69 self.numArgs = numArgs
70
71 def accept(self, index, arg, it):
72 if arg.startswith(self.name):
73 try:
74 values = [it.next()[1] for i in range(self.numArgs)]
75 except StopIteration:
76 raise MissingArgumentError,self
77 return MultipleValuesArg(index, self)
78
79class JoinedOrSeparateOption(Option):
80 """An option which either literally prefixes its value or is
81 followed by an value."""
82
83 def accept(self, index, arg, it):
84 if arg.startswith(self.name):
85 if len(arg) != len(self.name): # Joined case
86 return JoinedValueArg(index, self)
87 else:
88 try:
89 _,value = it.next()
90 except StopIteration:
91 raise MissingArgumentError,self
92 return SeparateValueArg(index, self)
93
94class JoinedAndSeparateOption(Option):
95 """An option which literally prefixes its value and is followed by
96 an value."""
97
98 def accept(self, index, arg, it):
99 if arg.startswith(self.name):
100 try:
101 _,value = it.next()
102 except StopIteration:
103 raise MissingArgumentError,self
104 return JoinedAndSeparateValuesArg(index, self)
105
106###
107
108class Arg(object):
109 """Arg - Base class for actual driver arguments."""
110 def __init__(self, index, opt):
Daniel Dunbar5039f212009-01-06 02:30:10 +0000111 assert opt is not None
Daniel Dunbara5677512009-01-05 19:53:30 +0000112 self.index = index
113 self.opt = opt
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000114
Daniel Dunbara5677512009-01-05 19:53:30 +0000115 def __repr__(self):
116 return '<%s index=%r opt=%r>' % (self.__class__.__name__,
117 self.index,
118 self.opt)
119
120 def render(self, args):
121 """render(args) -> [str]
122
123 Map the argument into a list of actual program arguments,
124 given the source argument array."""
125 assert self.opt
126 return [self.opt.name]
127
128class ValueArg(Arg):
129 """ValueArg - An instance of an option which has an argument."""
130
131 def getValue(self, args):
132 abstract
133
Daniel Dunbar5039f212009-01-06 02:30:10 +0000134class PositionalArg(ValueArg):
135 """PositionalArg - A simple positional argument."""
Daniel Dunbara5677512009-01-05 19:53:30 +0000136
137 def getValue(self, args):
138 return args[self.index]
Daniel Dunbara5677512009-01-05 19:53:30 +0000139
140 def render(self, args):
141 return [args[self.index]]
142
143class JoinedValueArg(ValueArg):
Daniel Dunbar5039f212009-01-06 02:30:10 +0000144 """JoinedValueArg - A single value argument where the value is
145 joined (suffixed) to the option."""
146
Daniel Dunbara5677512009-01-05 19:53:30 +0000147 def getValue(self, args):
148 return args[self.index][len(self.opt.name):]
149
Daniel Dunbara5677512009-01-05 19:53:30 +0000150 def render(self, args):
151 return [self.opt.name + self.getValue(args)]
152
153class SeparateValueArg(ValueArg):
Daniel Dunbar5039f212009-01-06 02:30:10 +0000154 """SeparateValueArg - A single value argument where the value
155 follows the option in the argument vector."""
156
Daniel Dunbara5677512009-01-05 19:53:30 +0000157 def getValue(self, args):
158 return args[self.index+1]
159
Daniel Dunbara5677512009-01-05 19:53:30 +0000160 def render(self, args):
161 return [self.opt.name, self.getValue(args)]
162
163class MultipleValuesArg(Arg):
Daniel Dunbar5039f212009-01-06 02:30:10 +0000164 """MultipleValuesArg - An argument with multiple values which
165 follow the option in the argument vector."""
166
167 # FIXME: Should we unify this with SeparateValueArg?
168
Daniel Dunbara5677512009-01-05 19:53:30 +0000169 def getValues(self, args):
170 return args[self.index + 1:self.index + 1 + self.opt.numArgs]
171
Daniel Dunbara5677512009-01-05 19:53:30 +0000172 def render(self, args):
173 return [self.opt.name] + self.getValues(args)
174
175# FIXME: Man, this is lame. It is only used by -Xarch. Maybe easier to
176# just special case?
177class JoinedAndSeparateValuesArg(Arg):
178 """JoinedAndSeparateValuesArg - An argument with both joined and
179 separate values."""
180
181 def getJoinedValue(self, args):
182 return args[self.index][len(self.opt.name):]
183
184 def getSeparateValue(self, args):
185 return args[self.index+1]
186
187 def setJoinedValue(self, args, value):
188 assert self.opt.name == args[self.index][:len(self.opt.name)]
189 args[self.index] = self.opt.name + value
190
191 def setSeparateValue(self, args, vaue):
192 args[self.index+1] = value
193
194 def render(self, args):
195 return ([self.opt.name + self.getJoinedValue(args)] +
196 [self.getSeparateValue(args)])
197
Daniel Dunbara5677512009-01-05 19:53:30 +0000198class DerivedArg(ValueArg):
199 """DerivedArg - A synthesized argument which does not correspend
Daniel Dunbar5039f212009-01-06 02:30:10 +0000200 to an item in the argument vector."""
Daniel Dunbara5677512009-01-05 19:53:30 +0000201
202 def __init__(self, value):
Daniel Dunbar5039f212009-01-06 02:30:10 +0000203 # FIXME: The UnknownOption() here is a total hack so we can
204 # rely on arg.opt not being nil. Ok for now since DerivedArg
205 # is dying.
206 super(DerivedArg, self).__init__(-1, UnknownOption())
Daniel Dunbara5677512009-01-05 19:53:30 +0000207 self.value = value
208
209 def getValue(self, args):
210 return self.value
211
Daniel Dunbara5677512009-01-05 19:53:30 +0000212 def render(self, args):
213 return [self.value]
214
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000215class ArgList:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000216 """ArgList - Collect an input argument vector along with a set of parsed Args
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000217 and supporting information."""
218
219 def __init__(self, argv):
220 self.argv = list(argv)
221 self.args = []
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000222 self.lastArgs = {}
223
224 def getLastArg(self, option):
225 return self.lastArgs.get(option)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000226
227 # Support use as a simple arg list.
228
229 def __iter__(self):
230 return iter(self.args)
231
232 def append(self, arg):
233 self.args.append(arg)
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000234 self.lastArgs[arg.opt] = arg
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000235
236 # Forwarding methods.
237
238 def getValue(self, arg):
239 return arg.getValue(self.argv)
240
241 def getValues(self, arg):
242 return arg.getValues(self.argv)
243
244 def getSeparateValue(self, arg):
245 return arg.getSeparateValue(self.argv)
246
247 def getJoinedValue(self, arg):
248 return arg.getJoinedValue(self.argv)
Daniel Dunbar1dd2ada2009-01-06 06:32:49 +0000249
250###
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000251
Daniel Dunbara5677512009-01-05 19:53:30 +0000252class OptionParser:
253 def __init__(self):
254 self.options = []
Daniel Dunbar5039f212009-01-06 02:30:10 +0000255 self.inputOption = InputOption()
256 self.unknownOption = UnknownOption()
257
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000258 # Driver driver options
259 self.archOption = self.addOption(SeparateOption('-arch'))
260
261 # Misc driver options
262 self.addOption(FlagOption('-pass-exit-codes'))
263 self.addOption(FlagOption('--help'))
264 self.addOption(FlagOption('--target-help'))
265
266 self.dumpspecsOption = self.addOption(FlagOption('-dumpspecs'))
267 self.dumpversionOption = self.addOption(FlagOption('-dumpversion'))
268 self.dumpmachineOption = self.addOption(FlagOption('-dumpmachine'))
269 self.printSearchDirsOption = self.addOption(FlagOption('-print-search-dirs'))
270 self.printLibgccFilenameOption = self.addOption(FlagOption('-print-libgcc-file-name'))
271 # FIXME: Hrm, where does this come from? It isn't always true that
272 # we take both - and --. For example, gcc --S ... ends up sending
273 # -fS to cc1. Investigate.
274 #
275 # FIXME: Need to implement some form of alias support inside
276 # getLastOption to handle this.
277 self.printLibgccFileNameOption2 = self.addOption(FlagOption('--print-libgcc-file-name'))
278 self.printFileNameOption = self.addOption(JoinedOption('-print-file-name='))
279 self.printProgNameOption = self.addOption(JoinedOption('-print-prog-name='))
280 self.printProgNameOption2 = self.addOption(JoinedOption('--print-prog-name='))
281 self.printMultiDirectoryOption = self.addOption(FlagOption('-print-multi-directory'))
282 self.printMultiLibOption = self.addOption(FlagOption('-print-multi-lib'))
283 self.addOption(FlagOption('-print-multi-os-directory'))
284
285 # Hmmm, who really takes this?
286 self.addOption(FlagOption('--version'))
287
288 # Pipeline control
289 self.hashHashHashOption = self.addOption(FlagOption('-###'))
290 self.EOption = self.addOption(FlagOption('-E'))
291 self.SOption = self.addOption(FlagOption('-S'))
292 self.cOption = self.addOption(FlagOption('-c'))
293 self.combineOption = self.addOption(FlagOption('-combine'))
294 self.noIntegratedCPPOption = self.addOption(FlagOption('-no-integrated-cpp'))
295 self.pipeOption = self.addOption(FlagOption('-pipe'))
296 self.saveTempsOption = self.addOption(FlagOption('-save-temps'))
297 self.saveTempsOption2 = self.addOption(FlagOption('--save-temps'))
298 self.addOption(JoinedOption('-specs='))
299 self.addOption(FlagOption('-time'))
300 self.addOption(FlagOption('-v'))
301
302 # Input/output stuff
303 self.oOption = self.addOption(JoinedOrSeparateOption('-o'))
304 self.xOption = self.addOption(JoinedOrSeparateOption('-x'))
305
306 # FIXME: What do these actually do? The documentation is less than
307 # clear.
308 self.addOption(FlagOption('-ObjC'))
309 self.addOption(FlagOption('-ObjC++'))
310
311 # FIXME: Weird, gcc claims this here in help but I'm not sure why;
312 # perhaps interaction with preprocessor? Investigate.
313 self.addOption(JoinedOption('-std='))
314 self.addOption(JoinedOrSeparateOption('--sysroot'))
315
316 # Version control
317 self.addOption(JoinedOrSeparateOption('-B'))
318 self.addOption(JoinedOrSeparateOption('-V'))
319 self.addOption(JoinedOrSeparateOption('-b'))
320
321 # Blanket pass-through options.
322
323 self.addOption(JoinedOption('-Wa,'))
324 self.addOption(SeparateOption('-Xassembler'))
325
326 self.addOption(JoinedOption('-Wp,'))
327 self.addOption(SeparateOption('-Xpreprocessor'))
328
329 self.addOption(JoinedOption('-Wl,'))
330 self.addOption(SeparateOption('-Xlinker'))
331
332 ####
333 # Bring on the random garbage.
334
335 self.addOption(FlagOption('-MD'))
336 self.addOption(FlagOption('-MP'))
337 self.addOption(FlagOption('-MM'))
338 self.addOption(JoinedOrSeparateOption('-MF'))
339 self.addOption(JoinedOrSeparateOption('-MT'))
340 self.addOption(FlagOption('-undef'))
341
342 self.addOption(FlagOption('-w'))
343 self.addOption(JoinedOrSeparateOption('-allowable_client'))
344 self.addOption(JoinedOrSeparateOption('-client_name'))
345 self.addOption(JoinedOrSeparateOption('-compatibility_version'))
346 self.addOption(JoinedOrSeparateOption('-current_version'))
347 self.addOption(JoinedOrSeparateOption('-exported_symbols_list'))
348 self.addOption(JoinedOrSeparateOption('-idirafter'))
349 self.addOption(JoinedOrSeparateOption('-iquote'))
350 self.addOption(JoinedOrSeparateOption('-isysroot'))
351 self.addOption(JoinedOrSeparateOption('-keep_private_externs'))
352 self.addOption(JoinedOrSeparateOption('-seg1addr'))
353 self.addOption(JoinedOrSeparateOption('-segprot'))
354 self.addOption(JoinedOrSeparateOption('-sub_library'))
355 self.addOption(JoinedOrSeparateOption('-sub_umbrella'))
356 self.addOption(JoinedOrSeparateOption('-umbrella'))
357 self.addOption(JoinedOrSeparateOption('-undefined'))
358 self.addOption(JoinedOrSeparateOption('-unexported_symbols_list'))
359 self.addOption(JoinedOrSeparateOption('-weak_framework'))
360 self.addOption(JoinedOption('-headerpad_max_install_names'))
361 self.addOption(FlagOption('-twolevel_namespace'))
362 self.addOption(FlagOption('-prebind'))
363 self.addOption(FlagOption('-prebind_all_twolevel_modules'))
364 self.addOption(FlagOption('-single_module'))
365 self.addOption(FlagOption('-nomultidefs'))
366 self.addOption(FlagOption('-nostdlib'))
367 self.addOption(FlagOption('-nostdinc'))
368 self.addOption(FlagOption('-static'))
369 self.addOption(FlagOption('-shared'))
370 self.addOption(FlagOption('-C'))
371 self.addOption(FlagOption('-CC'))
372 self.addOption(FlagOption('-R'))
373 self.addOption(FlagOption('-P'))
374 self.addOption(FlagOption('-all_load'))
375 self.addOption(FlagOption('--constant-cfstrings'))
376 self.addOption(FlagOption('-traditional'))
377 self.addOption(FlagOption('--traditional'))
378 self.addOption(FlagOption('-no_dead_strip_inits_and_terms'))
379 self.addOption(MultiArgOption('-sectalign', numArgs=3))
380 self.addOption(MultiArgOption('-sectcreate', numArgs=3))
381 self.addOption(MultiArgOption('-sectorder', numArgs=3))
382
383 # I dunno why these don't end up working when joined. Maybe
384 # because of translation?
385 self.filelistOption = self.addOption(SeparateOption('-filelist'))
386 self.addOption(SeparateOption('-framework'))
387 self.addOption(SeparateOption('-install_name'))
388 self.addOption(SeparateOption('-seg_addr_table'))
389 self.addOption(SeparateOption('-seg_addr_table_filename'))
390
391 # Where are these coming from? I can't find them...
392 self.addOption(JoinedOrSeparateOption('-e')) # Gets forwarded to linker
393 self.addOption(JoinedOrSeparateOption('-r'))
394
395 # Is this actually declared anywhere? I can only find it in a
396 # spec. :(
397 self.addOption(FlagOption('-pg'))
398
399 doNotReallySupport = 1
400 if doNotReallySupport:
401 # Archaic gcc option.
402 self.addOption(FlagOption('-cpp-precomp'))
403 self.addOption(FlagOption('-no-cpp-precomp'))
404
405 # C options for testing
406
407 self.addOption(JoinedOrSeparateOption('-include'))
408 self.addOption(JoinedOrSeparateOption('-A'))
409 self.addOption(JoinedOrSeparateOption('-D'))
410 self.addOption(JoinedOrSeparateOption('-F'))
411 self.addOption(JoinedOrSeparateOption('-I'))
412 self.addOption(JoinedOrSeparateOption('-L'))
413 self.addOption(JoinedOrSeparateOption('-U'))
414 self.addOption(JoinedOrSeparateOption('-l'))
415 self.addOption(JoinedOrSeparateOption('-u'))
416
417 # FIXME: What is going on here? '-X' goes to linker, and -X ... goes nowhere?
418 self.addOption(FlagOption('-X'))
419 # Not exactly sure how to decompose this. I split out -Xarch_
420 # because we need to recognize that in the driver driver part.
421 # FIXME: Man, this is lame it needs its own option.
422 self.XarchOption = self.addOption(JoinedAndSeparateOption('-Xarch_'))
423 self.addOption(JoinedOption('-X'))
424
425 # The driver needs to know about this flag.
426 self.syntaxOnlyOption = self.addOption(FlagOption('-fsyntax-only'))
427
428 # FIXME: Wrong?
429 # FIXME: What to do about the ambiguity of options like
430 # -dumpspecs? How is this handled in gcc?
431 self.addOption(JoinedOption('-d'))
432 self.addOption(JoinedOption('-g'))
433 self.addOption(JoinedOption('-f'))
434 self.addOption(JoinedOption('-m'))
435 self.addOption(JoinedOption('-i'))
436 self.addOption(JoinedOption('-O'))
437 self.addOption(JoinedOption('-W'))
438 # FIXME: Weird. This option isn't really separate, --param=a=b
439 # works. An alias somewhere?
440 self.addOption(SeparateOption('--param'))
441
442 # FIXME: What is this? Seems to do something on Linux. I think
443 # only one is valid, but have a log that uses both.
444 self.addOption(FlagOption('-pthread'))
445 self.addOption(FlagOption('-pthreads'))
446
Daniel Dunbara5677512009-01-05 19:53:30 +0000447 def addOption(self, opt):
448 self.options.append(opt)
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000449 return opt
Daniel Dunbara5677512009-01-05 19:53:30 +0000450
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000451 def parseArgs(self, argv):
Daniel Dunbara5677512009-01-05 19:53:30 +0000452 """
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000453 parseArgs([str]) -> ArgList
Daniel Dunbara5677512009-01-05 19:53:30 +0000454
455 Parse command line into individual option instances.
456 """
457
458 iargs = enumerate(argv)
459 it = iter(iargs)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000460 args = ArgList(argv)
Daniel Dunbara5677512009-01-05 19:53:30 +0000461 for i,a in it:
462 # FIXME: Handle '@'
463 if not a:
464 # gcc's handling of empty arguments doesn't make
465 # sense, but this is not a common use case. :)
466 #
467 # We just ignore them here (note that other things may
468 # still take them as arguments).
469 pass
470 elif a[0] == '-' and a != '-':
471 args.append(self.lookupOptForArg(i, a, it))
472 else:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000473 args.append(PositionalArg(i, self.inputOption))
Daniel Dunbara5677512009-01-05 19:53:30 +0000474 return args
475
Daniel Dunbar5039f212009-01-06 02:30:10 +0000476 def lookupOptForArg(self, i, string, it):
477 for o in self.options:
478 arg = o.accept(i, string, it)
479 if arg is not None:
480 return arg
481 return PositionalArg(i, self.unknownOption)