blob: 0133c34e08ffb3e4cfd776d89252c49da58e5956 [file] [log] [blame]
Daniel Dunbara5677512009-01-05 19:53:30 +00001import os
2import sys
3import tempfile
4from pprint import pprint
5
6###
7
8import Arguments
9import Jobs
10import Phases
11import Tools
12import Types
13import Util
14
15# FIXME: Clean up naming of options and arguments. Decide whether to
16# rename Option and be consistent about use of Option/Arg.
17
18####
19
20class MissingArgumentError(ValueError):
21 """MissingArgumentError - An option required an argument but none
22 was given."""
23
24###
25
26class Driver(object):
27 def __init__(self):
28 self.parser = Arguments.createOptionParser()
29
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000030 def run(self, argv):
Daniel Dunbara5677512009-01-05 19:53:30 +000031 # FIXME: Things to support from environment: GCC_EXEC_PREFIX,
32 # COMPILER_PATH, LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS,
33 # QA_OVERRIDE_GCC3_OPTIONS, ...?
34
35 # FIXME: -V and -b processing
36
37 # Handle some special -ccc- options used for testing which are
38 # only allowed at the beginning of the command line.
39 cccPrintOptions = False
40 cccPrintPhases = False
41 cccUseDriverDriver = True
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000042 while argv and argv[0].startswith('-ccc-'):
43 opt,argv = argv[0][5:],argv[1:]
Daniel Dunbara5677512009-01-05 19:53:30 +000044
45 if opt == 'print-options':
46 cccPrintOptions = True
47 elif opt == 'print-phases':
48 cccPrintPhases = True
49 elif opt == 'no-driver-driver':
50 # FIXME: Remove this once we have some way of being a
51 # cross compiler driver (cross driver compiler? compiler
52 # cross driver? etc.).
53 cccUseDriverDriver = False
54 else:
55 raise ValueError,"Invalid ccc option: %r" % cccPrintOptions
56
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000057 args = self.parser.parseArgs(argv)
Daniel Dunbara5677512009-01-05 19:53:30 +000058
59 # FIXME: Ho hum I have just realized -Xarch_ is broken. We really
60 # need to reparse the Arguments after they have been expanded by
61 # -Xarch. How is this going to work?
62 #
63 # Scratch that, we aren't going to do that; it really disrupts the
64 # organization, doesn't consistently work with gcc-dd, and is
65 # confusing. Instead we are going to enforce that -Xarch_ is only
66 # used with options which do not alter the driver behavior. Let's
67 # hope this is ok, because the current architecture is a little
68 # tied to it.
69
70 if cccPrintOptions:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000071 self.printOptions(args)
Daniel Dunbara5677512009-01-05 19:53:30 +000072 sys.exit(0)
73
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000074 self.handleImmediateOptions(args)
Daniel Dunbara5677512009-01-05 19:53:30 +000075
76 if cccUseDriverDriver:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000077 phases = self.buildPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +000078 else:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000079 phases = self.buildNormalPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +000080
81 if cccPrintPhases:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000082 self.printPhases(phases, args)
Daniel Dunbara5677512009-01-05 19:53:30 +000083 sys.exit(0)
84
85 if 0:
86 print Util.pprint(phases)
87
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000088 jobs = self.bindPhases(phases, args)
Daniel Dunbara5677512009-01-05 19:53:30 +000089
90 # FIXME: We should provide some basic sanity checking of the
91 # pipeline as a "verification" sort of stage. For example, the
92 # pipeline should never end up writing to an output file in two
93 # places (I think). The pipeline should also never end up writing
94 # to an output file that is an input.
95 #
96 # This is intended to just be a "verify" step, not a functionality
97 # step. It should catch things like the driver driver not
98 # preventing -save-temps, but it shouldn't change behavior (so we
99 # can turn it off in Release-Asserts builds).
100
101 # Print in -### syntax.
102 hasHashHashHash = None
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000103 for arg in args:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000104 if arg.opt.name == '-###':
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000105 hasHashHashHash = arg
Daniel Dunbara5677512009-01-05 19:53:30 +0000106
107 if hasHashHashHash:
108 self.claim(hasHashHashHash)
109 for j in jobs.iterjobs():
110 if isinstance(j, Jobs.Command):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000111 print '"%s"' % '" "'.join(j.render(argv))
Daniel Dunbara5677512009-01-05 19:53:30 +0000112 elif isinstance(j, Jobs.PipedJob):
113 for c in j.commands:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000114 print '"%s" %c' % ('" "'.join(c.render(argv)),
Daniel Dunbara5677512009-01-05 19:53:30 +0000115 "| "[c is j.commands[-1]])
116 elif not isinstance(j, JobList):
117 raise ValueError,'Encountered unknown job.'
118 sys.exit(0)
119
120 for j in jobs.iterjobs():
121 if isinstance(j, Jobs.Command):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000122 cmd_args = j.render(argv)
Daniel Dunbara5677512009-01-05 19:53:30 +0000123 res = os.spawnvp(os.P_WAIT, cmd_args[0], cmd_args)
124 if res:
125 sys.exit(res)
126 elif isinstance(j, Jobs.PipedJob):
127 raise NotImplementedError,"Piped jobs aren't implemented yet."
128 else:
129 raise ValueError,'Encountered unknown job.'
130
131 def claim(self, option):
132 # FIXME: Move to OptionList once introduced and implement.
133 pass
134
135 def warning(self, message):
136 print >>sys.stderr,'%s: %s' % (sys.argv[0], message)
137
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000138 def printOptions(self, args):
139 for i,arg in enumerate(args):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000140 if isinstance(arg, Arguments.MultipleValuesArg):
141 values = list(args.getValues(arg))
142 elif isinstance(arg, Arguments.ValueArg):
143 values = [args.getValue(arg)]
144 elif isinstance(arg, Arguments.JoinedAndSeparateValuesArg):
145 values = [args.getJoinedValue(arg), args.getSeparateValue(arg)]
Daniel Dunbara5677512009-01-05 19:53:30 +0000146 else:
147 values = []
Daniel Dunbar5039f212009-01-06 02:30:10 +0000148 print 'Option %d - Name: "%s", Values: {%s}' % (i, arg.opt.name,
Daniel Dunbara5677512009-01-05 19:53:30 +0000149 ', '.join(['"%s"' % v
150 for v in values]))
151
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000152 def printPhases(self, phases, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000153 def printPhase(p, f, steps, arch=None):
154 if p in steps:
155 return steps[p]
156 elif isinstance(p, Phases.BindArchAction):
157 for kid in p.inputs:
158 printPhase(kid, f, steps, p.arch)
159 steps[p] = len(steps)
160 return
161
162 if isinstance(p, Phases.InputAction):
163 phaseName = 'input'
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000164 inputStr = '"%s"' % args.getValue(p.filename)
Daniel Dunbara5677512009-01-05 19:53:30 +0000165 else:
166 phaseName = p.phase.name
167 inputs = [printPhase(i, f, steps, arch)
168 for i in p.inputs]
169 inputStr = '{%s}' % ', '.join(map(str, inputs))
170 if arch is not None:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000171 phaseName += '-' + args.getValue(arch)
Daniel Dunbara5677512009-01-05 19:53:30 +0000172 steps[p] = index = len(steps)
173 print "%d: %s, %s, %s" % (index,phaseName,inputStr,p.type.name)
174 return index
175 steps = {}
176 for phase in phases:
177 printPhase(phase, sys.stdout, steps)
178
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000179 def handleImmediateOptions(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000180 # FIXME: Some driver Arguments are consumed right off the bat,
181 # like -dumpversion. Currently the gcc-dd handles these
182 # poorly, so we should be ok handling them upfront instead of
183 # after driver-driver level dispatching.
184 #
185 # FIXME: The actual order of these options in gcc is all over the
186 # place. The -dump ones seem to be first and in specification
187 # order, but there are other levels of precedence. For example,
188 # -print-search-dirs is evaluated before -print-prog-name=,
189 # regardless of order (and the last instance of -print-prog-name=
190 # wins verse itself).
191 #
192 # FIXME: Do we want to report "argument unused" type errors in the
193 # presence of things like -dumpmachine and -print-search-dirs?
194 # Probably not.
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000195 for arg in args:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000196 if arg.opt.name == '-dumpmachine':
197 print 'FIXME: %s' % arg.opt.name
198 sys.exit(1)
199 elif arg.opt.name == '-dumpspecs':
200 print 'FIXME: %s' % arg.opt.name
201 sys.exit(1)
202 elif arg.opt.name == '-dumpversion':
203 print 'FIXME: %s' % arg.opt.name
204 sys.exit(1)
205 elif arg.opt.name == '-print-file-name=':
206 print 'FIXME: %s' % arg.opt.name
207 sys.exit(1)
208 elif arg.opt.name == '-print-multi-directory':
209 print 'FIXME: %s' % arg.opt.name
210 sys.exit(1)
211 elif arg.opt.name == '-print-multi-lib':
212 print 'FIXME: %s' % arg.opt.name
213 sys.exit(1)
214 elif arg.opt.name == '-print-prog-name=':
215 print 'FIXME: %s' % arg.opt.name
216 sys.exit(1)
217 elif arg.opt.name == '-print-libgcc-file-name':
218 print 'FIXME: %s' % arg.opt.name
219 sys.exit(1)
220 elif arg.opt.name == '-print-search-dirs':
221 print 'FIXME: %s' % arg.opt.name
222 sys.exit(1)
Daniel Dunbara5677512009-01-05 19:53:30 +0000223
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000224 def buildNormalPipeline(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000225 hasCombine = None
226 hasSyntaxOnly = None
227 hasDashC = hasDashE = hasDashS = None
228
229 inputType = None
230 inputTypeOpt = None
231 inputs = []
232 for a in args:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000233 if a.opt.name == '<input>':
Daniel Dunbara5677512009-01-05 19:53:30 +0000234 if inputType is None:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000235 base,ext = os.path.splitext(args.getValue(a))
Daniel Dunbara5677512009-01-05 19:53:30 +0000236 if ext and ext in Types.kTypeSuffixMap:
237 klass = Types.kTypeSuffixMap[ext]
238 else:
239 # FIXME: Its not clear why we shouldn't just
240 # revert to unknown. I think this is more likely a
241 # bug / unintended behavior in gcc. Not very
242 # important though.
243 klass = Types.ObjectType
244 else:
245 assert inputTypeOpt is not None
246 self.claim(inputTypeOpt)
247 klass = inputType
248 inputs.append((klass, a))
Daniel Dunbar5039f212009-01-06 02:30:10 +0000249 elif a.opt.name == '-E':
250 hasDashE = a
251 elif a.opt.name == '-S':
252 hasDashS = a
253 elif a.opt.name == '-c':
254 hasDashC = a
255 elif a.opt.name == '-fsyntax-only':
256 hasSyntaxOnly = a
257 elif a.opt.name == '-combine':
258 hasCombine = a
259 elif a.opt.name == '-filelist':
260 # Treat as a linker input.
261 #
262 # FIXME: This might not be good enough. We may
263 # need to introduce another type for this case, so
264 # that other code which needs to know the inputs
265 # handles this properly. Best not to try and lipo
266 # this, for example.
267 inputs.append((Types.ObjectType, a))
268 elif a.opt.name == '-x':
269 self.claim(a)
270 inputTypeOpt = a
271 value = args.getValue(a)
272 if value in Types.kTypeSpecifierMap:
273 inputType = Types.kTypeSpecifierMap[value]
274 else:
275 # FIXME: How are we going to handle diagnostics.
276 self.warning("language %s not recognized" % value)
Daniel Dunbara5677512009-01-05 19:53:30 +0000277
Daniel Dunbar5039f212009-01-06 02:30:10 +0000278 # FIXME: Its not clear why we shouldn't just
279 # revert to unknown. I think this is more likely a
280 # bug / unintended behavior in gcc. Not very
281 # important though.
282 inputType = ObjectType
Daniel Dunbara5677512009-01-05 19:53:30 +0000283
284 # We claim things here so that options for which we silently allow
285 # override only ever claim the used option.
286 if hasCombine:
287 self.claim(hasCombine)
288
289 finalPhase = Phases.Phase.eOrderPostAssemble
290 finalPhaseOpt = None
291
292 # Determine what compilation mode we are in.
293 if hasDashE:
294 finalPhase = Phases.Phase.eOrderPreprocess
295 finalPhaseOpt = hasDashE
296 elif hasSyntaxOnly:
297 finalPhase = Phases.Phase.eOrderCompile
298 finalPhaseOpt = hasSyntaxOnly
299 elif hasDashS:
300 finalPhase = Phases.Phase.eOrderCompile
301 finalPhaseOpt = hasDashS
302 elif hasDashC:
303 finalPhase = Phases.Phase.eOrderAssemble
304 finalPhaseOpt = hasDashC
305
306 if finalPhaseOpt:
307 self.claim(finalPhaseOpt)
308
309 # FIXME: Support -combine.
310 if hasCombine:
311 raise NotImplementedError,"-combine is not yet supported."
312
313 actions = []
314 linkerInputs = []
315 # FIXME: This is gross.
316 linkPhase = Phases.LinkPhase()
317 for klass,input in inputs:
318 # Figure out what step to start at.
319
320 # FIXME: This should be part of the input class probably?
321 # Altough it doesn't quite fit there either, things like
322 # asm-with-preprocess don't easily fit into a linear scheme.
323
324 # FIXME: I think we are going to end up wanting to just build
325 # a simple FSA which we run the inputs down.
326 sequence = []
327 if klass.preprocess:
328 sequence.append(Phases.PreprocessPhase())
329 if klass == Types.ObjectType:
330 sequence.append(linkPhase)
331 elif klass.onlyAssemble:
332 sequence.extend([Phases.AssemblePhase(),
333 linkPhase])
334 elif klass.onlyPrecompile:
335 sequence.append(Phases.PrecompilePhase())
336 else:
337 sequence.extend([Phases.CompilePhase(),
338 Phases.AssemblePhase(),
339 linkPhase])
340
341 if sequence[0].order > finalPhase:
342 assert finalPhaseOpt and finalPhaseOpt.opt
343 # FIXME: Explain what type of input file is. Or just match
344 # gcc warning.
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000345 self.warning("%s: %s input file unused when %s is present" % (args.getValue(input),
Daniel Dunbara5677512009-01-05 19:53:30 +0000346 sequence[0].name,
347 finalPhaseOpt.opt.name))
348 else:
349 # Build the pipeline for this file.
350
351 current = Phases.InputAction(input, klass)
352 for transition in sequence:
353 # If the current action produces no output, or we are
354 # past what the user requested, we are done.
355 if (current.type is Types.NothingType or
356 transition.order > finalPhase):
357 break
358 else:
359 if isinstance(transition, Phases.PreprocessPhase):
360 assert isinstance(klass.preprocess, Types.InputType)
361 current = Phases.JobAction(transition,
362 [current],
363 klass.preprocess)
364 elif isinstance(transition, Phases.PrecompilePhase):
365 current = Phases.JobAction(transition,
366 [current],
367 Types.PCHType)
368 elif isinstance(transition, Phases.CompilePhase):
369 if hasSyntaxOnly:
370 output = Types.NothingType
371 else:
372 output = Types.AsmTypeNoPP
373 current = Phases.JobAction(transition,
374 [current],
375 output)
376 elif isinstance(transition, Phases.AssemblePhase):
377 current = Phases.JobAction(transition,
378 [current],
379 Types.ObjectType)
380 elif transition is linkPhase:
381 linkerInputs.append(current)
382 current = None
383 break
384 else:
385 raise RuntimeError,'Unrecognized transition: %s.' % transition
386 pass
387
388 if current is not None:
389 assert not isinstance(current, Phases.InputAction)
390 actions.append(current)
391
392 if linkerInputs:
393 actions.append(Phases.JobAction(linkPhase,
394 linkerInputs,
395 Types.ImageType))
396
397 return actions
398
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000399 def buildPipeline(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000400 # FIXME: We need to handle canonicalization of the specified arch.
401
402 archs = []
403 hasOutput = None
404 hasDashM = hasSaveTemps = None
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000405 for arg in args:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000406 if arg.opt.name == '-arch':
407 archs.append(arg)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000408 elif arg.opt.name.startswith('-M'):
409 hasDashM = arg
410 elif arg.opt.name in ('-save-temps','--save-temps'):
411 hasSaveTemps = arg
Daniel Dunbara5677512009-01-05 19:53:30 +0000412
413 if not archs:
414 # FIXME: Need to infer arch so that we sub -Xarch
415 # correctly.
416 archs.append(Arguments.DerivedArg('i386'))
417
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000418 actions = self.buildNormalPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000419
420 # FIXME: Use custom exception for this.
421 #
422 # FIXME: We killed off some others but these aren't yet detected in
423 # a functional manner. If we added information to jobs about which
424 # "auxiliary" files they wrote then we could detect the conflict
425 # these cause downstream.
426 if len(archs) > 1:
427 if hasDashM:
428 raise ValueError,"Cannot use -M options with multiple arch flags."
429 elif hasSaveTemps:
430 raise ValueError,"Cannot use -save-temps with multiple arch flags."
431
432 # Execute once per arch.
433 finalActions = []
434 for p in actions:
435 # Make sure we can lipo this kind of output. If not (and it
436 # is an actual output) then we disallow, since we can't
437 # create an output file with the right name without
438 # overwriting it. We could remove this oddity by just
439 # changing the output names to include the arch, which would
440 # also fix -save-temps. Compatibility wins for now.
441 #
442 # FIXME: Is this error substantially less useful than
443 # gcc-dd's? The main problem is that "Cannot use compiler
444 # output with multiple arch flags" won't make sense to most
445 # developers.
446 if (len(archs) > 1 and
447 p.type not in (Types.NothingType,Types.ObjectType,Types.ImageType)):
448 raise ValueError,'Cannot use %s output with multiple arch flags.' % p.type.name
449
450 inputs = []
451 for arch in archs:
452 inputs.append(Phases.BindArchAction(p, arch))
453
454 # Lipo if necessary. We do it this way because we need to set
455 # the arch flag so that -Xarch_ gets rewritten.
456 if len(inputs) == 1 or p.type == Types.NothingType:
457 finalActions.extend(inputs)
458 else:
459 finalActions.append(Phases.JobAction(Phases.LipoPhase(),
460 inputs,
461 p.type))
462
463 # FIXME: We need to add -Wl,arch_multiple and -Wl,final_output in
464 # certain cases. This may be icky because we need to figure out the
465 # mode first. Current plan is to hack on the pipeline once it is built
466 # and we know what is being spit out. This avoids having to handling
467 # things like -c and -combine in multiple places.
468 #
469 # The annoying one of these is -Wl,final_output because it involves
470 # communication across different phases.
471 #
472 # Hopefully we can do this purely as part of the binding, but
473 # leaving comment here for now until it is clear this works.
474
475 return finalActions
476
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000477 def bindPhases(self, phases, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000478 jobs = Jobs.JobList()
479
480 finalOutput = None
481 hasSaveTemps = hasNoIntegratedCPP = hasPipe = None
482 forward = []
483 for a in args:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000484 if a.opt.name == '<input>':
Daniel Dunbara5677512009-01-05 19:53:30 +0000485 pass
Daniel Dunbar5039f212009-01-06 02:30:10 +0000486 elif a.opt.name == '-save-temps':
487 hasSaveTemps = a
488 elif a.opt.name == '-no-integrated-cpp':
489 hasNoIntegratedCPP = a
490 elif a.opt.name == '-o':
491 finalOutput = a
492 elif a.opt.name == '-pipe':
493 hasPipe = a
494 elif a.opt.name in ('-E', '-S', '-c',
495 '-arch', '-fsyntax-only', '-combine', '-x',
496 '-###'):
497 pass
Daniel Dunbara5677512009-01-05 19:53:30 +0000498 else:
499 forward.append(a)
500
501 # We claim things here so that options for which we silently allow
502 # override only ever claim the used option.
503 if hasPipe:
504 self.claim(hasPipe)
505 # FIXME: Hack, override -pipe till we support it.
506 hasPipe = None
507 # Claim these here. Its not completely accurate but any warnings
508 # about these being unused are likely to be noise anyway.
509 if hasSaveTemps:
510 self.claim(hasSaveTemps)
511 if hasNoIntegratedCPP:
512 self.claim(hasNoIntegratedCPP)
513
514 toolMap = {
515 Phases.PreprocessPhase : Tools.GCC_PreprocessTool(),
516 Phases.CompilePhase : Tools.GCC_CompileTool(),
517 Phases.PrecompilePhase : Tools.GCC_PrecompileTool(),
518 Phases.AssemblePhase : Tools.DarwinAssemblerTool(),
519 Phases.LinkPhase : Tools.Collect2Tool(),
520 Phases.LipoPhase : Tools.LipoTool(),
521 }
522
523 class InputInfo:
524 def __init__(self, source, type, baseInput):
525 self.source = source
526 self.type = type
527 self.baseInput = baseInput
528
529 def __repr__(self):
530 return '%s(%r, %r, %r)' % (self.__class__.__name__,
531 self.source, self.type, self.baseInput)
532
533 def createJobs(phase, forwardArgs,
534 canAcceptPipe=False, atTopLevel=False, arch=None):
535 if isinstance(phase, Phases.InputAction):
536 return InputInfo(phase.filename, phase.type, phase.filename)
537 elif isinstance(phase, Phases.BindArchAction):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000538 archName = args.getValue(phase.arch)
Daniel Dunbara5677512009-01-05 19:53:30 +0000539 filteredArgs = []
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000540 for arg in forwardArgs:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000541 if arg.opt.name == '-arch':
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000542 if arg is phase.arch:
543 filteredArgs.append(arg)
544 elif arg.opt.name == '-Xarch_':
Daniel Dunbara5677512009-01-05 19:53:30 +0000545 # FIXME: gcc-dd has another conditional for passing
546 # through, when the arch conditional array has an empty
547 # string. Why?
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000548 if args.getJoinedValue(arg) == archName:
Daniel Dunbara5677512009-01-05 19:53:30 +0000549 # FIXME: This is wrong, we don't want a
550 # DerivedArg we want an actual parsed version
551 # of this arg.
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000552 filteredArgs.append(Arguments.DerivedArg(args.getSeparateValue(arg)))
Daniel Dunbara5677512009-01-05 19:53:30 +0000553 else:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000554 filteredArgs.append(arg)
Daniel Dunbara5677512009-01-05 19:53:30 +0000555
556 return createJobs(phase.inputs[0], filteredArgs,
557 canAcceptPipe, atTopLevel, phase.arch)
558
559 assert isinstance(phase, Phases.JobAction)
560 tool = toolMap[phase.phase.__class__]
561
562 # See if we should use an integrated CPP. We only use an
563 # integrated cpp when we have exactly one input, since this is
564 # the only use case we care about.
565 useIntegratedCPP = False
566 inputList = phase.inputs
567 if (not hasNoIntegratedCPP and
568 not hasSaveTemps and
569 tool.hasIntegratedCPP()):
570 if (len(phase.inputs) == 1 and
571 isinstance(phase.inputs[0].phase, Phases.PreprocessPhase)):
572 useIntegratedCPP = True
573 inputList = phase.inputs[0].inputs
574
575 # Only try to use pipes when exactly one input.
576 canAcceptPipe = len(inputList) == 1 and tool.acceptsPipedInput()
577 inputs = [createJobs(p, forwardArgs, canAcceptPipe, False, arch) for p in inputList]
578
579 # Determine if we should output to a pipe.
580 canOutputToPipe = canAcceptPipe and tool.canPipeOutput()
581 outputToPipe = False
582 if canOutputToPipe:
583 # Some things default to writing to a pipe if the final
584 # phase and there was no user override.
585 #
586 # FIXME: What is the best way to handle this?
587 if (atTopLevel and
588 isinstance(phase, Phases.PreprocessPhase) and
589 not finalOutput):
590 outputToPipe = True
591 elif hasPipe:
592 outputToPipe = True
593
594 # Figure out where to put the job (pipes).
595 jobList = jobs
596 if canAcceptPipe and isinstance(inputs[0].source, Jobs.PipedJob):
597 jobList = inputs[0].source
598
599 # Figure out where to put the output.
600 baseInput = inputs[0].baseInput
601 if phase.type == Types.NothingType:
602 output = None
603 elif outputToPipe:
604 if isinstance(jobList, Jobs.PipedJob):
605 output = jobList
606 else:
607 jobList = output = Jobs.PipedJob([])
608 jobs.addJob(output)
609 else:
610 # Figure out what the derived output location would be.
611 #
612 # FIXME: gcc has some special case in here so that it doesn't
613 # create output files if they would conflict with an input.
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000614 inputName = args.getValue(baseInput)
Daniel Dunbara5677512009-01-05 19:53:30 +0000615 if phase.type is Types.ImageType:
616 namedOutput = "a.out"
617 else:
618 base,_ = os.path.splitext(inputName)
619 assert phase.type.tempSuffix is not None
620 namedOutput = base + phase.type.tempSuffix
621
622 # Output to user requested destination?
623 if atTopLevel and finalOutput:
624 output = finalOutput
625 # Contruct a named destination?
626 elif atTopLevel or hasSaveTemps:
627 output = Arguments.DerivedArg(namedOutput)
628 else:
629 # Output to temp file...
630 fd,filename = tempfile.mkstemp(suffix=phase.type.tempSuffix)
631 output = Arguments.DerivedArg(filename)
632
633 tool.constructJob(phase, arch, jobList, inputs, output, phase.type, forwardArgs)
634
635 return InputInfo(output, phase.type, baseInput)
636
637 # It is an error to provide a -o option if we are making multiple
638 # output files.
639 if finalOutput and len([a for a in phases if a.type is not Types.NothingType]) > 1:
640 # FIXME: Custom exception.
641 raise ValueError,"Cannot specify -o when generating multiple files."
642
643 for phase in phases:
644 createJobs(phase, forward, canAcceptPipe=True, atTopLevel=True)
645
646 return jobs