blob: 5d73a985aad0b1b9c505e451d15b0d2279710d01 [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 Dunbar33a5d612009-01-14 01:03:36 +000032 self.cccHostBits = self.cccHostMachine = None
33 self.cccHostSystem = self.cccHostRelease = None
34 self.cccCXX = False
35 self.cccClang = False
36 self.cccFallback = False
Daniel Dunbara5677512009-01-05 19:53:30 +000037
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000038 # Host queries which can be forcibly over-riden by the user for
39 # testing purposes.
40 #
41 # FIXME: We should make sure these are drawn from a fixed set so
42 # that nothing downstream ever plays a guessing game.
43
44 def getHostBits(self):
45 if self.cccHostBits:
46 return self.cccHostBits
47
48 return platform.architecture()[0].replace('bit','')
49
50 def getHostMachine(self):
51 if self.cccHostMachine:
52 return self.cccHostMachine
53
54 machine = platform.machine()
55 # Normalize names.
56 if machine == 'Power Macintosh':
57 return 'ppc'
58 return machine
59
60 def getHostSystemName(self):
61 if self.cccHostSystem:
62 return self.cccHostSystem
63
64 return platform.system().lower()
65
Daniel Dunbar9c257c32009-01-12 04:21:12 +000066 def getHostReleaseName(self):
67 if self.cccHostRelease:
68 return self.cccHostRelease
69
70 return platform.release()
71
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000072 ###
73
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000074 def run(self, argv):
Daniel Dunbara5677512009-01-05 19:53:30 +000075 # FIXME: Things to support from environment: GCC_EXEC_PREFIX,
76 # COMPILER_PATH, LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS,
77 # QA_OVERRIDE_GCC3_OPTIONS, ...?
78
79 # FIXME: -V and -b processing
80
81 # Handle some special -ccc- options used for testing which are
82 # only allowed at the beginning of the command line.
83 cccPrintOptions = False
84 cccPrintPhases = False
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000085
86 # FIXME: How to handle override of host? ccc specific options?
87 # Abuse -b?
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000088 while argv and argv[0].startswith('-ccc-'):
89 opt,argv = argv[0][5:],argv[1:]
Daniel Dunbara5677512009-01-05 19:53:30 +000090
91 if opt == 'print-options':
92 cccPrintOptions = True
93 elif opt == 'print-phases':
94 cccPrintPhases = True
Daniel Dunbar33a5d612009-01-14 01:03:36 +000095 elif opt == 'cxx':
96 self.cccCXX = True
97 elif opt == 'clang':
98 self.cccClang = True
99 elif opt == 'fallback':
100 self.cccFallback = True
Daniel Dunbar9066af82009-01-09 01:00:40 +0000101 elif opt == 'host-bits':
Daniel Dunbara75ea3d2009-01-09 22:21:24 +0000102 self.cccHostBits,argv = argv[0],argv[1:]
Daniel Dunbar9066af82009-01-09 01:00:40 +0000103 elif opt == 'host-machine':
Daniel Dunbara75ea3d2009-01-09 22:21:24 +0000104 self.cccHostMachine,argv = argv[0],argv[1:]
Daniel Dunbar9066af82009-01-09 01:00:40 +0000105 elif opt == 'host-system':
Daniel Dunbara75ea3d2009-01-09 22:21:24 +0000106 self.cccHostSystem,argv = argv[0],argv[1:]
Daniel Dunbar9c257c32009-01-12 04:21:12 +0000107 elif opt == 'host-release':
108 self.cccHostRelease,argv = argv[0],argv[1:]
Daniel Dunbara5677512009-01-05 19:53:30 +0000109 else:
110 raise ValueError,"Invalid ccc option: %r" % cccPrintOptions
111
Daniel Dunbara75ea3d2009-01-09 22:21:24 +0000112 self.hostInfo = HostInfo.getHostInfo(self)
Daniel Dunbar43124722009-01-10 02:07:54 +0000113 self.toolChain = self.hostInfo.getToolChain()
Daniel Dunbar9066af82009-01-09 01:00:40 +0000114
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000115 args = self.parser.parseArgs(argv)
Daniel Dunbara5677512009-01-05 19:53:30 +0000116
117 # FIXME: Ho hum I have just realized -Xarch_ is broken. We really
118 # need to reparse the Arguments after they have been expanded by
119 # -Xarch. How is this going to work?
120 #
121 # Scratch that, we aren't going to do that; it really disrupts the
122 # organization, doesn't consistently work with gcc-dd, and is
123 # confusing. Instead we are going to enforce that -Xarch_ is only
124 # used with options which do not alter the driver behavior. Let's
125 # hope this is ok, because the current architecture is a little
126 # tied to it.
127
128 if cccPrintOptions:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000129 self.printOptions(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000130 sys.exit(0)
131
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000132 self.handleImmediateOptions(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000133
Daniel Dunbar9066af82009-01-09 01:00:40 +0000134 if self.hostInfo.useDriverDriver():
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000135 phases = self.buildPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000136 else:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000137 phases = self.buildNormalPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000138
139 if cccPrintPhases:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000140 self.printPhases(phases, args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000141 sys.exit(0)
Daniel Dunbar9066af82009-01-09 01:00:40 +0000142
Daniel Dunbara5677512009-01-05 19:53:30 +0000143 if 0:
144 print Util.pprint(phases)
145
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000146 jobs = self.bindPhases(phases, args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000147
148 # FIXME: We should provide some basic sanity checking of the
149 # pipeline as a "verification" sort of stage. For example, the
150 # pipeline should never end up writing to an output file in two
151 # places (I think). The pipeline should also never end up writing
152 # to an output file that is an input.
153 #
154 # This is intended to just be a "verify" step, not a functionality
155 # step. It should catch things like the driver driver not
156 # preventing -save-temps, but it shouldn't change behavior (so we
157 # can turn it off in Release-Asserts builds).
158
159 # Print in -### syntax.
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000160 hasHashHashHash = args.getLastArg(self.parser.hashHashHashOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000161 if hasHashHashHash:
162 self.claim(hasHashHashHash)
163 for j in jobs.iterjobs():
164 if isinstance(j, Jobs.Command):
Daniel Dunbar3ecc20f2009-01-12 19:36:35 +0000165 print >>sys.stderr, ' "%s"' % '" "'.join(j.getArgv())
Daniel Dunbara5677512009-01-05 19:53:30 +0000166 elif isinstance(j, Jobs.PipedJob):
167 for c in j.commands:
Daniel Dunbar3ecc20f2009-01-12 19:36:35 +0000168 print >>sys.stderr, ' "%s" %c' % ('" "'.join(c.getArgv()),
169 "| "[c is j.commands[-1]])
Daniel Dunbara5677512009-01-05 19:53:30 +0000170 elif not isinstance(j, JobList):
171 raise ValueError,'Encountered unknown job.'
172 sys.exit(0)
173
174 for j in jobs.iterjobs():
175 if isinstance(j, Jobs.Command):
Daniel Dunbardb439902009-01-07 18:40:45 +0000176 res = os.spawnvp(os.P_WAIT, j.executable, j.getArgv())
Daniel Dunbara5677512009-01-05 19:53:30 +0000177 if res:
178 sys.exit(res)
179 elif isinstance(j, Jobs.PipedJob):
180 raise NotImplementedError,"Piped jobs aren't implemented yet."
181 else:
182 raise ValueError,'Encountered unknown job.'
183
184 def claim(self, option):
185 # FIXME: Move to OptionList once introduced and implement.
186 pass
187
188 def warning(self, message):
189 print >>sys.stderr,'%s: %s' % (sys.argv[0], message)
190
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000191 def printOptions(self, args):
192 for i,arg in enumerate(args):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000193 if isinstance(arg, Arguments.MultipleValuesArg):
194 values = list(args.getValues(arg))
195 elif isinstance(arg, Arguments.ValueArg):
196 values = [args.getValue(arg)]
197 elif isinstance(arg, Arguments.JoinedAndSeparateValuesArg):
198 values = [args.getJoinedValue(arg), args.getSeparateValue(arg)]
Daniel Dunbara5677512009-01-05 19:53:30 +0000199 else:
200 values = []
Daniel Dunbar5039f212009-01-06 02:30:10 +0000201 print 'Option %d - Name: "%s", Values: {%s}' % (i, arg.opt.name,
Daniel Dunbara5677512009-01-05 19:53:30 +0000202 ', '.join(['"%s"' % v
203 for v in values]))
204
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000205 def printPhases(self, phases, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000206 def printPhase(p, f, steps, arch=None):
207 if p in steps:
208 return steps[p]
209 elif isinstance(p, Phases.BindArchAction):
210 for kid in p.inputs:
211 printPhase(kid, f, steps, p.arch)
212 steps[p] = len(steps)
213 return
214
215 if isinstance(p, Phases.InputAction):
216 phaseName = 'input'
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000217 inputStr = '"%s"' % args.getValue(p.filename)
Daniel Dunbara5677512009-01-05 19:53:30 +0000218 else:
219 phaseName = p.phase.name
220 inputs = [printPhase(i, f, steps, arch)
221 for i in p.inputs]
222 inputStr = '{%s}' % ', '.join(map(str, inputs))
223 if arch is not None:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000224 phaseName += '-' + args.getValue(arch)
Daniel Dunbara5677512009-01-05 19:53:30 +0000225 steps[p] = index = len(steps)
226 print "%d: %s, %s, %s" % (index,phaseName,inputStr,p.type.name)
227 return index
228 steps = {}
229 for phase in phases:
230 printPhase(phase, sys.stdout, steps)
231
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000232 def handleImmediateOptions(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000233 # FIXME: Some driver Arguments are consumed right off the bat,
234 # like -dumpversion. Currently the gcc-dd handles these
235 # poorly, so we should be ok handling them upfront instead of
236 # after driver-driver level dispatching.
237 #
238 # FIXME: The actual order of these options in gcc is all over the
239 # place. The -dump ones seem to be first and in specification
240 # order, but there are other levels of precedence. For example,
241 # -print-search-dirs is evaluated before -print-prog-name=,
242 # regardless of order (and the last instance of -print-prog-name=
243 # wins verse itself).
244 #
245 # FIXME: Do we want to report "argument unused" type errors in the
246 # presence of things like -dumpmachine and -print-search-dirs?
247 # Probably not.
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000248 arg = args.getLastArg(self.parser.dumpmachineOption)
249 if arg:
250 print 'FIXME: %s' % arg.opt.name
251 sys.exit(1)
252
253 arg = args.getLastArg(self.parser.dumpspecsOption)
254 if arg:
255 print 'FIXME: %s' % arg.opt.name
256 sys.exit(1)
257
258 arg = args.getLastArg(self.parser.dumpversionOption)
259 if arg:
260 print 'FIXME: %s' % arg.opt.name
261 sys.exit(1)
262
263 arg = args.getLastArg(self.parser.printFileNameOption)
264 if arg:
265 print 'FIXME: %s' % arg.opt.name
266 sys.exit(1)
267
268 arg = args.getLastArg(self.parser.printMultiDirectoryOption)
269 if arg:
270 print 'FIXME: %s' % arg.opt.name
271 sys.exit(1)
272
273 arg = args.getLastArg(self.parser.printMultiLibOption)
274 if arg:
275 print 'FIXME: %s' % arg.opt.name
276 sys.exit(1)
277
278 arg = args.getLastArg(self.parser.printProgNameOption)
279 if arg:
280 print 'FIXME: %s' % arg.opt.name
281 sys.exit(1)
282
283 arg = args.getLastArg(self.parser.printLibgccFilenameOption)
284 if arg:
285 print 'FIXME: %s' % arg.opt.name
286 sys.exit(1)
287
288 arg = args.getLastArg(self.parser.printSearchDirsOption)
289 if arg:
290 print 'FIXME: %s' % arg.opt.name
291 sys.exit(1)
Daniel Dunbara5677512009-01-05 19:53:30 +0000292
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000293 def buildNormalPipeline(self, args):
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000294 hasCombine = args.getLastArg(self.parser.combineOption)
295 hasSyntaxOnly = args.getLastArg(self.parser.syntaxOnlyOption)
296 hasDashC = args.getLastArg(self.parser.cOption)
297 hasDashE = args.getLastArg(self.parser.EOption)
298 hasDashS = args.getLastArg(self.parser.SOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000299
300 inputType = None
301 inputTypeOpt = None
302 inputs = []
303 for a in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000304 if a.opt is self.parser.inputOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000305 if inputType is None:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000306 base,ext = os.path.splitext(args.getValue(a))
Daniel Dunbara5677512009-01-05 19:53:30 +0000307 if ext and ext in Types.kTypeSuffixMap:
308 klass = Types.kTypeSuffixMap[ext]
309 else:
310 # FIXME: Its not clear why we shouldn't just
311 # revert to unknown. I think this is more likely a
312 # bug / unintended behavior in gcc. Not very
313 # important though.
314 klass = Types.ObjectType
315 else:
316 assert inputTypeOpt is not None
317 self.claim(inputTypeOpt)
318 klass = inputType
319 inputs.append((klass, a))
Daniel Dunbar2ec55bc2009-01-12 03:33:58 +0000320 elif a.opt.isLinkerInput:
321 # Treat as a linker input.
Daniel Dunbar5039f212009-01-06 02:30:10 +0000322 #
323 # FIXME: This might not be good enough. We may
324 # need to introduce another type for this case, so
325 # that other code which needs to know the inputs
326 # handles this properly. Best not to try and lipo
327 # this, for example.
Daniel Dunbare99f9262009-01-11 22:03:55 +0000328 #
329 # FIXME: Actually, this is just flat out broken, the
330 # tools expect inputs to be accessible by .getValue
331 # but that of course only yields the argument.
Daniel Dunbar5039f212009-01-06 02:30:10 +0000332 inputs.append((Types.ObjectType, a))
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000333 elif a.opt is self.parser.xOption:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000334 self.claim(a)
335 inputTypeOpt = a
336 value = args.getValue(a)
337 if value in Types.kTypeSpecifierMap:
338 inputType = Types.kTypeSpecifierMap[value]
339 else:
340 # FIXME: How are we going to handle diagnostics.
341 self.warning("language %s not recognized" % value)
Daniel Dunbara5677512009-01-05 19:53:30 +0000342
Daniel Dunbar5039f212009-01-06 02:30:10 +0000343 # FIXME: Its not clear why we shouldn't just
344 # revert to unknown. I think this is more likely a
345 # bug / unintended behavior in gcc. Not very
346 # important though.
Daniel Dunbar25d4a8f2009-01-13 21:07:43 +0000347 inputType = Types.ObjectType
Daniel Dunbara5677512009-01-05 19:53:30 +0000348
349 # We claim things here so that options for which we silently allow
350 # override only ever claim the used option.
351 if hasCombine:
352 self.claim(hasCombine)
353
354 finalPhase = Phases.Phase.eOrderPostAssemble
355 finalPhaseOpt = None
356
357 # Determine what compilation mode we are in.
358 if hasDashE:
359 finalPhase = Phases.Phase.eOrderPreprocess
360 finalPhaseOpt = hasDashE
361 elif hasSyntaxOnly:
362 finalPhase = Phases.Phase.eOrderCompile
363 finalPhaseOpt = hasSyntaxOnly
364 elif hasDashS:
365 finalPhase = Phases.Phase.eOrderCompile
366 finalPhaseOpt = hasDashS
367 elif hasDashC:
368 finalPhase = Phases.Phase.eOrderAssemble
369 finalPhaseOpt = hasDashC
370
371 if finalPhaseOpt:
372 self.claim(finalPhaseOpt)
373
374 # FIXME: Support -combine.
375 if hasCombine:
376 raise NotImplementedError,"-combine is not yet supported."
377
378 actions = []
379 linkerInputs = []
380 # FIXME: This is gross.
381 linkPhase = Phases.LinkPhase()
382 for klass,input in inputs:
383 # Figure out what step to start at.
384
385 # FIXME: This should be part of the input class probably?
386 # Altough it doesn't quite fit there either, things like
387 # asm-with-preprocess don't easily fit into a linear scheme.
388
389 # FIXME: I think we are going to end up wanting to just build
390 # a simple FSA which we run the inputs down.
391 sequence = []
392 if klass.preprocess:
393 sequence.append(Phases.PreprocessPhase())
394 if klass == Types.ObjectType:
395 sequence.append(linkPhase)
396 elif klass.onlyAssemble:
397 sequence.extend([Phases.AssemblePhase(),
398 linkPhase])
399 elif klass.onlyPrecompile:
400 sequence.append(Phases.PrecompilePhase())
401 else:
402 sequence.extend([Phases.CompilePhase(),
403 Phases.AssemblePhase(),
404 linkPhase])
405
406 if sequence[0].order > finalPhase:
407 assert finalPhaseOpt and finalPhaseOpt.opt
408 # FIXME: Explain what type of input file is. Or just match
409 # gcc warning.
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000410 self.warning("%s: %s input file unused when %s is present" % (args.getValue(input),
Daniel Dunbara5677512009-01-05 19:53:30 +0000411 sequence[0].name,
412 finalPhaseOpt.opt.name))
413 else:
414 # Build the pipeline for this file.
415
416 current = Phases.InputAction(input, klass)
417 for transition in sequence:
418 # If the current action produces no output, or we are
419 # past what the user requested, we are done.
420 if (current.type is Types.NothingType or
421 transition.order > finalPhase):
422 break
423 else:
424 if isinstance(transition, Phases.PreprocessPhase):
425 assert isinstance(klass.preprocess, Types.InputType)
426 current = Phases.JobAction(transition,
427 [current],
428 klass.preprocess)
429 elif isinstance(transition, Phases.PrecompilePhase):
430 current = Phases.JobAction(transition,
431 [current],
432 Types.PCHType)
433 elif isinstance(transition, Phases.CompilePhase):
434 if hasSyntaxOnly:
435 output = Types.NothingType
436 else:
437 output = Types.AsmTypeNoPP
438 current = Phases.JobAction(transition,
439 [current],
440 output)
441 elif isinstance(transition, Phases.AssemblePhase):
442 current = Phases.JobAction(transition,
443 [current],
444 Types.ObjectType)
445 elif transition is linkPhase:
446 linkerInputs.append(current)
447 current = None
448 break
449 else:
450 raise RuntimeError,'Unrecognized transition: %s.' % transition
451 pass
452
453 if current is not None:
454 assert not isinstance(current, Phases.InputAction)
455 actions.append(current)
456
457 if linkerInputs:
458 actions.append(Phases.JobAction(linkPhase,
459 linkerInputs,
460 Types.ImageType))
461
462 return actions
463
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000464 def buildPipeline(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000465 # FIXME: We need to handle canonicalization of the specified arch.
466
467 archs = []
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000468 hasDashM = None
469 hasSaveTemps = (args.getLastArg(self.parser.saveTempsOption) or
470 args.getLastArg(self.parser.saveTempsOption2))
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000471 for arg in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000472 if arg.opt is self.parser.archOption:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000473 archs.append(arg)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000474 elif arg.opt.name.startswith('-M'):
475 hasDashM = arg
Daniel Dunbara5677512009-01-05 19:53:30 +0000476
477 if not archs:
Daniel Dunbar1f73ecb2009-01-13 04:05:40 +0000478 archs.append(args.makeSeparateArg(self.hostInfo.getArchName(args),
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000479 self.parser.archOption))
Daniel Dunbara5677512009-01-05 19:53:30 +0000480
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000481 actions = self.buildNormalPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000482
483 # FIXME: Use custom exception for this.
484 #
485 # FIXME: We killed off some others but these aren't yet detected in
486 # a functional manner. If we added information to jobs about which
487 # "auxiliary" files they wrote then we could detect the conflict
488 # these cause downstream.
489 if len(archs) > 1:
490 if hasDashM:
491 raise ValueError,"Cannot use -M options with multiple arch flags."
492 elif hasSaveTemps:
493 raise ValueError,"Cannot use -save-temps with multiple arch flags."
494
495 # Execute once per arch.
496 finalActions = []
497 for p in actions:
498 # Make sure we can lipo this kind of output. If not (and it
499 # is an actual output) then we disallow, since we can't
500 # create an output file with the right name without
501 # overwriting it. We could remove this oddity by just
502 # changing the output names to include the arch, which would
503 # also fix -save-temps. Compatibility wins for now.
504 #
505 # FIXME: Is this error substantially less useful than
506 # gcc-dd's? The main problem is that "Cannot use compiler
507 # output with multiple arch flags" won't make sense to most
508 # developers.
509 if (len(archs) > 1 and
510 p.type not in (Types.NothingType,Types.ObjectType,Types.ImageType)):
511 raise ValueError,'Cannot use %s output with multiple arch flags.' % p.type.name
512
513 inputs = []
514 for arch in archs:
515 inputs.append(Phases.BindArchAction(p, arch))
516
517 # Lipo if necessary. We do it this way because we need to set
518 # the arch flag so that -Xarch_ gets rewritten.
519 if len(inputs) == 1 or p.type == Types.NothingType:
520 finalActions.extend(inputs)
521 else:
522 finalActions.append(Phases.JobAction(Phases.LipoPhase(),
523 inputs,
524 p.type))
525
526 # FIXME: We need to add -Wl,arch_multiple and -Wl,final_output in
527 # certain cases. This may be icky because we need to figure out the
528 # mode first. Current plan is to hack on the pipeline once it is built
529 # and we know what is being spit out. This avoids having to handling
530 # things like -c and -combine in multiple places.
531 #
532 # The annoying one of these is -Wl,final_output because it involves
533 # communication across different phases.
534 #
535 # Hopefully we can do this purely as part of the binding, but
536 # leaving comment here for now until it is clear this works.
537
538 return finalActions
539
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000540 def bindPhases(self, phases, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000541 jobs = Jobs.JobList()
542
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000543 finalOutput = args.getLastArg(self.parser.oOption)
544 hasSaveTemps = (args.getLastArg(self.parser.saveTempsOption) or
545 args.getLastArg(self.parser.saveTempsOption2))
546 hasNoIntegratedCPP = args.getLastArg(self.parser.noIntegratedCPPOption)
Daniel Dunbar6325fcf2009-01-12 09:23:15 +0000547 hasTraditionalCPP = args.getLastArg(self.parser.traditionalCPPOption)
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000548 hasPipe = args.getLastArg(self.parser.pipeOption)
Daniel Dunbar2ec55bc2009-01-12 03:33:58 +0000549
Daniel Dunbara5677512009-01-05 19:53:30 +0000550 # We claim things here so that options for which we silently allow
551 # override only ever claim the used option.
552 if hasPipe:
553 self.claim(hasPipe)
554 # FIXME: Hack, override -pipe till we support it.
555 hasPipe = None
556 # Claim these here. Its not completely accurate but any warnings
557 # about these being unused are likely to be noise anyway.
558 if hasSaveTemps:
559 self.claim(hasSaveTemps)
Daniel Dunbar6325fcf2009-01-12 09:23:15 +0000560
561 if hasTraditionalCPP:
562 self.claim(hasTraditionalCPP)
563 elif hasNoIntegratedCPP:
Daniel Dunbara5677512009-01-05 19:53:30 +0000564 self.claim(hasNoIntegratedCPP)
Daniel Dunbar6325fcf2009-01-12 09:23:15 +0000565
Daniel Dunbar76290532009-01-13 06:25:31 +0000566 # FIXME: Move to... somewhere else.
Daniel Dunbara5677512009-01-05 19:53:30 +0000567 class InputInfo:
568 def __init__(self, source, type, baseInput):
569 self.source = source
570 self.type = type
571 self.baseInput = baseInput
572
573 def __repr__(self):
574 return '%s(%r, %r, %r)' % (self.__class__.__name__,
575 self.source, self.type, self.baseInput)
Daniel Dunbar76290532009-01-13 06:25:31 +0000576
577 def isOriginalInput(self):
578 return self.source is self.baseInput
Daniel Dunbara5677512009-01-05 19:53:30 +0000579
Daniel Dunbar11672ec2009-01-13 18:51:26 +0000580 def createJobs(tc, phase,
581 canAcceptPipe=False, atTopLevel=False, arch=None,
582 tcArgs=None):
Daniel Dunbara5677512009-01-05 19:53:30 +0000583 if isinstance(phase, Phases.InputAction):
584 return InputInfo(phase.filename, phase.type, phase.filename)
585 elif isinstance(phase, Phases.BindArchAction):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000586 archName = args.getValue(phase.arch)
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000587 tc = self.hostInfo.getToolChainForArch(archName)
Daniel Dunbar11672ec2009-01-13 18:51:26 +0000588 return createJobs(tc, phase.inputs[0],
589 canAcceptPipe, atTopLevel, phase.arch,
590 tcArgs=None)
591
592 if tcArgs is None:
593 tcArgs = tc.translateArgs(args, arch)
Daniel Dunbara5677512009-01-05 19:53:30 +0000594
595 assert isinstance(phase, Phases.JobAction)
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000596 tool = tc.selectTool(phase)
Daniel Dunbara5677512009-01-05 19:53:30 +0000597
598 # See if we should use an integrated CPP. We only use an
599 # integrated cpp when we have exactly one input, since this is
600 # the only use case we care about.
601 useIntegratedCPP = False
602 inputList = phase.inputs
603 if (not hasNoIntegratedCPP and
Daniel Dunbar6325fcf2009-01-12 09:23:15 +0000604 not hasTraditionalCPP and
Daniel Dunbara5677512009-01-05 19:53:30 +0000605 not hasSaveTemps and
606 tool.hasIntegratedCPP()):
607 if (len(phase.inputs) == 1 and
608 isinstance(phase.inputs[0].phase, Phases.PreprocessPhase)):
609 useIntegratedCPP = True
610 inputList = phase.inputs[0].inputs
611
612 # Only try to use pipes when exactly one input.
613 canAcceptPipe = len(inputList) == 1 and tool.acceptsPipedInput()
Daniel Dunbar11672ec2009-01-13 18:51:26 +0000614 inputs = [createJobs(tc, p, canAcceptPipe, False, arch, tcArgs)
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000615 for p in inputList]
Daniel Dunbara5677512009-01-05 19:53:30 +0000616
617 # Determine if we should output to a pipe.
618 canOutputToPipe = canAcceptPipe and tool.canPipeOutput()
619 outputToPipe = False
620 if canOutputToPipe:
621 # Some things default to writing to a pipe if the final
622 # phase and there was no user override.
623 #
624 # FIXME: What is the best way to handle this?
625 if (atTopLevel and
626 isinstance(phase, Phases.PreprocessPhase) and
627 not finalOutput):
628 outputToPipe = True
629 elif hasPipe:
630 outputToPipe = True
631
632 # Figure out where to put the job (pipes).
633 jobList = jobs
634 if canAcceptPipe and isinstance(inputs[0].source, Jobs.PipedJob):
635 jobList = inputs[0].source
636
637 # Figure out where to put the output.
638 baseInput = inputs[0].baseInput
639 if phase.type == Types.NothingType:
640 output = None
641 elif outputToPipe:
642 if isinstance(jobList, Jobs.PipedJob):
643 output = jobList
644 else:
645 jobList = output = Jobs.PipedJob([])
646 jobs.addJob(output)
647 else:
648 # Figure out what the derived output location would be.
649 #
650 # FIXME: gcc has some special case in here so that it doesn't
651 # create output files if they would conflict with an input.
Daniel Dunbara5677512009-01-05 19:53:30 +0000652 if phase.type is Types.ImageType:
653 namedOutput = "a.out"
654 else:
Daniel Dunbar2ec55bc2009-01-12 03:33:58 +0000655 inputName = args.getValue(baseInput)
Daniel Dunbara5677512009-01-05 19:53:30 +0000656 base,_ = os.path.splitext(inputName)
657 assert phase.type.tempSuffix is not None
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000658 namedOutput = base + '.' + phase.type.tempSuffix
Daniel Dunbara5677512009-01-05 19:53:30 +0000659
660 # Output to user requested destination?
661 if atTopLevel and finalOutput:
662 output = finalOutput
663 # Contruct a named destination?
664 elif atTopLevel or hasSaveTemps:
Daniel Dunbar3235fdb2009-01-12 07:48:07 +0000665 output = args.makeSeparateArg(os.path.basename(namedOutput),
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000666 self.parser.oOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000667 else:
668 # Output to temp file...
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000669 fd,filename = tempfile.mkstemp(suffix='.'+phase.type.tempSuffix)
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000670 output = args.makeSeparateArg(filename,
671 self.parser.oOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000672
Daniel Dunbardb439902009-01-07 18:40:45 +0000673 tool.constructJob(phase, arch, jobList, inputs, output, phase.type,
Daniel Dunbar11672ec2009-01-13 18:51:26 +0000674 tcArgs)
Daniel Dunbara5677512009-01-05 19:53:30 +0000675
676 return InputInfo(output, phase.type, baseInput)
677
678 # It is an error to provide a -o option if we are making multiple
679 # output files.
680 if finalOutput and len([a for a in phases if a.type is not Types.NothingType]) > 1:
681 # FIXME: Custom exception.
682 raise ValueError,"Cannot specify -o when generating multiple files."
683
684 for phase in phases:
Daniel Dunbar11672ec2009-01-13 18:51:26 +0000685 createJobs(self.toolChain, phase,
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000686 canAcceptPipe=True, atTopLevel=True)
Daniel Dunbara5677512009-01-05 19:53:30 +0000687
688 return jobs