blob: 06367890ab5f0ce74f5c061f9a531214489e2a5e [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):
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000138 return args.getInputString(self.index)
Daniel Dunbara5677512009-01-05 19:53:30 +0000139
140 def render(self, args):
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000141 return [args.getInputString(self.index)]
Daniel Dunbara5677512009-01-05 19:53:30 +0000142
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):
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000148 return args.getInputString(self.index)[len(self.opt.name):]
Daniel Dunbara5677512009-01-05 19:53:30 +0000149
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):
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000158 return args.getInputString(self.index, offset=1)
Daniel Dunbara5677512009-01-05 19:53:30 +0000159
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):
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000170 return [args.getInputString(self.index, offset=1+i)
171 for i in range(self.opt.numArgs)]
Daniel Dunbara5677512009-01-05 19:53:30 +0000172
Daniel Dunbara5677512009-01-05 19:53:30 +0000173 def render(self, args):
174 return [self.opt.name] + self.getValues(args)
175
176# FIXME: Man, this is lame. It is only used by -Xarch. Maybe easier to
177# just special case?
178class JoinedAndSeparateValuesArg(Arg):
179 """JoinedAndSeparateValuesArg - An argument with both joined and
180 separate values."""
181
182 def getJoinedValue(self, args):
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000183 return args.getInputString(self.index)[len(self.opt.name):]
Daniel Dunbara5677512009-01-05 19:53:30 +0000184
185 def getSeparateValue(self, args):
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000186 return args.getInputString(self.index, offset=1)
Daniel Dunbara5677512009-01-05 19:53:30 +0000187
188 def render(self, args):
189 return ([self.opt.name + self.getJoinedValue(args)] +
190 [self.getSeparateValue(args)])
191
Daniel Dunbara5677512009-01-05 19:53:30 +0000192class DerivedArg(ValueArg):
193 """DerivedArg - A synthesized argument which does not correspend
Daniel Dunbar5039f212009-01-06 02:30:10 +0000194 to an item in the argument vector."""
Daniel Dunbara5677512009-01-05 19:53:30 +0000195
196 def __init__(self, value):
Daniel Dunbar5039f212009-01-06 02:30:10 +0000197 # FIXME: The UnknownOption() here is a total hack so we can
198 # rely on arg.opt not being nil. Ok for now since DerivedArg
199 # is dying.
200 super(DerivedArg, self).__init__(-1, UnknownOption())
Daniel Dunbara5677512009-01-05 19:53:30 +0000201 self.value = value
202
203 def getValue(self, args):
204 return self.value
205
Daniel Dunbara5677512009-01-05 19:53:30 +0000206 def render(self, args):
207 return [self.value]
208
Daniel Dunbarefb4aeb2009-01-07 01:57:39 +0000209###
210
211class InputIndex:
212 def __init__(self, sourceId, pos):
213 self.sourceId = sourceId
214 self.pos = pos
215
216 def __repr__(self):
217 return 'InputIndex(%d, %d)' % (self.sourceId, self.pos)
218
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000219class ArgList:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000220 """ArgList - Collect an input argument vector along with a set of parsed Args
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000221 and supporting information."""
222
223 def __init__(self, argv):
224 self.argv = list(argv)
Daniel Dunbarefb4aeb2009-01-07 01:57:39 +0000225 self.syntheticArgv = []
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000226 self.lastArgs = {}
Daniel Dunbarefb4aeb2009-01-07 01:57:39 +0000227 self.args = []
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000228
229 def getLastArg(self, option):
230 return self.lastArgs.get(option)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000231
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000232 def getInputString(self, index, offset=0):
Daniel Dunbarefb4aeb2009-01-07 01:57:39 +0000233 # Source 0 is argv.
234 if index.sourceId == 0:
235 return self.argv[index.pos + offset]
236
237 # Source 1 is synthetic argv.
238 if index.sourceId == 1:
239 return self.syntheticArgv[index.pos + offset]
240
241 raise RuntimeError,'Unknown source ID for index.'
242
243 def getSyntheticIndex(self, *strings):
244 pos = len(self.syntheticArgv)
245 self.syntheticArgv.extend(strings)
246 return InputIndex(1, pos)
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000247
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000248 # Support use as a simple arg list.
249
250 def __iter__(self):
251 return iter(self.args)
252
253 def append(self, arg):
254 self.args.append(arg)
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000255 self.lastArgs[arg.opt] = arg
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000256
257 # Forwarding methods.
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000258 #
259 # FIXME: Clean this up once restructuring is done.
260
261 def render(self, arg):
262 return arg.render(self)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000263
264 def getValue(self, arg):
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000265 return arg.getValue(self)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000266
267 def getValues(self, arg):
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000268 return arg.getValues(self)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000269
270 def getSeparateValue(self, arg):
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000271 return arg.getSeparateValue(self)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000272
273 def getJoinedValue(self, arg):
Daniel Dunbarfb2c5c42009-01-07 01:29:28 +0000274 return arg.getJoinedValue(self)
Daniel Dunbar1dd2ada2009-01-06 06:32:49 +0000275
276###
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000277
Daniel Dunbara5677512009-01-05 19:53:30 +0000278class OptionParser:
279 def __init__(self):
280 self.options = []
Daniel Dunbar5039f212009-01-06 02:30:10 +0000281 self.inputOption = InputOption()
282 self.unknownOption = UnknownOption()
283
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000284 # Driver driver options
285 self.archOption = self.addOption(SeparateOption('-arch'))
286
287 # Misc driver options
288 self.addOption(FlagOption('-pass-exit-codes'))
289 self.addOption(FlagOption('--help'))
290 self.addOption(FlagOption('--target-help'))
291
292 self.dumpspecsOption = self.addOption(FlagOption('-dumpspecs'))
293 self.dumpversionOption = self.addOption(FlagOption('-dumpversion'))
294 self.dumpmachineOption = self.addOption(FlagOption('-dumpmachine'))
295 self.printSearchDirsOption = self.addOption(FlagOption('-print-search-dirs'))
296 self.printLibgccFilenameOption = self.addOption(FlagOption('-print-libgcc-file-name'))
297 # FIXME: Hrm, where does this come from? It isn't always true that
298 # we take both - and --. For example, gcc --S ... ends up sending
299 # -fS to cc1. Investigate.
300 #
301 # FIXME: Need to implement some form of alias support inside
302 # getLastOption to handle this.
303 self.printLibgccFileNameOption2 = self.addOption(FlagOption('--print-libgcc-file-name'))
304 self.printFileNameOption = self.addOption(JoinedOption('-print-file-name='))
305 self.printProgNameOption = self.addOption(JoinedOption('-print-prog-name='))
306 self.printProgNameOption2 = self.addOption(JoinedOption('--print-prog-name='))
307 self.printMultiDirectoryOption = self.addOption(FlagOption('-print-multi-directory'))
308 self.printMultiLibOption = self.addOption(FlagOption('-print-multi-lib'))
309 self.addOption(FlagOption('-print-multi-os-directory'))
310
311 # Hmmm, who really takes this?
312 self.addOption(FlagOption('--version'))
313
314 # Pipeline control
315 self.hashHashHashOption = self.addOption(FlagOption('-###'))
316 self.EOption = self.addOption(FlagOption('-E'))
317 self.SOption = self.addOption(FlagOption('-S'))
318 self.cOption = self.addOption(FlagOption('-c'))
319 self.combineOption = self.addOption(FlagOption('-combine'))
320 self.noIntegratedCPPOption = self.addOption(FlagOption('-no-integrated-cpp'))
321 self.pipeOption = self.addOption(FlagOption('-pipe'))
322 self.saveTempsOption = self.addOption(FlagOption('-save-temps'))
323 self.saveTempsOption2 = self.addOption(FlagOption('--save-temps'))
324 self.addOption(JoinedOption('-specs='))
325 self.addOption(FlagOption('-time'))
326 self.addOption(FlagOption('-v'))
327
328 # Input/output stuff
329 self.oOption = self.addOption(JoinedOrSeparateOption('-o'))
330 self.xOption = self.addOption(JoinedOrSeparateOption('-x'))
331
332 # FIXME: What do these actually do? The documentation is less than
333 # clear.
334 self.addOption(FlagOption('-ObjC'))
335 self.addOption(FlagOption('-ObjC++'))
336
337 # FIXME: Weird, gcc claims this here in help but I'm not sure why;
338 # perhaps interaction with preprocessor? Investigate.
339 self.addOption(JoinedOption('-std='))
340 self.addOption(JoinedOrSeparateOption('--sysroot'))
341
342 # Version control
343 self.addOption(JoinedOrSeparateOption('-B'))
344 self.addOption(JoinedOrSeparateOption('-V'))
345 self.addOption(JoinedOrSeparateOption('-b'))
346
347 # Blanket pass-through options.
348
349 self.addOption(JoinedOption('-Wa,'))
350 self.addOption(SeparateOption('-Xassembler'))
351
352 self.addOption(JoinedOption('-Wp,'))
353 self.addOption(SeparateOption('-Xpreprocessor'))
354
355 self.addOption(JoinedOption('-Wl,'))
356 self.addOption(SeparateOption('-Xlinker'))
357
358 ####
359 # Bring on the random garbage.
360
361 self.addOption(FlagOption('-MD'))
362 self.addOption(FlagOption('-MP'))
363 self.addOption(FlagOption('-MM'))
364 self.addOption(JoinedOrSeparateOption('-MF'))
365 self.addOption(JoinedOrSeparateOption('-MT'))
366 self.addOption(FlagOption('-undef'))
367
368 self.addOption(FlagOption('-w'))
369 self.addOption(JoinedOrSeparateOption('-allowable_client'))
370 self.addOption(JoinedOrSeparateOption('-client_name'))
371 self.addOption(JoinedOrSeparateOption('-compatibility_version'))
372 self.addOption(JoinedOrSeparateOption('-current_version'))
373 self.addOption(JoinedOrSeparateOption('-exported_symbols_list'))
374 self.addOption(JoinedOrSeparateOption('-idirafter'))
375 self.addOption(JoinedOrSeparateOption('-iquote'))
376 self.addOption(JoinedOrSeparateOption('-isysroot'))
377 self.addOption(JoinedOrSeparateOption('-keep_private_externs'))
378 self.addOption(JoinedOrSeparateOption('-seg1addr'))
379 self.addOption(JoinedOrSeparateOption('-segprot'))
380 self.addOption(JoinedOrSeparateOption('-sub_library'))
381 self.addOption(JoinedOrSeparateOption('-sub_umbrella'))
382 self.addOption(JoinedOrSeparateOption('-umbrella'))
383 self.addOption(JoinedOrSeparateOption('-undefined'))
384 self.addOption(JoinedOrSeparateOption('-unexported_symbols_list'))
385 self.addOption(JoinedOrSeparateOption('-weak_framework'))
386 self.addOption(JoinedOption('-headerpad_max_install_names'))
387 self.addOption(FlagOption('-twolevel_namespace'))
388 self.addOption(FlagOption('-prebind'))
389 self.addOption(FlagOption('-prebind_all_twolevel_modules'))
390 self.addOption(FlagOption('-single_module'))
391 self.addOption(FlagOption('-nomultidefs'))
392 self.addOption(FlagOption('-nostdlib'))
393 self.addOption(FlagOption('-nostdinc'))
394 self.addOption(FlagOption('-static'))
395 self.addOption(FlagOption('-shared'))
396 self.addOption(FlagOption('-C'))
397 self.addOption(FlagOption('-CC'))
398 self.addOption(FlagOption('-R'))
399 self.addOption(FlagOption('-P'))
400 self.addOption(FlagOption('-all_load'))
401 self.addOption(FlagOption('--constant-cfstrings'))
402 self.addOption(FlagOption('-traditional'))
403 self.addOption(FlagOption('--traditional'))
404 self.addOption(FlagOption('-no_dead_strip_inits_and_terms'))
405 self.addOption(MultiArgOption('-sectalign', numArgs=3))
406 self.addOption(MultiArgOption('-sectcreate', numArgs=3))
407 self.addOption(MultiArgOption('-sectorder', numArgs=3))
408
409 # I dunno why these don't end up working when joined. Maybe
410 # because of translation?
411 self.filelistOption = self.addOption(SeparateOption('-filelist'))
412 self.addOption(SeparateOption('-framework'))
413 self.addOption(SeparateOption('-install_name'))
414 self.addOption(SeparateOption('-seg_addr_table'))
415 self.addOption(SeparateOption('-seg_addr_table_filename'))
416
417 # Where are these coming from? I can't find them...
418 self.addOption(JoinedOrSeparateOption('-e')) # Gets forwarded to linker
419 self.addOption(JoinedOrSeparateOption('-r'))
420
421 # Is this actually declared anywhere? I can only find it in a
422 # spec. :(
423 self.addOption(FlagOption('-pg'))
424
425 doNotReallySupport = 1
426 if doNotReallySupport:
427 # Archaic gcc option.
428 self.addOption(FlagOption('-cpp-precomp'))
429 self.addOption(FlagOption('-no-cpp-precomp'))
430
431 # C options for testing
432
433 self.addOption(JoinedOrSeparateOption('-include'))
434 self.addOption(JoinedOrSeparateOption('-A'))
435 self.addOption(JoinedOrSeparateOption('-D'))
436 self.addOption(JoinedOrSeparateOption('-F'))
437 self.addOption(JoinedOrSeparateOption('-I'))
438 self.addOption(JoinedOrSeparateOption('-L'))
439 self.addOption(JoinedOrSeparateOption('-U'))
440 self.addOption(JoinedOrSeparateOption('-l'))
441 self.addOption(JoinedOrSeparateOption('-u'))
442
443 # FIXME: What is going on here? '-X' goes to linker, and -X ... goes nowhere?
444 self.addOption(FlagOption('-X'))
445 # Not exactly sure how to decompose this. I split out -Xarch_
446 # because we need to recognize that in the driver driver part.
447 # FIXME: Man, this is lame it needs its own option.
448 self.XarchOption = self.addOption(JoinedAndSeparateOption('-Xarch_'))
449 self.addOption(JoinedOption('-X'))
450
451 # The driver needs to know about this flag.
452 self.syntaxOnlyOption = self.addOption(FlagOption('-fsyntax-only'))
453
454 # FIXME: Wrong?
455 # FIXME: What to do about the ambiguity of options like
456 # -dumpspecs? How is this handled in gcc?
457 self.addOption(JoinedOption('-d'))
458 self.addOption(JoinedOption('-g'))
459 self.addOption(JoinedOption('-f'))
460 self.addOption(JoinedOption('-m'))
461 self.addOption(JoinedOption('-i'))
462 self.addOption(JoinedOption('-O'))
463 self.addOption(JoinedOption('-W'))
464 # FIXME: Weird. This option isn't really separate, --param=a=b
465 # works. An alias somewhere?
466 self.addOption(SeparateOption('--param'))
467
468 # FIXME: What is this? Seems to do something on Linux. I think
469 # only one is valid, but have a log that uses both.
470 self.addOption(FlagOption('-pthread'))
471 self.addOption(FlagOption('-pthreads'))
472
Daniel Dunbara5677512009-01-05 19:53:30 +0000473 def addOption(self, opt):
474 self.options.append(opt)
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000475 return opt
Daniel Dunbara5677512009-01-05 19:53:30 +0000476
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000477 def parseArgs(self, argv):
Daniel Dunbara5677512009-01-05 19:53:30 +0000478 """
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000479 parseArgs([str]) -> ArgList
Daniel Dunbara5677512009-01-05 19:53:30 +0000480
481 Parse command line into individual option instances.
482 """
483
484 iargs = enumerate(argv)
485 it = iter(iargs)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000486 args = ArgList(argv)
Daniel Dunbarefb4aeb2009-01-07 01:57:39 +0000487 for pos,a in it:
488 i = InputIndex(0, pos)
Daniel Dunbara5677512009-01-05 19:53:30 +0000489 # FIXME: Handle '@'
490 if not a:
491 # gcc's handling of empty arguments doesn't make
492 # sense, but this is not a common use case. :)
493 #
494 # We just ignore them here (note that other things may
495 # still take them as arguments).
496 pass
497 elif a[0] == '-' and a != '-':
498 args.append(self.lookupOptForArg(i, a, it))
499 else:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000500 args.append(PositionalArg(i, self.inputOption))
Daniel Dunbara5677512009-01-05 19:53:30 +0000501 return args
502
Daniel Dunbar5039f212009-01-06 02:30:10 +0000503 def lookupOptForArg(self, i, string, it):
504 for o in self.options:
505 arg = o.accept(i, string, it)
506 if arg is not None:
507 return arg
508 return PositionalArg(i, self.unknownOption)