blob: 486af4f1fb19ff8702417302406bba4a3d624d9b [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
134 def setValue(self, args, value):
135 abstract
136
Daniel Dunbar5039f212009-01-06 02:30:10 +0000137class PositionalArg(ValueArg):
138 """PositionalArg - A simple positional argument."""
Daniel Dunbara5677512009-01-05 19:53:30 +0000139
140 def getValue(self, args):
141 return args[self.index]
142
143 def setValue(self, args, value):
144 args[self.index] = value
145
146 def render(self, args):
147 return [args[self.index]]
148
149class JoinedValueArg(ValueArg):
Daniel Dunbar5039f212009-01-06 02:30:10 +0000150 """JoinedValueArg - A single value argument where the value is
151 joined (suffixed) to the option."""
152
Daniel Dunbara5677512009-01-05 19:53:30 +0000153 def getValue(self, args):
154 return args[self.index][len(self.opt.name):]
155
156 def setValue(self, args, value):
157 assert self.opt.name == args[self.index][:len(self.opt.name)]
158 args[self.index] = self.opt.name + value
159
160 def render(self, args):
161 return [self.opt.name + self.getValue(args)]
162
163class SeparateValueArg(ValueArg):
Daniel Dunbar5039f212009-01-06 02:30:10 +0000164 """SeparateValueArg - A single value argument where the value
165 follows the option in the argument vector."""
166
Daniel Dunbara5677512009-01-05 19:53:30 +0000167 def getValue(self, args):
168 return args[self.index+1]
169
170 def setValue(self, args, value):
171 args[self.index+1] = value
172
173 def render(self, args):
174 return [self.opt.name, self.getValue(args)]
175
176class MultipleValuesArg(Arg):
Daniel Dunbar5039f212009-01-06 02:30:10 +0000177 """MultipleValuesArg - An argument with multiple values which
178 follow the option in the argument vector."""
179
180 # FIXME: Should we unify this with SeparateValueArg?
181
Daniel Dunbara5677512009-01-05 19:53:30 +0000182 def getValues(self, args):
183 return args[self.index + 1:self.index + 1 + self.opt.numArgs]
184
185 def setValues(self, args, value):
186 assert self.opt.numArgs == len(value)
187 args[self.index + 1:self.index + 1 + self.opt.numArgs] = value
188
189 def render(self, args):
190 return [self.opt.name] + self.getValues(args)
191
192# FIXME: Man, this is lame. It is only used by -Xarch. Maybe easier to
193# just special case?
194class JoinedAndSeparateValuesArg(Arg):
195 """JoinedAndSeparateValuesArg - An argument with both joined and
196 separate values."""
197
198 def getJoinedValue(self, args):
199 return args[self.index][len(self.opt.name):]
200
201 def getSeparateValue(self, args):
202 return args[self.index+1]
203
204 def setJoinedValue(self, args, value):
205 assert self.opt.name == args[self.index][:len(self.opt.name)]
206 args[self.index] = self.opt.name + value
207
208 def setSeparateValue(self, args, vaue):
209 args[self.index+1] = value
210
211 def render(self, args):
212 return ([self.opt.name + self.getJoinedValue(args)] +
213 [self.getSeparateValue(args)])
214
Daniel Dunbara5677512009-01-05 19:53:30 +0000215class DerivedArg(ValueArg):
216 """DerivedArg - A synthesized argument which does not correspend
Daniel Dunbar5039f212009-01-06 02:30:10 +0000217 to an item in the argument vector."""
Daniel Dunbara5677512009-01-05 19:53:30 +0000218
219 def __init__(self, value):
Daniel Dunbar5039f212009-01-06 02:30:10 +0000220 # FIXME: The UnknownOption() here is a total hack so we can
221 # rely on arg.opt not being nil. Ok for now since DerivedArg
222 # is dying.
223 super(DerivedArg, self).__init__(-1, UnknownOption())
Daniel Dunbara5677512009-01-05 19:53:30 +0000224 self.value = value
225
226 def getValue(self, args):
227 return self.value
228
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000229 def setValue(self, args, value):
Daniel Dunbara5677512009-01-05 19:53:30 +0000230 raise ValueError,"Cannot call setValue() on a DerivedArg."
231
232 def render(self, args):
233 return [self.value]
234
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000235class ArgList:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000236 """ArgList - Collect an input argument vector along with a set of parsed Args
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000237 and supporting information."""
238
239 def __init__(self, argv):
240 self.argv = list(argv)
241 self.args = []
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000242 self.lastArgs = {}
243
244 def getLastArg(self, option):
245 return self.lastArgs.get(option)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000246
247 # Support use as a simple arg list.
248
249 def __iter__(self):
250 return iter(self.args)
251
252 def append(self, arg):
253 self.args.append(arg)
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000254 self.lastArgs[arg.opt] = arg
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000255
256 # Forwarding methods.
257
258 def getValue(self, arg):
259 return arg.getValue(self.argv)
260
261 def getValues(self, arg):
262 return arg.getValues(self.argv)
263
264 def getSeparateValue(self, arg):
265 return arg.getSeparateValue(self.argv)
266
267 def getJoinedValue(self, arg):
268 return arg.getJoinedValue(self.argv)
269
Daniel Dunbara5677512009-01-05 19:53:30 +0000270class OptionParser:
271 def __init__(self):
272 self.options = []
Daniel Dunbar5039f212009-01-06 02:30:10 +0000273 self.inputOption = InputOption()
274 self.unknownOption = UnknownOption()
275
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000276 # Driver driver options
277 self.archOption = self.addOption(SeparateOption('-arch'))
278
279 # Misc driver options
280 self.addOption(FlagOption('-pass-exit-codes'))
281 self.addOption(FlagOption('--help'))
282 self.addOption(FlagOption('--target-help'))
283
284 self.dumpspecsOption = self.addOption(FlagOption('-dumpspecs'))
285 self.dumpversionOption = self.addOption(FlagOption('-dumpversion'))
286 self.dumpmachineOption = self.addOption(FlagOption('-dumpmachine'))
287 self.printSearchDirsOption = self.addOption(FlagOption('-print-search-dirs'))
288 self.printLibgccFilenameOption = self.addOption(FlagOption('-print-libgcc-file-name'))
289 # FIXME: Hrm, where does this come from? It isn't always true that
290 # we take both - and --. For example, gcc --S ... ends up sending
291 # -fS to cc1. Investigate.
292 #
293 # FIXME: Need to implement some form of alias support inside
294 # getLastOption to handle this.
295 self.printLibgccFileNameOption2 = self.addOption(FlagOption('--print-libgcc-file-name'))
296 self.printFileNameOption = self.addOption(JoinedOption('-print-file-name='))
297 self.printProgNameOption = self.addOption(JoinedOption('-print-prog-name='))
298 self.printProgNameOption2 = self.addOption(JoinedOption('--print-prog-name='))
299 self.printMultiDirectoryOption = self.addOption(FlagOption('-print-multi-directory'))
300 self.printMultiLibOption = self.addOption(FlagOption('-print-multi-lib'))
301 self.addOption(FlagOption('-print-multi-os-directory'))
302
303 # Hmmm, who really takes this?
304 self.addOption(FlagOption('--version'))
305
306 # Pipeline control
307 self.hashHashHashOption = self.addOption(FlagOption('-###'))
308 self.EOption = self.addOption(FlagOption('-E'))
309 self.SOption = self.addOption(FlagOption('-S'))
310 self.cOption = self.addOption(FlagOption('-c'))
311 self.combineOption = self.addOption(FlagOption('-combine'))
312 self.noIntegratedCPPOption = self.addOption(FlagOption('-no-integrated-cpp'))
313 self.pipeOption = self.addOption(FlagOption('-pipe'))
314 self.saveTempsOption = self.addOption(FlagOption('-save-temps'))
315 self.saveTempsOption2 = self.addOption(FlagOption('--save-temps'))
316 self.addOption(JoinedOption('-specs='))
317 self.addOption(FlagOption('-time'))
318 self.addOption(FlagOption('-v'))
319
320 # Input/output stuff
321 self.oOption = self.addOption(JoinedOrSeparateOption('-o'))
322 self.xOption = self.addOption(JoinedOrSeparateOption('-x'))
323
324 # FIXME: What do these actually do? The documentation is less than
325 # clear.
326 self.addOption(FlagOption('-ObjC'))
327 self.addOption(FlagOption('-ObjC++'))
328
329 # FIXME: Weird, gcc claims this here in help but I'm not sure why;
330 # perhaps interaction with preprocessor? Investigate.
331 self.addOption(JoinedOption('-std='))
332 self.addOption(JoinedOrSeparateOption('--sysroot'))
333
334 # Version control
335 self.addOption(JoinedOrSeparateOption('-B'))
336 self.addOption(JoinedOrSeparateOption('-V'))
337 self.addOption(JoinedOrSeparateOption('-b'))
338
339 # Blanket pass-through options.
340
341 self.addOption(JoinedOption('-Wa,'))
342 self.addOption(SeparateOption('-Xassembler'))
343
344 self.addOption(JoinedOption('-Wp,'))
345 self.addOption(SeparateOption('-Xpreprocessor'))
346
347 self.addOption(JoinedOption('-Wl,'))
348 self.addOption(SeparateOption('-Xlinker'))
349
350 ####
351 # Bring on the random garbage.
352
353 self.addOption(FlagOption('-MD'))
354 self.addOption(FlagOption('-MP'))
355 self.addOption(FlagOption('-MM'))
356 self.addOption(JoinedOrSeparateOption('-MF'))
357 self.addOption(JoinedOrSeparateOption('-MT'))
358 self.addOption(FlagOption('-undef'))
359
360 self.addOption(FlagOption('-w'))
361 self.addOption(JoinedOrSeparateOption('-allowable_client'))
362 self.addOption(JoinedOrSeparateOption('-client_name'))
363 self.addOption(JoinedOrSeparateOption('-compatibility_version'))
364 self.addOption(JoinedOrSeparateOption('-current_version'))
365 self.addOption(JoinedOrSeparateOption('-exported_symbols_list'))
366 self.addOption(JoinedOrSeparateOption('-idirafter'))
367 self.addOption(JoinedOrSeparateOption('-iquote'))
368 self.addOption(JoinedOrSeparateOption('-isysroot'))
369 self.addOption(JoinedOrSeparateOption('-keep_private_externs'))
370 self.addOption(JoinedOrSeparateOption('-seg1addr'))
371 self.addOption(JoinedOrSeparateOption('-segprot'))
372 self.addOption(JoinedOrSeparateOption('-sub_library'))
373 self.addOption(JoinedOrSeparateOption('-sub_umbrella'))
374 self.addOption(JoinedOrSeparateOption('-umbrella'))
375 self.addOption(JoinedOrSeparateOption('-undefined'))
376 self.addOption(JoinedOrSeparateOption('-unexported_symbols_list'))
377 self.addOption(JoinedOrSeparateOption('-weak_framework'))
378 self.addOption(JoinedOption('-headerpad_max_install_names'))
379 self.addOption(FlagOption('-twolevel_namespace'))
380 self.addOption(FlagOption('-prebind'))
381 self.addOption(FlagOption('-prebind_all_twolevel_modules'))
382 self.addOption(FlagOption('-single_module'))
383 self.addOption(FlagOption('-nomultidefs'))
384 self.addOption(FlagOption('-nostdlib'))
385 self.addOption(FlagOption('-nostdinc'))
386 self.addOption(FlagOption('-static'))
387 self.addOption(FlagOption('-shared'))
388 self.addOption(FlagOption('-C'))
389 self.addOption(FlagOption('-CC'))
390 self.addOption(FlagOption('-R'))
391 self.addOption(FlagOption('-P'))
392 self.addOption(FlagOption('-all_load'))
393 self.addOption(FlagOption('--constant-cfstrings'))
394 self.addOption(FlagOption('-traditional'))
395 self.addOption(FlagOption('--traditional'))
396 self.addOption(FlagOption('-no_dead_strip_inits_and_terms'))
397 self.addOption(MultiArgOption('-sectalign', numArgs=3))
398 self.addOption(MultiArgOption('-sectcreate', numArgs=3))
399 self.addOption(MultiArgOption('-sectorder', numArgs=3))
400
401 # I dunno why these don't end up working when joined. Maybe
402 # because of translation?
403 self.filelistOption = self.addOption(SeparateOption('-filelist'))
404 self.addOption(SeparateOption('-framework'))
405 self.addOption(SeparateOption('-install_name'))
406 self.addOption(SeparateOption('-seg_addr_table'))
407 self.addOption(SeparateOption('-seg_addr_table_filename'))
408
409 # Where are these coming from? I can't find them...
410 self.addOption(JoinedOrSeparateOption('-e')) # Gets forwarded to linker
411 self.addOption(JoinedOrSeparateOption('-r'))
412
413 # Is this actually declared anywhere? I can only find it in a
414 # spec. :(
415 self.addOption(FlagOption('-pg'))
416
417 doNotReallySupport = 1
418 if doNotReallySupport:
419 # Archaic gcc option.
420 self.addOption(FlagOption('-cpp-precomp'))
421 self.addOption(FlagOption('-no-cpp-precomp'))
422
423 # C options for testing
424
425 self.addOption(JoinedOrSeparateOption('-include'))
426 self.addOption(JoinedOrSeparateOption('-A'))
427 self.addOption(JoinedOrSeparateOption('-D'))
428 self.addOption(JoinedOrSeparateOption('-F'))
429 self.addOption(JoinedOrSeparateOption('-I'))
430 self.addOption(JoinedOrSeparateOption('-L'))
431 self.addOption(JoinedOrSeparateOption('-U'))
432 self.addOption(JoinedOrSeparateOption('-l'))
433 self.addOption(JoinedOrSeparateOption('-u'))
434
435 # FIXME: What is going on here? '-X' goes to linker, and -X ... goes nowhere?
436 self.addOption(FlagOption('-X'))
437 # Not exactly sure how to decompose this. I split out -Xarch_
438 # because we need to recognize that in the driver driver part.
439 # FIXME: Man, this is lame it needs its own option.
440 self.XarchOption = self.addOption(JoinedAndSeparateOption('-Xarch_'))
441 self.addOption(JoinedOption('-X'))
442
443 # The driver needs to know about this flag.
444 self.syntaxOnlyOption = self.addOption(FlagOption('-fsyntax-only'))
445
446 # FIXME: Wrong?
447 # FIXME: What to do about the ambiguity of options like
448 # -dumpspecs? How is this handled in gcc?
449 self.addOption(JoinedOption('-d'))
450 self.addOption(JoinedOption('-g'))
451 self.addOption(JoinedOption('-f'))
452 self.addOption(JoinedOption('-m'))
453 self.addOption(JoinedOption('-i'))
454 self.addOption(JoinedOption('-O'))
455 self.addOption(JoinedOption('-W'))
456 # FIXME: Weird. This option isn't really separate, --param=a=b
457 # works. An alias somewhere?
458 self.addOption(SeparateOption('--param'))
459
460 # FIXME: What is this? Seems to do something on Linux. I think
461 # only one is valid, but have a log that uses both.
462 self.addOption(FlagOption('-pthread'))
463 self.addOption(FlagOption('-pthreads'))
464
Daniel Dunbara5677512009-01-05 19:53:30 +0000465 def addOption(self, opt):
466 self.options.append(opt)
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000467 return opt
Daniel Dunbara5677512009-01-05 19:53:30 +0000468
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000469 def parseArgs(self, argv):
Daniel Dunbara5677512009-01-05 19:53:30 +0000470 """
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000471 parseArgs([str]) -> ArgList
Daniel Dunbara5677512009-01-05 19:53:30 +0000472
473 Parse command line into individual option instances.
474 """
475
476 iargs = enumerate(argv)
477 it = iter(iargs)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000478 args = ArgList(argv)
Daniel Dunbara5677512009-01-05 19:53:30 +0000479 for i,a in it:
480 # FIXME: Handle '@'
481 if not a:
482 # gcc's handling of empty arguments doesn't make
483 # sense, but this is not a common use case. :)
484 #
485 # We just ignore them here (note that other things may
486 # still take them as arguments).
487 pass
488 elif a[0] == '-' and a != '-':
489 args.append(self.lookupOptForArg(i, a, it))
490 else:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000491 args.append(PositionalArg(i, self.inputOption))
Daniel Dunbara5677512009-01-05 19:53:30 +0000492 return args
493
Daniel Dunbar5039f212009-01-06 02:30:10 +0000494 def lookupOptForArg(self, i, string, it):
495 for o in self.options:
496 arg = o.accept(i, string, it)
497 if arg is not None:
498 return arg
499 return PositionalArg(i, self.unknownOption)