blob: e7e69282d20dceee9b675afd6af482b80fbfe94b [file] [log] [blame]
Daniel Dunbara5677512009-01-05 19:53:30 +00001import os
Daniel Dunbar9066af82009-01-09 01:00:40 +00002import platform
Daniel Dunbara5677512009-01-05 19:53:30 +00003import sys
4import tempfile
5from pprint import pprint
6
7###
8
9import Arguments
10import Jobs
Daniel Dunbar9066af82009-01-09 01:00:40 +000011import HostInfo
Daniel Dunbara5677512009-01-05 19:53:30 +000012import Phases
13import Tools
14import Types
15import Util
16
17# FIXME: Clean up naming of options and arguments. Decide whether to
18# rename Option and be consistent about use of Option/Arg.
19
20####
21
22class MissingArgumentError(ValueError):
23 """MissingArgumentError - An option required an argument but none
24 was given."""
25
26###
27
28class Driver(object):
29 def __init__(self):
Daniel Dunbar9066af82009-01-09 01:00:40 +000030 self.hostInfo = None
Daniel Dunbarba6e3232009-01-06 06:12:13 +000031 self.parser = Arguments.OptionParser()
Daniel Dunbara5677512009-01-05 19:53:30 +000032
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000033 def run(self, argv):
Daniel Dunbara5677512009-01-05 19:53:30 +000034 # FIXME: Things to support from environment: GCC_EXEC_PREFIX,
35 # COMPILER_PATH, LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS,
36 # QA_OVERRIDE_GCC3_OPTIONS, ...?
37
38 # FIXME: -V and -b processing
39
40 # Handle some special -ccc- options used for testing which are
41 # only allowed at the beginning of the command line.
42 cccPrintOptions = False
43 cccPrintPhases = False
Daniel Dunbar9066af82009-01-09 01:00:40 +000044 cccHostBits = cccHostMachine = cccHostSystem = None
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000045 while argv and argv[0].startswith('-ccc-'):
46 opt,argv = argv[0][5:],argv[1:]
Daniel Dunbara5677512009-01-05 19:53:30 +000047
48 if opt == 'print-options':
49 cccPrintOptions = True
50 elif opt == 'print-phases':
51 cccPrintPhases = True
Daniel Dunbar9066af82009-01-09 01:00:40 +000052 elif opt == 'host-bits':
53 cccHostBits,argv = argv[0],argv[1:]
54 elif opt == 'host-machine':
55 cccHostMachine,argv = argv[0],argv[1:]
56 elif opt == 'host-system':
57 cccHostSystem,argv = argv[0],argv[1:]
Daniel Dunbara5677512009-01-05 19:53:30 +000058 else:
59 raise ValueError,"Invalid ccc option: %r" % cccPrintOptions
60
Daniel Dunbar9066af82009-01-09 01:00:40 +000061 # FIXME: How to handle override of host? ccc specific options?
62 # Abuse -b?
63 hostBits = cccHostBits or platform.architecture()[0].replace('bit','')
64 hostMachine = cccHostMachine or platform.machine()
65 hostSystem = cccHostSystem or platform.system().lower()
66 self.hostInfo = HostInfo.getHostInfo(self,
67 hostSystem, hostMachine, hostBits)
68
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000069 args = self.parser.parseArgs(argv)
Daniel Dunbara5677512009-01-05 19:53:30 +000070
71 # FIXME: Ho hum I have just realized -Xarch_ is broken. We really
72 # need to reparse the Arguments after they have been expanded by
73 # -Xarch. How is this going to work?
74 #
75 # Scratch that, we aren't going to do that; it really disrupts the
76 # organization, doesn't consistently work with gcc-dd, and is
77 # confusing. Instead we are going to enforce that -Xarch_ is only
78 # used with options which do not alter the driver behavior. Let's
79 # hope this is ok, because the current architecture is a little
80 # tied to it.
81
82 if cccPrintOptions:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000083 self.printOptions(args)
Daniel Dunbara5677512009-01-05 19:53:30 +000084 sys.exit(0)
85
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000086 self.handleImmediateOptions(args)
Daniel Dunbara5677512009-01-05 19:53:30 +000087
Daniel Dunbar9066af82009-01-09 01:00:40 +000088 if self.hostInfo.useDriverDriver():
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000089 phases = self.buildPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +000090 else:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000091 phases = self.buildNormalPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +000092
93 if cccPrintPhases:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000094 self.printPhases(phases, args)
Daniel Dunbara5677512009-01-05 19:53:30 +000095 sys.exit(0)
Daniel Dunbar9066af82009-01-09 01:00:40 +000096
Daniel Dunbara5677512009-01-05 19:53:30 +000097 if 0:
98 print Util.pprint(phases)
99
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000100 jobs = self.bindPhases(phases, args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000101
102 # FIXME: We should provide some basic sanity checking of the
103 # pipeline as a "verification" sort of stage. For example, the
104 # pipeline should never end up writing to an output file in two
105 # places (I think). The pipeline should also never end up writing
106 # to an output file that is an input.
107 #
108 # This is intended to just be a "verify" step, not a functionality
109 # step. It should catch things like the driver driver not
110 # preventing -save-temps, but it shouldn't change behavior (so we
111 # can turn it off in Release-Asserts builds).
112
113 # Print in -### syntax.
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000114 hasHashHashHash = args.getLastArg(self.parser.hashHashHashOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000115 if hasHashHashHash:
116 self.claim(hasHashHashHash)
117 for j in jobs.iterjobs():
118 if isinstance(j, Jobs.Command):
Daniel Dunbardb439902009-01-07 18:40:45 +0000119 print '"%s"' % '" "'.join(j.getArgv())
Daniel Dunbara5677512009-01-05 19:53:30 +0000120 elif isinstance(j, Jobs.PipedJob):
121 for c in j.commands:
Daniel Dunbardb439902009-01-07 18:40:45 +0000122 print '"%s" %c' % ('" "'.join(c.getArgv()),
Daniel Dunbara5677512009-01-05 19:53:30 +0000123 "| "[c is j.commands[-1]])
124 elif not isinstance(j, JobList):
125 raise ValueError,'Encountered unknown job.'
126 sys.exit(0)
127
128 for j in jobs.iterjobs():
129 if isinstance(j, Jobs.Command):
Daniel Dunbardb439902009-01-07 18:40:45 +0000130 res = os.spawnvp(os.P_WAIT, j.executable, j.getArgv())
Daniel Dunbara5677512009-01-05 19:53:30 +0000131 if res:
132 sys.exit(res)
133 elif isinstance(j, Jobs.PipedJob):
134 raise NotImplementedError,"Piped jobs aren't implemented yet."
135 else:
136 raise ValueError,'Encountered unknown job.'
137
138 def claim(self, option):
139 # FIXME: Move to OptionList once introduced and implement.
140 pass
141
142 def warning(self, message):
143 print >>sys.stderr,'%s: %s' % (sys.argv[0], message)
144
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000145 def printOptions(self, args):
146 for i,arg in enumerate(args):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000147 if isinstance(arg, Arguments.MultipleValuesArg):
148 values = list(args.getValues(arg))
149 elif isinstance(arg, Arguments.ValueArg):
150 values = [args.getValue(arg)]
151 elif isinstance(arg, Arguments.JoinedAndSeparateValuesArg):
152 values = [args.getJoinedValue(arg), args.getSeparateValue(arg)]
Daniel Dunbara5677512009-01-05 19:53:30 +0000153 else:
154 values = []
Daniel Dunbar5039f212009-01-06 02:30:10 +0000155 print 'Option %d - Name: "%s", Values: {%s}' % (i, arg.opt.name,
Daniel Dunbara5677512009-01-05 19:53:30 +0000156 ', '.join(['"%s"' % v
157 for v in values]))
158
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000159 def printPhases(self, phases, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000160 def printPhase(p, f, steps, arch=None):
161 if p in steps:
162 return steps[p]
163 elif isinstance(p, Phases.BindArchAction):
164 for kid in p.inputs:
165 printPhase(kid, f, steps, p.arch)
166 steps[p] = len(steps)
167 return
168
169 if isinstance(p, Phases.InputAction):
170 phaseName = 'input'
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000171 inputStr = '"%s"' % args.getValue(p.filename)
Daniel Dunbara5677512009-01-05 19:53:30 +0000172 else:
173 phaseName = p.phase.name
174 inputs = [printPhase(i, f, steps, arch)
175 for i in p.inputs]
176 inputStr = '{%s}' % ', '.join(map(str, inputs))
177 if arch is not None:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000178 phaseName += '-' + args.getValue(arch)
Daniel Dunbara5677512009-01-05 19:53:30 +0000179 steps[p] = index = len(steps)
180 print "%d: %s, %s, %s" % (index,phaseName,inputStr,p.type.name)
181 return index
182 steps = {}
183 for phase in phases:
184 printPhase(phase, sys.stdout, steps)
185
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000186 def handleImmediateOptions(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000187 # FIXME: Some driver Arguments are consumed right off the bat,
188 # like -dumpversion. Currently the gcc-dd handles these
189 # poorly, so we should be ok handling them upfront instead of
190 # after driver-driver level dispatching.
191 #
192 # FIXME: The actual order of these options in gcc is all over the
193 # place. The -dump ones seem to be first and in specification
194 # order, but there are other levels of precedence. For example,
195 # -print-search-dirs is evaluated before -print-prog-name=,
196 # regardless of order (and the last instance of -print-prog-name=
197 # wins verse itself).
198 #
199 # FIXME: Do we want to report "argument unused" type errors in the
200 # presence of things like -dumpmachine and -print-search-dirs?
201 # Probably not.
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000202 arg = args.getLastArg(self.parser.dumpmachineOption)
203 if arg:
204 print 'FIXME: %s' % arg.opt.name
205 sys.exit(1)
206
207 arg = args.getLastArg(self.parser.dumpspecsOption)
208 if arg:
209 print 'FIXME: %s' % arg.opt.name
210 sys.exit(1)
211
212 arg = args.getLastArg(self.parser.dumpversionOption)
213 if arg:
214 print 'FIXME: %s' % arg.opt.name
215 sys.exit(1)
216
217 arg = args.getLastArg(self.parser.printFileNameOption)
218 if arg:
219 print 'FIXME: %s' % arg.opt.name
220 sys.exit(1)
221
222 arg = args.getLastArg(self.parser.printMultiDirectoryOption)
223 if arg:
224 print 'FIXME: %s' % arg.opt.name
225 sys.exit(1)
226
227 arg = args.getLastArg(self.parser.printMultiLibOption)
228 if arg:
229 print 'FIXME: %s' % arg.opt.name
230 sys.exit(1)
231
232 arg = args.getLastArg(self.parser.printProgNameOption)
233 if arg:
234 print 'FIXME: %s' % arg.opt.name
235 sys.exit(1)
236
237 arg = args.getLastArg(self.parser.printLibgccFilenameOption)
238 if arg:
239 print 'FIXME: %s' % arg.opt.name
240 sys.exit(1)
241
242 arg = args.getLastArg(self.parser.printSearchDirsOption)
243 if arg:
244 print 'FIXME: %s' % arg.opt.name
245 sys.exit(1)
Daniel Dunbara5677512009-01-05 19:53:30 +0000246
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000247 def buildNormalPipeline(self, args):
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000248 hasCombine = args.getLastArg(self.parser.combineOption)
249 hasSyntaxOnly = args.getLastArg(self.parser.syntaxOnlyOption)
250 hasDashC = args.getLastArg(self.parser.cOption)
251 hasDashE = args.getLastArg(self.parser.EOption)
252 hasDashS = args.getLastArg(self.parser.SOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000253
254 inputType = None
255 inputTypeOpt = None
256 inputs = []
257 for a in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000258 if a.opt is self.parser.inputOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000259 if inputType is None:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000260 base,ext = os.path.splitext(args.getValue(a))
Daniel Dunbara5677512009-01-05 19:53:30 +0000261 if ext and ext in Types.kTypeSuffixMap:
262 klass = Types.kTypeSuffixMap[ext]
263 else:
264 # FIXME: Its not clear why we shouldn't just
265 # revert to unknown. I think this is more likely a
266 # bug / unintended behavior in gcc. Not very
267 # important though.
268 klass = Types.ObjectType
269 else:
270 assert inputTypeOpt is not None
271 self.claim(inputTypeOpt)
272 klass = inputType
273 inputs.append((klass, a))
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000274 elif a.opt is self.parser.filelistOption:
275 # Treat as a linker input. Investigate how gcc is
276 # handling this.
Daniel Dunbar5039f212009-01-06 02:30:10 +0000277 #
278 # FIXME: This might not be good enough. We may
279 # need to introduce another type for this case, so
280 # that other code which needs to know the inputs
281 # handles this properly. Best not to try and lipo
282 # this, for example.
283 inputs.append((Types.ObjectType, a))
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000284 elif a.opt is self.parser.xOption:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000285 self.claim(a)
286 inputTypeOpt = a
287 value = args.getValue(a)
288 if value in Types.kTypeSpecifierMap:
289 inputType = Types.kTypeSpecifierMap[value]
290 else:
291 # FIXME: How are we going to handle diagnostics.
292 self.warning("language %s not recognized" % value)
Daniel Dunbara5677512009-01-05 19:53:30 +0000293
Daniel Dunbar5039f212009-01-06 02:30:10 +0000294 # FIXME: Its not clear why we shouldn't just
295 # revert to unknown. I think this is more likely a
296 # bug / unintended behavior in gcc. Not very
297 # important though.
298 inputType = ObjectType
Daniel Dunbara5677512009-01-05 19:53:30 +0000299
300 # We claim things here so that options for which we silently allow
301 # override only ever claim the used option.
302 if hasCombine:
303 self.claim(hasCombine)
304
305 finalPhase = Phases.Phase.eOrderPostAssemble
306 finalPhaseOpt = None
307
308 # Determine what compilation mode we are in.
309 if hasDashE:
310 finalPhase = Phases.Phase.eOrderPreprocess
311 finalPhaseOpt = hasDashE
312 elif hasSyntaxOnly:
313 finalPhase = Phases.Phase.eOrderCompile
314 finalPhaseOpt = hasSyntaxOnly
315 elif hasDashS:
316 finalPhase = Phases.Phase.eOrderCompile
317 finalPhaseOpt = hasDashS
318 elif hasDashC:
319 finalPhase = Phases.Phase.eOrderAssemble
320 finalPhaseOpt = hasDashC
321
322 if finalPhaseOpt:
323 self.claim(finalPhaseOpt)
324
325 # FIXME: Support -combine.
326 if hasCombine:
327 raise NotImplementedError,"-combine is not yet supported."
328
329 actions = []
330 linkerInputs = []
331 # FIXME: This is gross.
332 linkPhase = Phases.LinkPhase()
333 for klass,input in inputs:
334 # Figure out what step to start at.
335
336 # FIXME: This should be part of the input class probably?
337 # Altough it doesn't quite fit there either, things like
338 # asm-with-preprocess don't easily fit into a linear scheme.
339
340 # FIXME: I think we are going to end up wanting to just build
341 # a simple FSA which we run the inputs down.
342 sequence = []
343 if klass.preprocess:
344 sequence.append(Phases.PreprocessPhase())
345 if klass == Types.ObjectType:
346 sequence.append(linkPhase)
347 elif klass.onlyAssemble:
348 sequence.extend([Phases.AssemblePhase(),
349 linkPhase])
350 elif klass.onlyPrecompile:
351 sequence.append(Phases.PrecompilePhase())
352 else:
353 sequence.extend([Phases.CompilePhase(),
354 Phases.AssemblePhase(),
355 linkPhase])
356
357 if sequence[0].order > finalPhase:
358 assert finalPhaseOpt and finalPhaseOpt.opt
359 # FIXME: Explain what type of input file is. Or just match
360 # gcc warning.
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000361 self.warning("%s: %s input file unused when %s is present" % (args.getValue(input),
Daniel Dunbara5677512009-01-05 19:53:30 +0000362 sequence[0].name,
363 finalPhaseOpt.opt.name))
364 else:
365 # Build the pipeline for this file.
366
367 current = Phases.InputAction(input, klass)
368 for transition in sequence:
369 # If the current action produces no output, or we are
370 # past what the user requested, we are done.
371 if (current.type is Types.NothingType or
372 transition.order > finalPhase):
373 break
374 else:
375 if isinstance(transition, Phases.PreprocessPhase):
376 assert isinstance(klass.preprocess, Types.InputType)
377 current = Phases.JobAction(transition,
378 [current],
379 klass.preprocess)
380 elif isinstance(transition, Phases.PrecompilePhase):
381 current = Phases.JobAction(transition,
382 [current],
383 Types.PCHType)
384 elif isinstance(transition, Phases.CompilePhase):
385 if hasSyntaxOnly:
386 output = Types.NothingType
387 else:
388 output = Types.AsmTypeNoPP
389 current = Phases.JobAction(transition,
390 [current],
391 output)
392 elif isinstance(transition, Phases.AssemblePhase):
393 current = Phases.JobAction(transition,
394 [current],
395 Types.ObjectType)
396 elif transition is linkPhase:
397 linkerInputs.append(current)
398 current = None
399 break
400 else:
401 raise RuntimeError,'Unrecognized transition: %s.' % transition
402 pass
403
404 if current is not None:
405 assert not isinstance(current, Phases.InputAction)
406 actions.append(current)
407
408 if linkerInputs:
409 actions.append(Phases.JobAction(linkPhase,
410 linkerInputs,
411 Types.ImageType))
412
413 return actions
414
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000415 def buildPipeline(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000416 # FIXME: We need to handle canonicalization of the specified arch.
417
418 archs = []
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000419 hasDashM = None
420 hasSaveTemps = (args.getLastArg(self.parser.saveTempsOption) or
421 args.getLastArg(self.parser.saveTempsOption2))
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000422 for arg in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000423 if arg.opt is self.parser.archOption:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000424 archs.append(arg)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000425 elif arg.opt.name.startswith('-M'):
426 hasDashM = arg
Daniel Dunbara5677512009-01-05 19:53:30 +0000427
428 if not archs:
Daniel Dunbar9066af82009-01-09 01:00:40 +0000429 archs.append(args.makeSeparateArg(self.hostInfo.getArchName(),
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000430 self.parser.archOption))
Daniel Dunbara5677512009-01-05 19:53:30 +0000431
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000432 actions = self.buildNormalPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000433
434 # FIXME: Use custom exception for this.
435 #
436 # FIXME: We killed off some others but these aren't yet detected in
437 # a functional manner. If we added information to jobs about which
438 # "auxiliary" files they wrote then we could detect the conflict
439 # these cause downstream.
440 if len(archs) > 1:
441 if hasDashM:
442 raise ValueError,"Cannot use -M options with multiple arch flags."
443 elif hasSaveTemps:
444 raise ValueError,"Cannot use -save-temps with multiple arch flags."
445
446 # Execute once per arch.
447 finalActions = []
448 for p in actions:
449 # Make sure we can lipo this kind of output. If not (and it
450 # is an actual output) then we disallow, since we can't
451 # create an output file with the right name without
452 # overwriting it. We could remove this oddity by just
453 # changing the output names to include the arch, which would
454 # also fix -save-temps. Compatibility wins for now.
455 #
456 # FIXME: Is this error substantially less useful than
457 # gcc-dd's? The main problem is that "Cannot use compiler
458 # output with multiple arch flags" won't make sense to most
459 # developers.
460 if (len(archs) > 1 and
461 p.type not in (Types.NothingType,Types.ObjectType,Types.ImageType)):
462 raise ValueError,'Cannot use %s output with multiple arch flags.' % p.type.name
463
464 inputs = []
465 for arch in archs:
466 inputs.append(Phases.BindArchAction(p, arch))
467
468 # Lipo if necessary. We do it this way because we need to set
469 # the arch flag so that -Xarch_ gets rewritten.
470 if len(inputs) == 1 or p.type == Types.NothingType:
471 finalActions.extend(inputs)
472 else:
473 finalActions.append(Phases.JobAction(Phases.LipoPhase(),
474 inputs,
475 p.type))
476
477 # FIXME: We need to add -Wl,arch_multiple and -Wl,final_output in
478 # certain cases. This may be icky because we need to figure out the
479 # mode first. Current plan is to hack on the pipeline once it is built
480 # and we know what is being spit out. This avoids having to handling
481 # things like -c and -combine in multiple places.
482 #
483 # The annoying one of these is -Wl,final_output because it involves
484 # communication across different phases.
485 #
486 # Hopefully we can do this purely as part of the binding, but
487 # leaving comment here for now until it is clear this works.
488
489 return finalActions
490
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000491 def bindPhases(self, phases, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000492 jobs = Jobs.JobList()
493
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000494 finalOutput = args.getLastArg(self.parser.oOption)
495 hasSaveTemps = (args.getLastArg(self.parser.saveTempsOption) or
496 args.getLastArg(self.parser.saveTempsOption2))
497 hasNoIntegratedCPP = args.getLastArg(self.parser.noIntegratedCPPOption)
498 hasPipe = args.getLastArg(self.parser.pipeOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000499 forward = []
500 for a in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000501 if a.opt is self.parser.inputOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000502 pass
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000503
504 # FIXME: Needs to be part of option.
Daniel Dunbar5039f212009-01-06 02:30:10 +0000505 elif a.opt.name in ('-E', '-S', '-c',
506 '-arch', '-fsyntax-only', '-combine', '-x',
507 '-###'):
508 pass
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000509
Daniel Dunbara5677512009-01-05 19:53:30 +0000510 else:
511 forward.append(a)
512
513 # We claim things here so that options for which we silently allow
514 # override only ever claim the used option.
515 if hasPipe:
516 self.claim(hasPipe)
517 # FIXME: Hack, override -pipe till we support it.
518 hasPipe = None
519 # Claim these here. Its not completely accurate but any warnings
520 # about these being unused are likely to be noise anyway.
521 if hasSaveTemps:
522 self.claim(hasSaveTemps)
523 if hasNoIntegratedCPP:
524 self.claim(hasNoIntegratedCPP)
525
526 toolMap = {
527 Phases.PreprocessPhase : Tools.GCC_PreprocessTool(),
528 Phases.CompilePhase : Tools.GCC_CompileTool(),
529 Phases.PrecompilePhase : Tools.GCC_PrecompileTool(),
530 Phases.AssemblePhase : Tools.DarwinAssemblerTool(),
531 Phases.LinkPhase : Tools.Collect2Tool(),
532 Phases.LipoPhase : Tools.LipoTool(),
533 }
534
535 class InputInfo:
536 def __init__(self, source, type, baseInput):
537 self.source = source
538 self.type = type
539 self.baseInput = baseInput
540
541 def __repr__(self):
542 return '%s(%r, %r, %r)' % (self.__class__.__name__,
543 self.source, self.type, self.baseInput)
544
545 def createJobs(phase, forwardArgs,
546 canAcceptPipe=False, atTopLevel=False, arch=None):
547 if isinstance(phase, Phases.InputAction):
548 return InputInfo(phase.filename, phase.type, phase.filename)
549 elif isinstance(phase, Phases.BindArchAction):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000550 archName = args.getValue(phase.arch)
Daniel Dunbara5677512009-01-05 19:53:30 +0000551 filteredArgs = []
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000552 for arg in forwardArgs:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000553 if arg.opt is self.parser.archOption:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000554 if arg is phase.arch:
555 filteredArgs.append(arg)
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000556 elif arg.opt is self.parser.XarchOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000557 # FIXME: gcc-dd has another conditional for passing
558 # through, when the arch conditional array has an empty
559 # string. Why?
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000560 if args.getJoinedValue(arg) == archName:
Daniel Dunbara5677512009-01-05 19:53:30 +0000561 # FIXME: This is wrong, we don't want a
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000562 # unknown arg we want an actual parsed
563 # version of this arg.
564 filteredArgs.append(args.makeUnknownArg(args.getSeparateValue(arg)))
Daniel Dunbara5677512009-01-05 19:53:30 +0000565 else:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000566 filteredArgs.append(arg)
Daniel Dunbara5677512009-01-05 19:53:30 +0000567
568 return createJobs(phase.inputs[0], filteredArgs,
569 canAcceptPipe, atTopLevel, phase.arch)
570
571 assert isinstance(phase, Phases.JobAction)
572 tool = toolMap[phase.phase.__class__]
573
574 # See if we should use an integrated CPP. We only use an
575 # integrated cpp when we have exactly one input, since this is
576 # the only use case we care about.
577 useIntegratedCPP = False
578 inputList = phase.inputs
579 if (not hasNoIntegratedCPP and
580 not hasSaveTemps and
581 tool.hasIntegratedCPP()):
582 if (len(phase.inputs) == 1 and
583 isinstance(phase.inputs[0].phase, Phases.PreprocessPhase)):
584 useIntegratedCPP = True
585 inputList = phase.inputs[0].inputs
586
587 # Only try to use pipes when exactly one input.
588 canAcceptPipe = len(inputList) == 1 and tool.acceptsPipedInput()
589 inputs = [createJobs(p, forwardArgs, canAcceptPipe, False, arch) for p in inputList]
590
591 # Determine if we should output to a pipe.
592 canOutputToPipe = canAcceptPipe and tool.canPipeOutput()
593 outputToPipe = False
594 if canOutputToPipe:
595 # Some things default to writing to a pipe if the final
596 # phase and there was no user override.
597 #
598 # FIXME: What is the best way to handle this?
599 if (atTopLevel and
600 isinstance(phase, Phases.PreprocessPhase) and
601 not finalOutput):
602 outputToPipe = True
603 elif hasPipe:
604 outputToPipe = True
605
606 # Figure out where to put the job (pipes).
607 jobList = jobs
608 if canAcceptPipe and isinstance(inputs[0].source, Jobs.PipedJob):
609 jobList = inputs[0].source
610
611 # Figure out where to put the output.
612 baseInput = inputs[0].baseInput
613 if phase.type == Types.NothingType:
614 output = None
615 elif outputToPipe:
616 if isinstance(jobList, Jobs.PipedJob):
617 output = jobList
618 else:
619 jobList = output = Jobs.PipedJob([])
620 jobs.addJob(output)
621 else:
622 # Figure out what the derived output location would be.
623 #
624 # FIXME: gcc has some special case in here so that it doesn't
625 # create output files if they would conflict with an input.
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000626 inputName = args.getValue(baseInput)
Daniel Dunbara5677512009-01-05 19:53:30 +0000627 if phase.type is Types.ImageType:
628 namedOutput = "a.out"
629 else:
630 base,_ = os.path.splitext(inputName)
631 assert phase.type.tempSuffix is not None
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000632 namedOutput = base + '.' + phase.type.tempSuffix
Daniel Dunbara5677512009-01-05 19:53:30 +0000633
634 # Output to user requested destination?
635 if atTopLevel and finalOutput:
636 output = finalOutput
637 # Contruct a named destination?
638 elif atTopLevel or hasSaveTemps:
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000639 output = args.makeSeparateArg(namedOutput,
640 self.parser.oOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000641 else:
642 # Output to temp file...
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000643 fd,filename = tempfile.mkstemp(suffix='.'+phase.type.tempSuffix)
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000644 output = args.makeSeparateArg(filename,
645 self.parser.oOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000646
Daniel Dunbardb439902009-01-07 18:40:45 +0000647 tool.constructJob(phase, arch, jobList, inputs, output, phase.type,
648 forwardArgs, args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000649
650 return InputInfo(output, phase.type, baseInput)
651
652 # It is an error to provide a -o option if we are making multiple
653 # output files.
654 if finalOutput and len([a for a in phases if a.type is not Types.NothingType]) > 1:
655 # FIXME: Custom exception.
656 raise ValueError,"Cannot specify -o when generating multiple files."
657
658 for phase in phases:
659 createJobs(phase, forward, canAcceptPipe=True, atTopLevel=True)
660
661 return jobs