blob: 85b440e23e6cb2b6d04a1edc03b788f35e0e7b09 [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):
Daniel Dunbarba6e3232009-01-06 06:12:13 +000028 self.parser = Arguments.OptionParser()
Daniel Dunbara5677512009-01-05 19:53:30 +000029
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.
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000102 hasHashHashHash = args.getLastArg(self.parser.hashHashHashOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000103 if hasHashHashHash:
104 self.claim(hasHashHashHash)
105 for j in jobs.iterjobs():
106 if isinstance(j, Jobs.Command):
Daniel Dunbardb439902009-01-07 18:40:45 +0000107 print '"%s"' % '" "'.join(j.getArgv())
Daniel Dunbara5677512009-01-05 19:53:30 +0000108 elif isinstance(j, Jobs.PipedJob):
109 for c in j.commands:
Daniel Dunbardb439902009-01-07 18:40:45 +0000110 print '"%s" %c' % ('" "'.join(c.getArgv()),
Daniel Dunbara5677512009-01-05 19:53:30 +0000111 "| "[c is j.commands[-1]])
112 elif not isinstance(j, JobList):
113 raise ValueError,'Encountered unknown job.'
114 sys.exit(0)
115
116 for j in jobs.iterjobs():
117 if isinstance(j, Jobs.Command):
Daniel Dunbardb439902009-01-07 18:40:45 +0000118 res = os.spawnvp(os.P_WAIT, j.executable, j.getArgv())
Daniel Dunbara5677512009-01-05 19:53:30 +0000119 if res:
120 sys.exit(res)
121 elif isinstance(j, Jobs.PipedJob):
122 raise NotImplementedError,"Piped jobs aren't implemented yet."
123 else:
124 raise ValueError,'Encountered unknown job.'
125
126 def claim(self, option):
127 # FIXME: Move to OptionList once introduced and implement.
128 pass
129
130 def warning(self, message):
131 print >>sys.stderr,'%s: %s' % (sys.argv[0], message)
132
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000133 def printOptions(self, args):
134 for i,arg in enumerate(args):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000135 if isinstance(arg, Arguments.MultipleValuesArg):
136 values = list(args.getValues(arg))
137 elif isinstance(arg, Arguments.ValueArg):
138 values = [args.getValue(arg)]
139 elif isinstance(arg, Arguments.JoinedAndSeparateValuesArg):
140 values = [args.getJoinedValue(arg), args.getSeparateValue(arg)]
Daniel Dunbara5677512009-01-05 19:53:30 +0000141 else:
142 values = []
Daniel Dunbar5039f212009-01-06 02:30:10 +0000143 print 'Option %d - Name: "%s", Values: {%s}' % (i, arg.opt.name,
Daniel Dunbara5677512009-01-05 19:53:30 +0000144 ', '.join(['"%s"' % v
145 for v in values]))
146
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000147 def printPhases(self, phases, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000148 def printPhase(p, f, steps, arch=None):
149 if p in steps:
150 return steps[p]
151 elif isinstance(p, Phases.BindArchAction):
152 for kid in p.inputs:
153 printPhase(kid, f, steps, p.arch)
154 steps[p] = len(steps)
155 return
156
157 if isinstance(p, Phases.InputAction):
158 phaseName = 'input'
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000159 inputStr = '"%s"' % args.getValue(p.filename)
Daniel Dunbara5677512009-01-05 19:53:30 +0000160 else:
161 phaseName = p.phase.name
162 inputs = [printPhase(i, f, steps, arch)
163 for i in p.inputs]
164 inputStr = '{%s}' % ', '.join(map(str, inputs))
165 if arch is not None:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000166 phaseName += '-' + args.getValue(arch)
Daniel Dunbara5677512009-01-05 19:53:30 +0000167 steps[p] = index = len(steps)
168 print "%d: %s, %s, %s" % (index,phaseName,inputStr,p.type.name)
169 return index
170 steps = {}
171 for phase in phases:
172 printPhase(phase, sys.stdout, steps)
173
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000174 def handleImmediateOptions(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000175 # FIXME: Some driver Arguments are consumed right off the bat,
176 # like -dumpversion. Currently the gcc-dd handles these
177 # poorly, so we should be ok handling them upfront instead of
178 # after driver-driver level dispatching.
179 #
180 # FIXME: The actual order of these options in gcc is all over the
181 # place. The -dump ones seem to be first and in specification
182 # order, but there are other levels of precedence. For example,
183 # -print-search-dirs is evaluated before -print-prog-name=,
184 # regardless of order (and the last instance of -print-prog-name=
185 # wins verse itself).
186 #
187 # FIXME: Do we want to report "argument unused" type errors in the
188 # presence of things like -dumpmachine and -print-search-dirs?
189 # Probably not.
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000190 arg = args.getLastArg(self.parser.dumpmachineOption)
191 if arg:
192 print 'FIXME: %s' % arg.opt.name
193 sys.exit(1)
194
195 arg = args.getLastArg(self.parser.dumpspecsOption)
196 if arg:
197 print 'FIXME: %s' % arg.opt.name
198 sys.exit(1)
199
200 arg = args.getLastArg(self.parser.dumpversionOption)
201 if arg:
202 print 'FIXME: %s' % arg.opt.name
203 sys.exit(1)
204
205 arg = args.getLastArg(self.parser.printFileNameOption)
206 if arg:
207 print 'FIXME: %s' % arg.opt.name
208 sys.exit(1)
209
210 arg = args.getLastArg(self.parser.printMultiDirectoryOption)
211 if arg:
212 print 'FIXME: %s' % arg.opt.name
213 sys.exit(1)
214
215 arg = args.getLastArg(self.parser.printMultiLibOption)
216 if arg:
217 print 'FIXME: %s' % arg.opt.name
218 sys.exit(1)
219
220 arg = args.getLastArg(self.parser.printProgNameOption)
221 if arg:
222 print 'FIXME: %s' % arg.opt.name
223 sys.exit(1)
224
225 arg = args.getLastArg(self.parser.printLibgccFilenameOption)
226 if arg:
227 print 'FIXME: %s' % arg.opt.name
228 sys.exit(1)
229
230 arg = args.getLastArg(self.parser.printSearchDirsOption)
231 if arg:
232 print 'FIXME: %s' % arg.opt.name
233 sys.exit(1)
Daniel Dunbara5677512009-01-05 19:53:30 +0000234
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000235 def buildNormalPipeline(self, args):
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000236 hasCombine = args.getLastArg(self.parser.combineOption)
237 hasSyntaxOnly = args.getLastArg(self.parser.syntaxOnlyOption)
238 hasDashC = args.getLastArg(self.parser.cOption)
239 hasDashE = args.getLastArg(self.parser.EOption)
240 hasDashS = args.getLastArg(self.parser.SOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000241
242 inputType = None
243 inputTypeOpt = None
244 inputs = []
245 for a in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000246 if a.opt is self.parser.inputOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000247 if inputType is None:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000248 base,ext = os.path.splitext(args.getValue(a))
Daniel Dunbara5677512009-01-05 19:53:30 +0000249 if ext and ext in Types.kTypeSuffixMap:
250 klass = Types.kTypeSuffixMap[ext]
251 else:
252 # FIXME: Its not clear why we shouldn't just
253 # revert to unknown. I think this is more likely a
254 # bug / unintended behavior in gcc. Not very
255 # important though.
256 klass = Types.ObjectType
257 else:
258 assert inputTypeOpt is not None
259 self.claim(inputTypeOpt)
260 klass = inputType
261 inputs.append((klass, a))
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000262 elif a.opt is self.parser.filelistOption:
263 # Treat as a linker input. Investigate how gcc is
264 # handling this.
Daniel Dunbar5039f212009-01-06 02:30:10 +0000265 #
266 # FIXME: This might not be good enough. We may
267 # need to introduce another type for this case, so
268 # that other code which needs to know the inputs
269 # handles this properly. Best not to try and lipo
270 # this, for example.
271 inputs.append((Types.ObjectType, a))
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000272 elif a.opt is self.parser.xOption:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000273 self.claim(a)
274 inputTypeOpt = a
275 value = args.getValue(a)
276 if value in Types.kTypeSpecifierMap:
277 inputType = Types.kTypeSpecifierMap[value]
278 else:
279 # FIXME: How are we going to handle diagnostics.
280 self.warning("language %s not recognized" % value)
Daniel Dunbara5677512009-01-05 19:53:30 +0000281
Daniel Dunbar5039f212009-01-06 02:30:10 +0000282 # FIXME: Its not clear why we shouldn't just
283 # revert to unknown. I think this is more likely a
284 # bug / unintended behavior in gcc. Not very
285 # important though.
286 inputType = ObjectType
Daniel Dunbara5677512009-01-05 19:53:30 +0000287
288 # We claim things here so that options for which we silently allow
289 # override only ever claim the used option.
290 if hasCombine:
291 self.claim(hasCombine)
292
293 finalPhase = Phases.Phase.eOrderPostAssemble
294 finalPhaseOpt = None
295
296 # Determine what compilation mode we are in.
297 if hasDashE:
298 finalPhase = Phases.Phase.eOrderPreprocess
299 finalPhaseOpt = hasDashE
300 elif hasSyntaxOnly:
301 finalPhase = Phases.Phase.eOrderCompile
302 finalPhaseOpt = hasSyntaxOnly
303 elif hasDashS:
304 finalPhase = Phases.Phase.eOrderCompile
305 finalPhaseOpt = hasDashS
306 elif hasDashC:
307 finalPhase = Phases.Phase.eOrderAssemble
308 finalPhaseOpt = hasDashC
309
310 if finalPhaseOpt:
311 self.claim(finalPhaseOpt)
312
313 # FIXME: Support -combine.
314 if hasCombine:
315 raise NotImplementedError,"-combine is not yet supported."
316
317 actions = []
318 linkerInputs = []
319 # FIXME: This is gross.
320 linkPhase = Phases.LinkPhase()
321 for klass,input in inputs:
322 # Figure out what step to start at.
323
324 # FIXME: This should be part of the input class probably?
325 # Altough it doesn't quite fit there either, things like
326 # asm-with-preprocess don't easily fit into a linear scheme.
327
328 # FIXME: I think we are going to end up wanting to just build
329 # a simple FSA which we run the inputs down.
330 sequence = []
331 if klass.preprocess:
332 sequence.append(Phases.PreprocessPhase())
333 if klass == Types.ObjectType:
334 sequence.append(linkPhase)
335 elif klass.onlyAssemble:
336 sequence.extend([Phases.AssemblePhase(),
337 linkPhase])
338 elif klass.onlyPrecompile:
339 sequence.append(Phases.PrecompilePhase())
340 else:
341 sequence.extend([Phases.CompilePhase(),
342 Phases.AssemblePhase(),
343 linkPhase])
344
345 if sequence[0].order > finalPhase:
346 assert finalPhaseOpt and finalPhaseOpt.opt
347 # FIXME: Explain what type of input file is. Or just match
348 # gcc warning.
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000349 self.warning("%s: %s input file unused when %s is present" % (args.getValue(input),
Daniel Dunbara5677512009-01-05 19:53:30 +0000350 sequence[0].name,
351 finalPhaseOpt.opt.name))
352 else:
353 # Build the pipeline for this file.
354
355 current = Phases.InputAction(input, klass)
356 for transition in sequence:
357 # If the current action produces no output, or we are
358 # past what the user requested, we are done.
359 if (current.type is Types.NothingType or
360 transition.order > finalPhase):
361 break
362 else:
363 if isinstance(transition, Phases.PreprocessPhase):
364 assert isinstance(klass.preprocess, Types.InputType)
365 current = Phases.JobAction(transition,
366 [current],
367 klass.preprocess)
368 elif isinstance(transition, Phases.PrecompilePhase):
369 current = Phases.JobAction(transition,
370 [current],
371 Types.PCHType)
372 elif isinstance(transition, Phases.CompilePhase):
373 if hasSyntaxOnly:
374 output = Types.NothingType
375 else:
376 output = Types.AsmTypeNoPP
377 current = Phases.JobAction(transition,
378 [current],
379 output)
380 elif isinstance(transition, Phases.AssemblePhase):
381 current = Phases.JobAction(transition,
382 [current],
383 Types.ObjectType)
384 elif transition is linkPhase:
385 linkerInputs.append(current)
386 current = None
387 break
388 else:
389 raise RuntimeError,'Unrecognized transition: %s.' % transition
390 pass
391
392 if current is not None:
393 assert not isinstance(current, Phases.InputAction)
394 actions.append(current)
395
396 if linkerInputs:
397 actions.append(Phases.JobAction(linkPhase,
398 linkerInputs,
399 Types.ImageType))
400
401 return actions
402
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000403 def buildPipeline(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000404 # FIXME: We need to handle canonicalization of the specified arch.
405
406 archs = []
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000407 hasDashM = None
408 hasSaveTemps = (args.getLastArg(self.parser.saveTempsOption) or
409 args.getLastArg(self.parser.saveTempsOption2))
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000410 for arg in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000411 if arg.opt is self.parser.archOption:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000412 archs.append(arg)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000413 elif arg.opt.name.startswith('-M'):
414 hasDashM = arg
Daniel Dunbara5677512009-01-05 19:53:30 +0000415
416 if not archs:
417 # FIXME: Need to infer arch so that we sub -Xarch
418 # correctly.
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000419 archs.append(args.makeSeparateArg('i386',
420 self.parser.archOption))
Daniel Dunbara5677512009-01-05 19:53:30 +0000421
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000422 actions = self.buildNormalPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000423
424 # FIXME: Use custom exception for this.
425 #
426 # FIXME: We killed off some others but these aren't yet detected in
427 # a functional manner. If we added information to jobs about which
428 # "auxiliary" files they wrote then we could detect the conflict
429 # these cause downstream.
430 if len(archs) > 1:
431 if hasDashM:
432 raise ValueError,"Cannot use -M options with multiple arch flags."
433 elif hasSaveTemps:
434 raise ValueError,"Cannot use -save-temps with multiple arch flags."
435
436 # Execute once per arch.
437 finalActions = []
438 for p in actions:
439 # Make sure we can lipo this kind of output. If not (and it
440 # is an actual output) then we disallow, since we can't
441 # create an output file with the right name without
442 # overwriting it. We could remove this oddity by just
443 # changing the output names to include the arch, which would
444 # also fix -save-temps. Compatibility wins for now.
445 #
446 # FIXME: Is this error substantially less useful than
447 # gcc-dd's? The main problem is that "Cannot use compiler
448 # output with multiple arch flags" won't make sense to most
449 # developers.
450 if (len(archs) > 1 and
451 p.type not in (Types.NothingType,Types.ObjectType,Types.ImageType)):
452 raise ValueError,'Cannot use %s output with multiple arch flags.' % p.type.name
453
454 inputs = []
455 for arch in archs:
456 inputs.append(Phases.BindArchAction(p, arch))
457
458 # Lipo if necessary. We do it this way because we need to set
459 # the arch flag so that -Xarch_ gets rewritten.
460 if len(inputs) == 1 or p.type == Types.NothingType:
461 finalActions.extend(inputs)
462 else:
463 finalActions.append(Phases.JobAction(Phases.LipoPhase(),
464 inputs,
465 p.type))
466
467 # FIXME: We need to add -Wl,arch_multiple and -Wl,final_output in
468 # certain cases. This may be icky because we need to figure out the
469 # mode first. Current plan is to hack on the pipeline once it is built
470 # and we know what is being spit out. This avoids having to handling
471 # things like -c and -combine in multiple places.
472 #
473 # The annoying one of these is -Wl,final_output because it involves
474 # communication across different phases.
475 #
476 # Hopefully we can do this purely as part of the binding, but
477 # leaving comment here for now until it is clear this works.
478
479 return finalActions
480
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000481 def bindPhases(self, phases, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000482 jobs = Jobs.JobList()
483
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000484 finalOutput = args.getLastArg(self.parser.oOption)
485 hasSaveTemps = (args.getLastArg(self.parser.saveTempsOption) or
486 args.getLastArg(self.parser.saveTempsOption2))
487 hasNoIntegratedCPP = args.getLastArg(self.parser.noIntegratedCPPOption)
488 hasPipe = args.getLastArg(self.parser.pipeOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000489 forward = []
490 for a in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000491 if a.opt is self.parser.inputOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000492 pass
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000493
494 # FIXME: Needs to be part of option.
Daniel Dunbar5039f212009-01-06 02:30:10 +0000495 elif a.opt.name in ('-E', '-S', '-c',
496 '-arch', '-fsyntax-only', '-combine', '-x',
497 '-###'):
498 pass
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000499
Daniel Dunbara5677512009-01-05 19:53:30 +0000500 else:
501 forward.append(a)
502
503 # We claim things here so that options for which we silently allow
504 # override only ever claim the used option.
505 if hasPipe:
506 self.claim(hasPipe)
507 # FIXME: Hack, override -pipe till we support it.
508 hasPipe = None
509 # Claim these here. Its not completely accurate but any warnings
510 # about these being unused are likely to be noise anyway.
511 if hasSaveTemps:
512 self.claim(hasSaveTemps)
513 if hasNoIntegratedCPP:
514 self.claim(hasNoIntegratedCPP)
515
516 toolMap = {
517 Phases.PreprocessPhase : Tools.GCC_PreprocessTool(),
518 Phases.CompilePhase : Tools.GCC_CompileTool(),
519 Phases.PrecompilePhase : Tools.GCC_PrecompileTool(),
520 Phases.AssemblePhase : Tools.DarwinAssemblerTool(),
521 Phases.LinkPhase : Tools.Collect2Tool(),
522 Phases.LipoPhase : Tools.LipoTool(),
523 }
524
525 class InputInfo:
526 def __init__(self, source, type, baseInput):
527 self.source = source
528 self.type = type
529 self.baseInput = baseInput
530
531 def __repr__(self):
532 return '%s(%r, %r, %r)' % (self.__class__.__name__,
533 self.source, self.type, self.baseInput)
534
535 def createJobs(phase, forwardArgs,
536 canAcceptPipe=False, atTopLevel=False, arch=None):
537 if isinstance(phase, Phases.InputAction):
538 return InputInfo(phase.filename, phase.type, phase.filename)
539 elif isinstance(phase, Phases.BindArchAction):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000540 archName = args.getValue(phase.arch)
Daniel Dunbara5677512009-01-05 19:53:30 +0000541 filteredArgs = []
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000542 for arg in forwardArgs:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000543 if arg.opt is self.parser.archOption:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000544 if arg is phase.arch:
545 filteredArgs.append(arg)
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000546 elif arg.opt is self.parser.XarchOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000547 # FIXME: gcc-dd has another conditional for passing
548 # through, when the arch conditional array has an empty
549 # string. Why?
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000550 if args.getJoinedValue(arg) == archName:
Daniel Dunbara5677512009-01-05 19:53:30 +0000551 # FIXME: This is wrong, we don't want a
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000552 # unknown arg we want an actual parsed
553 # version of this arg.
554 filteredArgs.append(args.makeUnknownArg(args.getSeparateValue(arg)))
Daniel Dunbara5677512009-01-05 19:53:30 +0000555 else:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000556 filteredArgs.append(arg)
Daniel Dunbara5677512009-01-05 19:53:30 +0000557
558 return createJobs(phase.inputs[0], filteredArgs,
559 canAcceptPipe, atTopLevel, phase.arch)
560
561 assert isinstance(phase, Phases.JobAction)
562 tool = toolMap[phase.phase.__class__]
563
564 # See if we should use an integrated CPP. We only use an
565 # integrated cpp when we have exactly one input, since this is
566 # the only use case we care about.
567 useIntegratedCPP = False
568 inputList = phase.inputs
569 if (not hasNoIntegratedCPP and
570 not hasSaveTemps and
571 tool.hasIntegratedCPP()):
572 if (len(phase.inputs) == 1 and
573 isinstance(phase.inputs[0].phase, Phases.PreprocessPhase)):
574 useIntegratedCPP = True
575 inputList = phase.inputs[0].inputs
576
577 # Only try to use pipes when exactly one input.
578 canAcceptPipe = len(inputList) == 1 and tool.acceptsPipedInput()
579 inputs = [createJobs(p, forwardArgs, canAcceptPipe, False, arch) for p in inputList]
580
581 # Determine if we should output to a pipe.
582 canOutputToPipe = canAcceptPipe and tool.canPipeOutput()
583 outputToPipe = False
584 if canOutputToPipe:
585 # Some things default to writing to a pipe if the final
586 # phase and there was no user override.
587 #
588 # FIXME: What is the best way to handle this?
589 if (atTopLevel and
590 isinstance(phase, Phases.PreprocessPhase) and
591 not finalOutput):
592 outputToPipe = True
593 elif hasPipe:
594 outputToPipe = True
595
596 # Figure out where to put the job (pipes).
597 jobList = jobs
598 if canAcceptPipe and isinstance(inputs[0].source, Jobs.PipedJob):
599 jobList = inputs[0].source
600
601 # Figure out where to put the output.
602 baseInput = inputs[0].baseInput
603 if phase.type == Types.NothingType:
604 output = None
605 elif outputToPipe:
606 if isinstance(jobList, Jobs.PipedJob):
607 output = jobList
608 else:
609 jobList = output = Jobs.PipedJob([])
610 jobs.addJob(output)
611 else:
612 # Figure out what the derived output location would be.
613 #
614 # FIXME: gcc has some special case in here so that it doesn't
615 # create output files if they would conflict with an input.
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000616 inputName = args.getValue(baseInput)
Daniel Dunbara5677512009-01-05 19:53:30 +0000617 if phase.type is Types.ImageType:
618 namedOutput = "a.out"
619 else:
620 base,_ = os.path.splitext(inputName)
621 assert phase.type.tempSuffix is not None
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000622 namedOutput = base + '.' + phase.type.tempSuffix
Daniel Dunbara5677512009-01-05 19:53:30 +0000623
624 # Output to user requested destination?
625 if atTopLevel and finalOutput:
626 output = finalOutput
627 # Contruct a named destination?
628 elif atTopLevel or hasSaveTemps:
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000629 output = args.makeSeparateArg(namedOutput,
630 self.parser.oOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000631 else:
632 # Output to temp file...
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000633 fd,filename = tempfile.mkstemp(suffix='.'+phase.type.tempSuffix)
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000634 output = args.makeSeparateArg(filename,
635 self.parser.oOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000636
Daniel Dunbardb439902009-01-07 18:40:45 +0000637 tool.constructJob(phase, arch, jobList, inputs, output, phase.type,
638 forwardArgs, args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000639
640 return InputInfo(output, phase.type, baseInput)
641
642 # It is an error to provide a -o option if we are making multiple
643 # output files.
644 if finalOutput and len([a for a in phases if a.type is not Types.NothingType]) > 1:
645 # FIXME: Custom exception.
646 raise ValueError,"Cannot specify -o when generating multiple files."
647
648 for phase in phases:
649 createJobs(phase, forward, canAcceptPipe=True, atTopLevel=True)
650
651 return jobs