blob: 5b5dbfec61aa25fb51827807fe5cb3be76ed7825 [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
114
115 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 = []
242
243 # Support use as a simple arg list.
244
245 def __iter__(self):
246 return iter(self.args)
247
248 def append(self, arg):
249 self.args.append(arg)
250
251 # Forwarding methods.
252
253 def getValue(self, arg):
254 return arg.getValue(self.argv)
255
256 def getValues(self, arg):
257 return arg.getValues(self.argv)
258
259 def getSeparateValue(self, arg):
260 return arg.getSeparateValue(self.argv)
261
262 def getJoinedValue(self, arg):
263 return arg.getJoinedValue(self.argv)
264
Daniel Dunbara5677512009-01-05 19:53:30 +0000265class OptionParser:
266 def __init__(self):
267 self.options = []
Daniel Dunbar5039f212009-01-06 02:30:10 +0000268 self.inputOption = InputOption()
269 self.unknownOption = UnknownOption()
270
Daniel Dunbara5677512009-01-05 19:53:30 +0000271 def addOption(self, opt):
272 self.options.append(opt)
273
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000274 def parseArgs(self, argv):
Daniel Dunbara5677512009-01-05 19:53:30 +0000275 """
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000276 parseArgs([str]) -> ArgList
Daniel Dunbara5677512009-01-05 19:53:30 +0000277
278 Parse command line into individual option instances.
279 """
280
281 iargs = enumerate(argv)
282 it = iter(iargs)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000283 args = ArgList(argv)
Daniel Dunbara5677512009-01-05 19:53:30 +0000284 for i,a in it:
285 # FIXME: Handle '@'
286 if not a:
287 # gcc's handling of empty arguments doesn't make
288 # sense, but this is not a common use case. :)
289 #
290 # We just ignore them here (note that other things may
291 # still take them as arguments).
292 pass
293 elif a[0] == '-' and a != '-':
294 args.append(self.lookupOptForArg(i, a, it))
295 else:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000296 args.append(PositionalArg(i, self.inputOption))
Daniel Dunbara5677512009-01-05 19:53:30 +0000297 return args
298
Daniel Dunbar5039f212009-01-06 02:30:10 +0000299 def lookupOptForArg(self, i, string, it):
300 for o in self.options:
301 arg = o.accept(i, string, it)
302 if arg is not None:
303 return arg
304 return PositionalArg(i, self.unknownOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000305
306def createOptionParser():
307 op = OptionParser()
308
309 # Driver driver options
310 op.addOption(SeparateOption('-arch'))
311
312 # Misc driver options
313 op.addOption(FlagOption('-pass-exit-codes'))
314 op.addOption(FlagOption('--help'))
315 op.addOption(FlagOption('--target-help'))
316
317 op.addOption(FlagOption('-dumpspecs'))
318 op.addOption(FlagOption('-dumpversion'))
319 op.addOption(FlagOption('-dumpmachine'))
320 op.addOption(FlagOption('-print-search-dirs'))
321 op.addOption(FlagOption('-print-libgcc-file-name'))
322 # FIXME: Hrm, where does this come from? It isn't always true that
323 # we take both - and --. For example, gcc --S ... ends up sending
324 # -fS to cc1. Investigate.
325 op.addOption(FlagOption('--print-libgcc-file-name'))
326 op.addOption(JoinedOption('-print-file-name='))
327 op.addOption(JoinedOption('-print-prog-name='))
328 op.addOption(JoinedOption('--print-prog-name='))
329 op.addOption(FlagOption('-print-multi-directory'))
330 op.addOption(FlagOption('-print-multi-lib'))
331 op.addOption(FlagOption('-print-multi-os-directory'))
332
333 # Hmmm, who really takes this?
334 op.addOption(FlagOption('--version'))
335
336 # Pipeline control
337 op.addOption(FlagOption('-###'))
338 op.addOption(FlagOption('-E'))
339 op.addOption(FlagOption('-S'))
340 op.addOption(FlagOption('-c'))
341 op.addOption(FlagOption('-combine'))
342 op.addOption(FlagOption('-no-integrated-cpp'))
343 op.addOption(FlagOption('-pipe'))
344 op.addOption(FlagOption('-save-temps'))
345 op.addOption(FlagOption('--save-temps'))
346 op.addOption(JoinedOption('-specs='))
347 op.addOption(FlagOption('-time'))
348 op.addOption(FlagOption('-v'))
349
350 # Input/output stuff
351 op.addOption(JoinedOrSeparateOption('-o'))
352 op.addOption(JoinedOrSeparateOption('-x'))
353
354 # FIXME: What do these actually do? The documentation is less than
355 # clear.
356 op.addOption(FlagOption('-ObjC'))
357 op.addOption(FlagOption('-ObjC++'))
358
359 # FIXME: Weird, gcc claims this here in help but I'm not sure why;
360 # perhaps interaction with preprocessor? Investigate.
361 op.addOption(JoinedOption('-std='))
362 op.addOption(JoinedOrSeparateOption('--sysroot'))
363
364 # Version control
365 op.addOption(JoinedOrSeparateOption('-B'))
366 op.addOption(JoinedOrSeparateOption('-V'))
367 op.addOption(JoinedOrSeparateOption('-b'))
368
369 # Blanket pass-through options.
370
371 op.addOption(JoinedOption('-Wa,'))
372 op.addOption(SeparateOption('-Xassembler'))
373
374 op.addOption(JoinedOption('-Wp,'))
375 op.addOption(SeparateOption('-Xpreprocessor'))
376
377 op.addOption(JoinedOption('-Wl,'))
378 op.addOption(SeparateOption('-Xlinker'))
379
380 ####
381 # Bring on the random garbage.
382
383 op.addOption(FlagOption('-MD'))
384 op.addOption(FlagOption('-MP'))
385 op.addOption(FlagOption('-MM'))
386 op.addOption(JoinedOrSeparateOption('-MF'))
387 op.addOption(JoinedOrSeparateOption('-MT'))
388 op.addOption(FlagOption('-undef'))
389
390 op.addOption(FlagOption('-w'))
391 op.addOption(JoinedOrSeparateOption('-allowable_client'))
392 op.addOption(JoinedOrSeparateOption('-client_name'))
393 op.addOption(JoinedOrSeparateOption('-compatibility_version'))
394 op.addOption(JoinedOrSeparateOption('-current_version'))
395 op.addOption(JoinedOrSeparateOption('-exported_symbols_list'))
396 op.addOption(JoinedOrSeparateOption('-idirafter'))
397 op.addOption(JoinedOrSeparateOption('-iquote'))
398 op.addOption(JoinedOrSeparateOption('-isysroot'))
399 op.addOption(JoinedOrSeparateOption('-keep_private_externs'))
400 op.addOption(JoinedOrSeparateOption('-seg1addr'))
401 op.addOption(JoinedOrSeparateOption('-segprot'))
402 op.addOption(JoinedOrSeparateOption('-sub_library'))
403 op.addOption(JoinedOrSeparateOption('-sub_umbrella'))
404 op.addOption(JoinedOrSeparateOption('-umbrella'))
405 op.addOption(JoinedOrSeparateOption('-undefined'))
406 op.addOption(JoinedOrSeparateOption('-unexported_symbols_list'))
407 op.addOption(JoinedOrSeparateOption('-weak_framework'))
408 op.addOption(JoinedOption('-headerpad_max_install_names'))
409 op.addOption(FlagOption('-twolevel_namespace'))
410 op.addOption(FlagOption('-prebind'))
411 op.addOption(FlagOption('-prebind_all_twolevel_modules'))
412 op.addOption(FlagOption('-single_module'))
413 op.addOption(FlagOption('-nomultidefs'))
414 op.addOption(FlagOption('-nostdlib'))
415 op.addOption(FlagOption('-nostdinc'))
416 op.addOption(FlagOption('-static'))
417 op.addOption(FlagOption('-shared'))
418 op.addOption(FlagOption('-C'))
419 op.addOption(FlagOption('-CC'))
420 op.addOption(FlagOption('-R'))
421 op.addOption(FlagOption('-P'))
422 op.addOption(FlagOption('-all_load'))
423 op.addOption(FlagOption('--constant-cfstrings'))
424 op.addOption(FlagOption('-traditional'))
425 op.addOption(FlagOption('--traditional'))
426 op.addOption(FlagOption('-no_dead_strip_inits_and_terms'))
427 op.addOption(MultiArgOption('-sectalign', numArgs=3))
428 op.addOption(MultiArgOption('-sectcreate', numArgs=3))
429 op.addOption(MultiArgOption('-sectorder', numArgs=3))
430
431 # I dunno why these don't end up working when joined. Maybe
432 # because of translation?
433 op.addOption(SeparateOption('-filelist'))
434 op.addOption(SeparateOption('-framework'))
435 op.addOption(SeparateOption('-install_name'))
436 op.addOption(SeparateOption('-seg_addr_table'))
437 op.addOption(SeparateOption('-seg_addr_table_filename'))
438
439 # Where are these coming from? I can't find them...
440 op.addOption(JoinedOrSeparateOption('-e')) # Gets forwarded to linker
441 op.addOption(JoinedOrSeparateOption('-r'))
442
443 # Is this actually declared anywhere? I can only find it in a
444 # spec. :(
445 op.addOption(FlagOption('-pg'))
446
447 doNotReallySupport = 1
448 if doNotReallySupport:
449 # Archaic gcc option.
450 op.addOption(FlagOption('-cpp-precomp'))
451 op.addOption(FlagOption('-no-cpp-precomp'))
452
453 # C options for testing
454
455 op.addOption(JoinedOrSeparateOption('-include'))
456 op.addOption(JoinedOrSeparateOption('-A'))
457 op.addOption(JoinedOrSeparateOption('-D'))
458 op.addOption(JoinedOrSeparateOption('-F'))
459 op.addOption(JoinedOrSeparateOption('-I'))
460 op.addOption(JoinedOrSeparateOption('-L'))
461 op.addOption(JoinedOrSeparateOption('-U'))
462 op.addOption(JoinedOrSeparateOption('-l'))
463 op.addOption(JoinedOrSeparateOption('-u'))
464
465 # FIXME: What is going on here? '-X' goes to linker, and -X ... goes nowhere?
466 op.addOption(FlagOption('-X'))
467 # Not exactly sure how to decompose this. I split out -Xarch_
468 # because we need to recognize that in the driver driver part.
469 # FIXME: Man, this is lame it needs its own option.
470 op.addOption(JoinedAndSeparateOption('-Xarch_'))
471 op.addOption(JoinedOption('-X'))
472
473 # The driver needs to know about this flag.
474 op.addOption(FlagOption('-fsyntax-only'))
475
476 # FIXME: Wrong?
477 # FIXME: What to do about the ambiguity of options like
478 # -dumpspecs? How is this handled in gcc?
479 op.addOption(JoinedOption('-d'))
480 op.addOption(JoinedOption('-g'))
481 op.addOption(JoinedOption('-f'))
482 op.addOption(JoinedOption('-m'))
483 op.addOption(JoinedOption('-i'))
484 op.addOption(JoinedOption('-O'))
485 op.addOption(JoinedOption('-W'))
486 # FIXME: Weird. This option isn't really separate, --param=a=b
487 # works. An alias somewhere?
488 op.addOption(SeparateOption('--param'))
489
490 # FIXME: What is this? Seems to do something on Linux. I think
491 # only one is valid, but have a log that uses both.
492 op.addOption(FlagOption('-pthread'))
493 op.addOption(FlagOption('-pthreads'))
494
495 return op