blob: 983a52bd185ddf97f018d0ac12dedb559fc3dd08 [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 Dunbara75ea3d2009-01-09 22:21:24 +000033 # Host queries which can be forcibly over-riden by the user for
34 # testing purposes.
35 #
36 # FIXME: We should make sure these are drawn from a fixed set so
37 # that nothing downstream ever plays a guessing game.
38
39 def getHostBits(self):
40 if self.cccHostBits:
41 return self.cccHostBits
42
43 return platform.architecture()[0].replace('bit','')
44
45 def getHostMachine(self):
46 if self.cccHostMachine:
47 return self.cccHostMachine
48
49 machine = platform.machine()
50 # Normalize names.
51 if machine == 'Power Macintosh':
52 return 'ppc'
53 return machine
54
55 def getHostSystemName(self):
56 if self.cccHostSystem:
57 return self.cccHostSystem
58
59 return platform.system().lower()
60
Daniel Dunbar9c257c32009-01-12 04:21:12 +000061 def getHostReleaseName(self):
62 if self.cccHostRelease:
63 return self.cccHostRelease
64
65 return platform.release()
66
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000067 ###
68
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000069 def run(self, argv):
Daniel Dunbara5677512009-01-05 19:53:30 +000070 # FIXME: Things to support from environment: GCC_EXEC_PREFIX,
71 # COMPILER_PATH, LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS,
72 # QA_OVERRIDE_GCC3_OPTIONS, ...?
73
74 # FIXME: -V and -b processing
75
76 # Handle some special -ccc- options used for testing which are
77 # only allowed at the beginning of the command line.
78 cccPrintOptions = False
79 cccPrintPhases = False
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000080
81 # FIXME: How to handle override of host? ccc specific options?
82 # Abuse -b?
Daniel Dunbar9c257c32009-01-12 04:21:12 +000083 self.cccHostBits = self.cccHostMachine = None
84 self.cccHostSystem = self.cccHostRelease = None
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000085 while argv and argv[0].startswith('-ccc-'):
86 opt,argv = argv[0][5:],argv[1:]
Daniel Dunbara5677512009-01-05 19:53:30 +000087
88 if opt == 'print-options':
89 cccPrintOptions = True
90 elif opt == 'print-phases':
91 cccPrintPhases = True
Daniel Dunbar9066af82009-01-09 01:00:40 +000092 elif opt == 'host-bits':
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000093 self.cccHostBits,argv = argv[0],argv[1:]
Daniel Dunbar9066af82009-01-09 01:00:40 +000094 elif opt == 'host-machine':
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000095 self.cccHostMachine,argv = argv[0],argv[1:]
Daniel Dunbar9066af82009-01-09 01:00:40 +000096 elif opt == 'host-system':
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000097 self.cccHostSystem,argv = argv[0],argv[1:]
Daniel Dunbar9c257c32009-01-12 04:21:12 +000098 elif opt == 'host-release':
99 self.cccHostRelease,argv = argv[0],argv[1:]
Daniel Dunbara5677512009-01-05 19:53:30 +0000100 else:
101 raise ValueError,"Invalid ccc option: %r" % cccPrintOptions
102
Daniel Dunbara75ea3d2009-01-09 22:21:24 +0000103 self.hostInfo = HostInfo.getHostInfo(self)
Daniel Dunbar43124722009-01-10 02:07:54 +0000104 self.toolChain = self.hostInfo.getToolChain()
Daniel Dunbar9066af82009-01-09 01:00:40 +0000105
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000106 args = self.parser.parseArgs(argv)
Daniel Dunbara5677512009-01-05 19:53:30 +0000107
108 # FIXME: Ho hum I have just realized -Xarch_ is broken. We really
109 # need to reparse the Arguments after they have been expanded by
110 # -Xarch. How is this going to work?
111 #
112 # Scratch that, we aren't going to do that; it really disrupts the
113 # organization, doesn't consistently work with gcc-dd, and is
114 # confusing. Instead we are going to enforce that -Xarch_ is only
115 # used with options which do not alter the driver behavior. Let's
116 # hope this is ok, because the current architecture is a little
117 # tied to it.
118
119 if cccPrintOptions:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000120 self.printOptions(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000121 sys.exit(0)
122
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000123 self.handleImmediateOptions(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000124
Daniel Dunbar9066af82009-01-09 01:00:40 +0000125 if self.hostInfo.useDriverDriver():
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000126 phases = self.buildPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000127 else:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000128 phases = self.buildNormalPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000129
130 if cccPrintPhases:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000131 self.printPhases(phases, args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000132 sys.exit(0)
Daniel Dunbar9066af82009-01-09 01:00:40 +0000133
Daniel Dunbara5677512009-01-05 19:53:30 +0000134 if 0:
135 print Util.pprint(phases)
136
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000137 jobs = self.bindPhases(phases, args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000138
139 # FIXME: We should provide some basic sanity checking of the
140 # pipeline as a "verification" sort of stage. For example, the
141 # pipeline should never end up writing to an output file in two
142 # places (I think). The pipeline should also never end up writing
143 # to an output file that is an input.
144 #
145 # This is intended to just be a "verify" step, not a functionality
146 # step. It should catch things like the driver driver not
147 # preventing -save-temps, but it shouldn't change behavior (so we
148 # can turn it off in Release-Asserts builds).
149
150 # Print in -### syntax.
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000151 hasHashHashHash = args.getLastArg(self.parser.hashHashHashOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000152 if hasHashHashHash:
153 self.claim(hasHashHashHash)
154 for j in jobs.iterjobs():
155 if isinstance(j, Jobs.Command):
Daniel Dunbare99f9262009-01-11 22:03:55 +0000156 print >>sys.stderr, '"%s"' % '" "'.join(j.getArgv())
Daniel Dunbara5677512009-01-05 19:53:30 +0000157 elif isinstance(j, Jobs.PipedJob):
158 for c in j.commands:
Daniel Dunbare99f9262009-01-11 22:03:55 +0000159 print >>sys.stderr, '"%s" %c' % ('" "'.join(c.getArgv()),
160 "| "[c is j.commands[-1]])
Daniel Dunbara5677512009-01-05 19:53:30 +0000161 elif not isinstance(j, JobList):
162 raise ValueError,'Encountered unknown job.'
163 sys.exit(0)
164
165 for j in jobs.iterjobs():
166 if isinstance(j, Jobs.Command):
Daniel Dunbardb439902009-01-07 18:40:45 +0000167 res = os.spawnvp(os.P_WAIT, j.executable, j.getArgv())
Daniel Dunbara5677512009-01-05 19:53:30 +0000168 if res:
169 sys.exit(res)
170 elif isinstance(j, Jobs.PipedJob):
171 raise NotImplementedError,"Piped jobs aren't implemented yet."
172 else:
173 raise ValueError,'Encountered unknown job.'
174
175 def claim(self, option):
176 # FIXME: Move to OptionList once introduced and implement.
177 pass
178
179 def warning(self, message):
180 print >>sys.stderr,'%s: %s' % (sys.argv[0], message)
181
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000182 def printOptions(self, args):
183 for i,arg in enumerate(args):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000184 if isinstance(arg, Arguments.MultipleValuesArg):
185 values = list(args.getValues(arg))
186 elif isinstance(arg, Arguments.ValueArg):
187 values = [args.getValue(arg)]
188 elif isinstance(arg, Arguments.JoinedAndSeparateValuesArg):
189 values = [args.getJoinedValue(arg), args.getSeparateValue(arg)]
Daniel Dunbara5677512009-01-05 19:53:30 +0000190 else:
191 values = []
Daniel Dunbar5039f212009-01-06 02:30:10 +0000192 print 'Option %d - Name: "%s", Values: {%s}' % (i, arg.opt.name,
Daniel Dunbara5677512009-01-05 19:53:30 +0000193 ', '.join(['"%s"' % v
194 for v in values]))
195
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000196 def printPhases(self, phases, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000197 def printPhase(p, f, steps, arch=None):
198 if p in steps:
199 return steps[p]
200 elif isinstance(p, Phases.BindArchAction):
201 for kid in p.inputs:
202 printPhase(kid, f, steps, p.arch)
203 steps[p] = len(steps)
204 return
205
206 if isinstance(p, Phases.InputAction):
207 phaseName = 'input'
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000208 inputStr = '"%s"' % args.getValue(p.filename)
Daniel Dunbara5677512009-01-05 19:53:30 +0000209 else:
210 phaseName = p.phase.name
211 inputs = [printPhase(i, f, steps, arch)
212 for i in p.inputs]
213 inputStr = '{%s}' % ', '.join(map(str, inputs))
214 if arch is not None:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000215 phaseName += '-' + args.getValue(arch)
Daniel Dunbara5677512009-01-05 19:53:30 +0000216 steps[p] = index = len(steps)
217 print "%d: %s, %s, %s" % (index,phaseName,inputStr,p.type.name)
218 return index
219 steps = {}
220 for phase in phases:
221 printPhase(phase, sys.stdout, steps)
222
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000223 def handleImmediateOptions(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000224 # FIXME: Some driver Arguments are consumed right off the bat,
225 # like -dumpversion. Currently the gcc-dd handles these
226 # poorly, so we should be ok handling them upfront instead of
227 # after driver-driver level dispatching.
228 #
229 # FIXME: The actual order of these options in gcc is all over the
230 # place. The -dump ones seem to be first and in specification
231 # order, but there are other levels of precedence. For example,
232 # -print-search-dirs is evaluated before -print-prog-name=,
233 # regardless of order (and the last instance of -print-prog-name=
234 # wins verse itself).
235 #
236 # FIXME: Do we want to report "argument unused" type errors in the
237 # presence of things like -dumpmachine and -print-search-dirs?
238 # Probably not.
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000239 arg = args.getLastArg(self.parser.dumpmachineOption)
240 if arg:
241 print 'FIXME: %s' % arg.opt.name
242 sys.exit(1)
243
244 arg = args.getLastArg(self.parser.dumpspecsOption)
245 if arg:
246 print 'FIXME: %s' % arg.opt.name
247 sys.exit(1)
248
249 arg = args.getLastArg(self.parser.dumpversionOption)
250 if arg:
251 print 'FIXME: %s' % arg.opt.name
252 sys.exit(1)
253
254 arg = args.getLastArg(self.parser.printFileNameOption)
255 if arg:
256 print 'FIXME: %s' % arg.opt.name
257 sys.exit(1)
258
259 arg = args.getLastArg(self.parser.printMultiDirectoryOption)
260 if arg:
261 print 'FIXME: %s' % arg.opt.name
262 sys.exit(1)
263
264 arg = args.getLastArg(self.parser.printMultiLibOption)
265 if arg:
266 print 'FIXME: %s' % arg.opt.name
267 sys.exit(1)
268
269 arg = args.getLastArg(self.parser.printProgNameOption)
270 if arg:
271 print 'FIXME: %s' % arg.opt.name
272 sys.exit(1)
273
274 arg = args.getLastArg(self.parser.printLibgccFilenameOption)
275 if arg:
276 print 'FIXME: %s' % arg.opt.name
277 sys.exit(1)
278
279 arg = args.getLastArg(self.parser.printSearchDirsOption)
280 if arg:
281 print 'FIXME: %s' % arg.opt.name
282 sys.exit(1)
Daniel Dunbara5677512009-01-05 19:53:30 +0000283
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000284 def buildNormalPipeline(self, args):
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000285 hasCombine = args.getLastArg(self.parser.combineOption)
286 hasSyntaxOnly = args.getLastArg(self.parser.syntaxOnlyOption)
287 hasDashC = args.getLastArg(self.parser.cOption)
288 hasDashE = args.getLastArg(self.parser.EOption)
289 hasDashS = args.getLastArg(self.parser.SOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000290
291 inputType = None
292 inputTypeOpt = None
293 inputs = []
294 for a in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000295 if a.opt is self.parser.inputOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000296 if inputType is None:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000297 base,ext = os.path.splitext(args.getValue(a))
Daniel Dunbara5677512009-01-05 19:53:30 +0000298 if ext and ext in Types.kTypeSuffixMap:
299 klass = Types.kTypeSuffixMap[ext]
300 else:
301 # FIXME: Its not clear why we shouldn't just
302 # revert to unknown. I think this is more likely a
303 # bug / unintended behavior in gcc. Not very
304 # important though.
305 klass = Types.ObjectType
306 else:
307 assert inputTypeOpt is not None
308 self.claim(inputTypeOpt)
309 klass = inputType
310 inputs.append((klass, a))
Daniel Dunbar2ec55bc2009-01-12 03:33:58 +0000311 elif a.opt.isLinkerInput:
312 # Treat as a linker input.
Daniel Dunbar5039f212009-01-06 02:30:10 +0000313 #
314 # FIXME: This might not be good enough. We may
315 # need to introduce another type for this case, so
316 # that other code which needs to know the inputs
317 # handles this properly. Best not to try and lipo
318 # this, for example.
Daniel Dunbare99f9262009-01-11 22:03:55 +0000319 #
320 # FIXME: Actually, this is just flat out broken, the
321 # tools expect inputs to be accessible by .getValue
322 # but that of course only yields the argument.
Daniel Dunbar5039f212009-01-06 02:30:10 +0000323 inputs.append((Types.ObjectType, a))
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000324 elif a.opt is self.parser.xOption:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000325 self.claim(a)
326 inputTypeOpt = a
327 value = args.getValue(a)
328 if value in Types.kTypeSpecifierMap:
329 inputType = Types.kTypeSpecifierMap[value]
330 else:
331 # FIXME: How are we going to handle diagnostics.
332 self.warning("language %s not recognized" % value)
Daniel Dunbara5677512009-01-05 19:53:30 +0000333
Daniel Dunbar5039f212009-01-06 02:30:10 +0000334 # FIXME: Its not clear why we shouldn't just
335 # revert to unknown. I think this is more likely a
336 # bug / unintended behavior in gcc. Not very
337 # important though.
338 inputType = ObjectType
Daniel Dunbara5677512009-01-05 19:53:30 +0000339
340 # We claim things here so that options for which we silently allow
341 # override only ever claim the used option.
342 if hasCombine:
343 self.claim(hasCombine)
344
345 finalPhase = Phases.Phase.eOrderPostAssemble
346 finalPhaseOpt = None
347
348 # Determine what compilation mode we are in.
349 if hasDashE:
350 finalPhase = Phases.Phase.eOrderPreprocess
351 finalPhaseOpt = hasDashE
352 elif hasSyntaxOnly:
353 finalPhase = Phases.Phase.eOrderCompile
354 finalPhaseOpt = hasSyntaxOnly
355 elif hasDashS:
356 finalPhase = Phases.Phase.eOrderCompile
357 finalPhaseOpt = hasDashS
358 elif hasDashC:
359 finalPhase = Phases.Phase.eOrderAssemble
360 finalPhaseOpt = hasDashC
361
362 if finalPhaseOpt:
363 self.claim(finalPhaseOpt)
364
365 # FIXME: Support -combine.
366 if hasCombine:
367 raise NotImplementedError,"-combine is not yet supported."
368
369 actions = []
370 linkerInputs = []
371 # FIXME: This is gross.
372 linkPhase = Phases.LinkPhase()
373 for klass,input in inputs:
374 # Figure out what step to start at.
375
376 # FIXME: This should be part of the input class probably?
377 # Altough it doesn't quite fit there either, things like
378 # asm-with-preprocess don't easily fit into a linear scheme.
379
380 # FIXME: I think we are going to end up wanting to just build
381 # a simple FSA which we run the inputs down.
382 sequence = []
383 if klass.preprocess:
384 sequence.append(Phases.PreprocessPhase())
385 if klass == Types.ObjectType:
386 sequence.append(linkPhase)
387 elif klass.onlyAssemble:
388 sequence.extend([Phases.AssemblePhase(),
389 linkPhase])
390 elif klass.onlyPrecompile:
391 sequence.append(Phases.PrecompilePhase())
392 else:
393 sequence.extend([Phases.CompilePhase(),
394 Phases.AssemblePhase(),
395 linkPhase])
396
397 if sequence[0].order > finalPhase:
398 assert finalPhaseOpt and finalPhaseOpt.opt
399 # FIXME: Explain what type of input file is. Or just match
400 # gcc warning.
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000401 self.warning("%s: %s input file unused when %s is present" % (args.getValue(input),
Daniel Dunbara5677512009-01-05 19:53:30 +0000402 sequence[0].name,
403 finalPhaseOpt.opt.name))
404 else:
405 # Build the pipeline for this file.
406
407 current = Phases.InputAction(input, klass)
408 for transition in sequence:
409 # If the current action produces no output, or we are
410 # past what the user requested, we are done.
411 if (current.type is Types.NothingType or
412 transition.order > finalPhase):
413 break
414 else:
415 if isinstance(transition, Phases.PreprocessPhase):
416 assert isinstance(klass.preprocess, Types.InputType)
417 current = Phases.JobAction(transition,
418 [current],
419 klass.preprocess)
420 elif isinstance(transition, Phases.PrecompilePhase):
421 current = Phases.JobAction(transition,
422 [current],
423 Types.PCHType)
424 elif isinstance(transition, Phases.CompilePhase):
425 if hasSyntaxOnly:
426 output = Types.NothingType
427 else:
428 output = Types.AsmTypeNoPP
429 current = Phases.JobAction(transition,
430 [current],
431 output)
432 elif isinstance(transition, Phases.AssemblePhase):
433 current = Phases.JobAction(transition,
434 [current],
435 Types.ObjectType)
436 elif transition is linkPhase:
437 linkerInputs.append(current)
438 current = None
439 break
440 else:
441 raise RuntimeError,'Unrecognized transition: %s.' % transition
442 pass
443
444 if current is not None:
445 assert not isinstance(current, Phases.InputAction)
446 actions.append(current)
447
448 if linkerInputs:
449 actions.append(Phases.JobAction(linkPhase,
450 linkerInputs,
451 Types.ImageType))
452
453 return actions
454
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000455 def buildPipeline(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000456 # FIXME: We need to handle canonicalization of the specified arch.
457
458 archs = []
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000459 hasDashM = None
460 hasSaveTemps = (args.getLastArg(self.parser.saveTempsOption) or
461 args.getLastArg(self.parser.saveTempsOption2))
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000462 for arg in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000463 if arg.opt is self.parser.archOption:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000464 archs.append(arg)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000465 elif arg.opt.name.startswith('-M'):
466 hasDashM = arg
Daniel Dunbara5677512009-01-05 19:53:30 +0000467
468 if not archs:
Daniel Dunbar9066af82009-01-09 01:00:40 +0000469 archs.append(args.makeSeparateArg(self.hostInfo.getArchName(),
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000470 self.parser.archOption))
Daniel Dunbara5677512009-01-05 19:53:30 +0000471
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000472 actions = self.buildNormalPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000473
474 # FIXME: Use custom exception for this.
475 #
476 # FIXME: We killed off some others but these aren't yet detected in
477 # a functional manner. If we added information to jobs about which
478 # "auxiliary" files they wrote then we could detect the conflict
479 # these cause downstream.
480 if len(archs) > 1:
481 if hasDashM:
482 raise ValueError,"Cannot use -M options with multiple arch flags."
483 elif hasSaveTemps:
484 raise ValueError,"Cannot use -save-temps with multiple arch flags."
485
486 # Execute once per arch.
487 finalActions = []
488 for p in actions:
489 # Make sure we can lipo this kind of output. If not (and it
490 # is an actual output) then we disallow, since we can't
491 # create an output file with the right name without
492 # overwriting it. We could remove this oddity by just
493 # changing the output names to include the arch, which would
494 # also fix -save-temps. Compatibility wins for now.
495 #
496 # FIXME: Is this error substantially less useful than
497 # gcc-dd's? The main problem is that "Cannot use compiler
498 # output with multiple arch flags" won't make sense to most
499 # developers.
500 if (len(archs) > 1 and
501 p.type not in (Types.NothingType,Types.ObjectType,Types.ImageType)):
502 raise ValueError,'Cannot use %s output with multiple arch flags.' % p.type.name
503
504 inputs = []
505 for arch in archs:
506 inputs.append(Phases.BindArchAction(p, arch))
507
508 # Lipo if necessary. We do it this way because we need to set
509 # the arch flag so that -Xarch_ gets rewritten.
510 if len(inputs) == 1 or p.type == Types.NothingType:
511 finalActions.extend(inputs)
512 else:
513 finalActions.append(Phases.JobAction(Phases.LipoPhase(),
514 inputs,
515 p.type))
516
517 # FIXME: We need to add -Wl,arch_multiple and -Wl,final_output in
518 # certain cases. This may be icky because we need to figure out the
519 # mode first. Current plan is to hack on the pipeline once it is built
520 # and we know what is being spit out. This avoids having to handling
521 # things like -c and -combine in multiple places.
522 #
523 # The annoying one of these is -Wl,final_output because it involves
524 # communication across different phases.
525 #
526 # Hopefully we can do this purely as part of the binding, but
527 # leaving comment here for now until it is clear this works.
528
529 return finalActions
530
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000531 def bindPhases(self, phases, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000532 jobs = Jobs.JobList()
533
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000534 finalOutput = args.getLastArg(self.parser.oOption)
535 hasSaveTemps = (args.getLastArg(self.parser.saveTempsOption) or
536 args.getLastArg(self.parser.saveTempsOption2))
537 hasNoIntegratedCPP = args.getLastArg(self.parser.noIntegratedCPPOption)
538 hasPipe = args.getLastArg(self.parser.pipeOption)
Daniel Dunbar2ec55bc2009-01-12 03:33:58 +0000539
540 # FIXME: forward will die, this isn't really how things are
541 # done, instead everything comes from the arglist. For this we
542 # need a DerivedArgList for handling -Xarch, and some way to
543 # still figure out what to forward to the generic gcc tool.
Daniel Dunbara5677512009-01-05 19:53:30 +0000544 forward = []
545 for a in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000546 if a.opt is self.parser.inputOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000547 pass
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000548
549 # FIXME: Needs to be part of option.
Daniel Dunbar2ec55bc2009-01-12 03:33:58 +0000550 elif (a.opt.name in ('-E', '-S', '-c',
551 '-arch', '-fsyntax-only', '-combine', '-x',
552 '-###') or
553 a.opt.isLinkerInput):
Daniel Dunbar5039f212009-01-06 02:30:10 +0000554 pass
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000555
Daniel Dunbara5677512009-01-05 19:53:30 +0000556 else:
557 forward.append(a)
558
559 # We claim things here so that options for which we silently allow
560 # override only ever claim the used option.
561 if hasPipe:
562 self.claim(hasPipe)
563 # FIXME: Hack, override -pipe till we support it.
564 hasPipe = None
565 # Claim these here. Its not completely accurate but any warnings
566 # about these being unused are likely to be noise anyway.
567 if hasSaveTemps:
568 self.claim(hasSaveTemps)
569 if hasNoIntegratedCPP:
570 self.claim(hasNoIntegratedCPP)
571
Daniel Dunbara5677512009-01-05 19:53:30 +0000572 class InputInfo:
573 def __init__(self, source, type, baseInput):
574 self.source = source
575 self.type = type
576 self.baseInput = baseInput
577
578 def __repr__(self):
579 return '%s(%r, %r, %r)' % (self.__class__.__name__,
580 self.source, self.type, self.baseInput)
581
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000582 def createJobs(tc, phase, forwardArgs,
Daniel Dunbara5677512009-01-05 19:53:30 +0000583 canAcceptPipe=False, atTopLevel=False, arch=None):
584 if isinstance(phase, Phases.InputAction):
585 return InputInfo(phase.filename, phase.type, phase.filename)
586 elif isinstance(phase, Phases.BindArchAction):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000587 archName = args.getValue(phase.arch)
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000588 tc = self.hostInfo.getToolChainForArch(archName)
Daniel Dunbara5677512009-01-05 19:53:30 +0000589 filteredArgs = []
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000590 for arg in forwardArgs:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000591 if arg.opt is self.parser.archOption:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000592 if arg is phase.arch:
593 filteredArgs.append(arg)
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000594 elif arg.opt is self.parser.XarchOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000595 # FIXME: gcc-dd has another conditional for passing
596 # through, when the arch conditional array has an empty
597 # string. Why?
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000598 if args.getJoinedValue(arg) == archName:
Daniel Dunbara5677512009-01-05 19:53:30 +0000599 # FIXME: This is wrong, we don't want a
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000600 # unknown arg we want an actual parsed
601 # version of this arg.
602 filteredArgs.append(args.makeUnknownArg(args.getSeparateValue(arg)))
Daniel Dunbara5677512009-01-05 19:53:30 +0000603 else:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000604 filteredArgs.append(arg)
Daniel Dunbara5677512009-01-05 19:53:30 +0000605
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000606 return createJobs(tc, phase.inputs[0], filteredArgs,
Daniel Dunbara5677512009-01-05 19:53:30 +0000607 canAcceptPipe, atTopLevel, phase.arch)
608
609 assert isinstance(phase, Phases.JobAction)
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000610 tool = tc.selectTool(phase)
Daniel Dunbara5677512009-01-05 19:53:30 +0000611
612 # See if we should use an integrated CPP. We only use an
613 # integrated cpp when we have exactly one input, since this is
614 # the only use case we care about.
615 useIntegratedCPP = False
616 inputList = phase.inputs
617 if (not hasNoIntegratedCPP and
618 not hasSaveTemps and
619 tool.hasIntegratedCPP()):
620 if (len(phase.inputs) == 1 and
621 isinstance(phase.inputs[0].phase, Phases.PreprocessPhase)):
622 useIntegratedCPP = True
623 inputList = phase.inputs[0].inputs
624
625 # Only try to use pipes when exactly one input.
626 canAcceptPipe = len(inputList) == 1 and tool.acceptsPipedInput()
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000627 inputs = [createJobs(tc, p, forwardArgs, canAcceptPipe, False, arch)
628 for p in inputList]
Daniel Dunbara5677512009-01-05 19:53:30 +0000629
630 # Determine if we should output to a pipe.
631 canOutputToPipe = canAcceptPipe and tool.canPipeOutput()
632 outputToPipe = False
633 if canOutputToPipe:
634 # Some things default to writing to a pipe if the final
635 # phase and there was no user override.
636 #
637 # FIXME: What is the best way to handle this?
638 if (atTopLevel and
639 isinstance(phase, Phases.PreprocessPhase) and
640 not finalOutput):
641 outputToPipe = True
642 elif hasPipe:
643 outputToPipe = True
644
645 # Figure out where to put the job (pipes).
646 jobList = jobs
647 if canAcceptPipe and isinstance(inputs[0].source, Jobs.PipedJob):
648 jobList = inputs[0].source
649
650 # Figure out where to put the output.
651 baseInput = inputs[0].baseInput
652 if phase.type == Types.NothingType:
653 output = None
654 elif outputToPipe:
655 if isinstance(jobList, Jobs.PipedJob):
656 output = jobList
657 else:
658 jobList = output = Jobs.PipedJob([])
659 jobs.addJob(output)
660 else:
661 # Figure out what the derived output location would be.
662 #
663 # FIXME: gcc has some special case in here so that it doesn't
664 # create output files if they would conflict with an input.
Daniel Dunbara5677512009-01-05 19:53:30 +0000665 if phase.type is Types.ImageType:
666 namedOutput = "a.out"
667 else:
Daniel Dunbar2ec55bc2009-01-12 03:33:58 +0000668 inputName = args.getValue(baseInput)
Daniel Dunbara5677512009-01-05 19:53:30 +0000669 base,_ = os.path.splitext(inputName)
670 assert phase.type.tempSuffix is not None
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000671 namedOutput = base + '.' + phase.type.tempSuffix
Daniel Dunbara5677512009-01-05 19:53:30 +0000672
673 # Output to user requested destination?
674 if atTopLevel and finalOutput:
675 output = finalOutput
676 # Contruct a named destination?
677 elif atTopLevel or hasSaveTemps:
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000678 output = args.makeSeparateArg(namedOutput,
679 self.parser.oOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000680 else:
681 # Output to temp file...
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000682 fd,filename = tempfile.mkstemp(suffix='.'+phase.type.tempSuffix)
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000683 output = args.makeSeparateArg(filename,
684 self.parser.oOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000685
Daniel Dunbardb439902009-01-07 18:40:45 +0000686 tool.constructJob(phase, arch, jobList, inputs, output, phase.type,
687 forwardArgs, args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000688
689 return InputInfo(output, phase.type, baseInput)
690
691 # It is an error to provide a -o option if we are making multiple
692 # output files.
693 if finalOutput and len([a for a in phases if a.type is not Types.NothingType]) > 1:
694 # FIXME: Custom exception.
695 raise ValueError,"Cannot specify -o when generating multiple files."
696
697 for phase in phases:
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000698 createJobs(self.toolChain, phase, forward,
699 canAcceptPipe=True, atTopLevel=True)
Daniel Dunbara5677512009-01-05 19:53:30 +0000700
701 return jobs