blob: afc7cf58543f2819ffd6c73eaea41dfcc4f64e27 [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
61 ###
62
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000063 def run(self, argv):
Daniel Dunbara5677512009-01-05 19:53:30 +000064 # FIXME: Things to support from environment: GCC_EXEC_PREFIX,
65 # COMPILER_PATH, LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS,
66 # QA_OVERRIDE_GCC3_OPTIONS, ...?
67
68 # FIXME: -V and -b processing
69
70 # Handle some special -ccc- options used for testing which are
71 # only allowed at the beginning of the command line.
72 cccPrintOptions = False
73 cccPrintPhases = False
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000074
75 # FIXME: How to handle override of host? ccc specific options?
76 # Abuse -b?
77 self.cccHostBits = self.cccHostMachine = self.cccHostSystem = None
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000078 while argv and argv[0].startswith('-ccc-'):
79 opt,argv = argv[0][5:],argv[1:]
Daniel Dunbara5677512009-01-05 19:53:30 +000080
81 if opt == 'print-options':
82 cccPrintOptions = True
83 elif opt == 'print-phases':
84 cccPrintPhases = True
Daniel Dunbar9066af82009-01-09 01:00:40 +000085 elif opt == 'host-bits':
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000086 self.cccHostBits,argv = argv[0],argv[1:]
Daniel Dunbar9066af82009-01-09 01:00:40 +000087 elif opt == 'host-machine':
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000088 self.cccHostMachine,argv = argv[0],argv[1:]
Daniel Dunbar9066af82009-01-09 01:00:40 +000089 elif opt == 'host-system':
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000090 self.cccHostSystem,argv = argv[0],argv[1:]
Daniel Dunbara5677512009-01-05 19:53:30 +000091 else:
92 raise ValueError,"Invalid ccc option: %r" % cccPrintOptions
93
Daniel Dunbara75ea3d2009-01-09 22:21:24 +000094 self.hostInfo = HostInfo.getHostInfo(self)
Daniel Dunbar43124722009-01-10 02:07:54 +000095 self.toolChain = self.hostInfo.getToolChain()
Daniel Dunbar9066af82009-01-09 01:00:40 +000096
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +000097 args = self.parser.parseArgs(argv)
Daniel Dunbara5677512009-01-05 19:53:30 +000098
99 # FIXME: Ho hum I have just realized -Xarch_ is broken. We really
100 # need to reparse the Arguments after they have been expanded by
101 # -Xarch. How is this going to work?
102 #
103 # Scratch that, we aren't going to do that; it really disrupts the
104 # organization, doesn't consistently work with gcc-dd, and is
105 # confusing. Instead we are going to enforce that -Xarch_ is only
106 # used with options which do not alter the driver behavior. Let's
107 # hope this is ok, because the current architecture is a little
108 # tied to it.
109
110 if cccPrintOptions:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000111 self.printOptions(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000112 sys.exit(0)
113
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000114 self.handleImmediateOptions(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000115
Daniel Dunbar9066af82009-01-09 01:00:40 +0000116 if self.hostInfo.useDriverDriver():
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000117 phases = self.buildPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000118 else:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000119 phases = self.buildNormalPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000120
121 if cccPrintPhases:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000122 self.printPhases(phases, args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000123 sys.exit(0)
Daniel Dunbar9066af82009-01-09 01:00:40 +0000124
Daniel Dunbara5677512009-01-05 19:53:30 +0000125 if 0:
126 print Util.pprint(phases)
127
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000128 jobs = self.bindPhases(phases, args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000129
130 # FIXME: We should provide some basic sanity checking of the
131 # pipeline as a "verification" sort of stage. For example, the
132 # pipeline should never end up writing to an output file in two
133 # places (I think). The pipeline should also never end up writing
134 # to an output file that is an input.
135 #
136 # This is intended to just be a "verify" step, not a functionality
137 # step. It should catch things like the driver driver not
138 # preventing -save-temps, but it shouldn't change behavior (so we
139 # can turn it off in Release-Asserts builds).
140
141 # Print in -### syntax.
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000142 hasHashHashHash = args.getLastArg(self.parser.hashHashHashOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000143 if hasHashHashHash:
144 self.claim(hasHashHashHash)
145 for j in jobs.iterjobs():
146 if isinstance(j, Jobs.Command):
Daniel Dunbare99f9262009-01-11 22:03:55 +0000147 print >>sys.stderr, '"%s"' % '" "'.join(j.getArgv())
Daniel Dunbara5677512009-01-05 19:53:30 +0000148 elif isinstance(j, Jobs.PipedJob):
149 for c in j.commands:
Daniel Dunbare99f9262009-01-11 22:03:55 +0000150 print >>sys.stderr, '"%s" %c' % ('" "'.join(c.getArgv()),
151 "| "[c is j.commands[-1]])
Daniel Dunbara5677512009-01-05 19:53:30 +0000152 elif not isinstance(j, JobList):
153 raise ValueError,'Encountered unknown job.'
154 sys.exit(0)
155
156 for j in jobs.iterjobs():
157 if isinstance(j, Jobs.Command):
Daniel Dunbardb439902009-01-07 18:40:45 +0000158 res = os.spawnvp(os.P_WAIT, j.executable, j.getArgv())
Daniel Dunbara5677512009-01-05 19:53:30 +0000159 if res:
160 sys.exit(res)
161 elif isinstance(j, Jobs.PipedJob):
162 raise NotImplementedError,"Piped jobs aren't implemented yet."
163 else:
164 raise ValueError,'Encountered unknown job.'
165
166 def claim(self, option):
167 # FIXME: Move to OptionList once introduced and implement.
168 pass
169
170 def warning(self, message):
171 print >>sys.stderr,'%s: %s' % (sys.argv[0], message)
172
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000173 def printOptions(self, args):
174 for i,arg in enumerate(args):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000175 if isinstance(arg, Arguments.MultipleValuesArg):
176 values = list(args.getValues(arg))
177 elif isinstance(arg, Arguments.ValueArg):
178 values = [args.getValue(arg)]
179 elif isinstance(arg, Arguments.JoinedAndSeparateValuesArg):
180 values = [args.getJoinedValue(arg), args.getSeparateValue(arg)]
Daniel Dunbara5677512009-01-05 19:53:30 +0000181 else:
182 values = []
Daniel Dunbar5039f212009-01-06 02:30:10 +0000183 print 'Option %d - Name: "%s", Values: {%s}' % (i, arg.opt.name,
Daniel Dunbara5677512009-01-05 19:53:30 +0000184 ', '.join(['"%s"' % v
185 for v in values]))
186
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000187 def printPhases(self, phases, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000188 def printPhase(p, f, steps, arch=None):
189 if p in steps:
190 return steps[p]
191 elif isinstance(p, Phases.BindArchAction):
192 for kid in p.inputs:
193 printPhase(kid, f, steps, p.arch)
194 steps[p] = len(steps)
195 return
196
197 if isinstance(p, Phases.InputAction):
198 phaseName = 'input'
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000199 inputStr = '"%s"' % args.getValue(p.filename)
Daniel Dunbara5677512009-01-05 19:53:30 +0000200 else:
201 phaseName = p.phase.name
202 inputs = [printPhase(i, f, steps, arch)
203 for i in p.inputs]
204 inputStr = '{%s}' % ', '.join(map(str, inputs))
205 if arch is not None:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000206 phaseName += '-' + args.getValue(arch)
Daniel Dunbara5677512009-01-05 19:53:30 +0000207 steps[p] = index = len(steps)
208 print "%d: %s, %s, %s" % (index,phaseName,inputStr,p.type.name)
209 return index
210 steps = {}
211 for phase in phases:
212 printPhase(phase, sys.stdout, steps)
213
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000214 def handleImmediateOptions(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000215 # FIXME: Some driver Arguments are consumed right off the bat,
216 # like -dumpversion. Currently the gcc-dd handles these
217 # poorly, so we should be ok handling them upfront instead of
218 # after driver-driver level dispatching.
219 #
220 # FIXME: The actual order of these options in gcc is all over the
221 # place. The -dump ones seem to be first and in specification
222 # order, but there are other levels of precedence. For example,
223 # -print-search-dirs is evaluated before -print-prog-name=,
224 # regardless of order (and the last instance of -print-prog-name=
225 # wins verse itself).
226 #
227 # FIXME: Do we want to report "argument unused" type errors in the
228 # presence of things like -dumpmachine and -print-search-dirs?
229 # Probably not.
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000230 arg = args.getLastArg(self.parser.dumpmachineOption)
231 if arg:
232 print 'FIXME: %s' % arg.opt.name
233 sys.exit(1)
234
235 arg = args.getLastArg(self.parser.dumpspecsOption)
236 if arg:
237 print 'FIXME: %s' % arg.opt.name
238 sys.exit(1)
239
240 arg = args.getLastArg(self.parser.dumpversionOption)
241 if arg:
242 print 'FIXME: %s' % arg.opt.name
243 sys.exit(1)
244
245 arg = args.getLastArg(self.parser.printFileNameOption)
246 if arg:
247 print 'FIXME: %s' % arg.opt.name
248 sys.exit(1)
249
250 arg = args.getLastArg(self.parser.printMultiDirectoryOption)
251 if arg:
252 print 'FIXME: %s' % arg.opt.name
253 sys.exit(1)
254
255 arg = args.getLastArg(self.parser.printMultiLibOption)
256 if arg:
257 print 'FIXME: %s' % arg.opt.name
258 sys.exit(1)
259
260 arg = args.getLastArg(self.parser.printProgNameOption)
261 if arg:
262 print 'FIXME: %s' % arg.opt.name
263 sys.exit(1)
264
265 arg = args.getLastArg(self.parser.printLibgccFilenameOption)
266 if arg:
267 print 'FIXME: %s' % arg.opt.name
268 sys.exit(1)
269
270 arg = args.getLastArg(self.parser.printSearchDirsOption)
271 if arg:
272 print 'FIXME: %s' % arg.opt.name
273 sys.exit(1)
Daniel Dunbara5677512009-01-05 19:53:30 +0000274
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000275 def buildNormalPipeline(self, args):
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000276 hasCombine = args.getLastArg(self.parser.combineOption)
277 hasSyntaxOnly = args.getLastArg(self.parser.syntaxOnlyOption)
278 hasDashC = args.getLastArg(self.parser.cOption)
279 hasDashE = args.getLastArg(self.parser.EOption)
280 hasDashS = args.getLastArg(self.parser.SOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000281
282 inputType = None
283 inputTypeOpt = None
284 inputs = []
285 for a in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000286 if a.opt is self.parser.inputOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000287 if inputType is None:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000288 base,ext = os.path.splitext(args.getValue(a))
Daniel Dunbara5677512009-01-05 19:53:30 +0000289 if ext and ext in Types.kTypeSuffixMap:
290 klass = Types.kTypeSuffixMap[ext]
291 else:
292 # FIXME: Its not clear why we shouldn't just
293 # revert to unknown. I think this is more likely a
294 # bug / unintended behavior in gcc. Not very
295 # important though.
296 klass = Types.ObjectType
297 else:
298 assert inputTypeOpt is not None
299 self.claim(inputTypeOpt)
300 klass = inputType
301 inputs.append((klass, a))
Daniel Dunbar2ec55bc2009-01-12 03:33:58 +0000302 elif a.opt.isLinkerInput:
303 # Treat as a linker input.
Daniel Dunbar5039f212009-01-06 02:30:10 +0000304 #
305 # FIXME: This might not be good enough. We may
306 # need to introduce another type for this case, so
307 # that other code which needs to know the inputs
308 # handles this properly. Best not to try and lipo
309 # this, for example.
Daniel Dunbare99f9262009-01-11 22:03:55 +0000310 #
311 # FIXME: Actually, this is just flat out broken, the
312 # tools expect inputs to be accessible by .getValue
313 # but that of course only yields the argument.
Daniel Dunbar5039f212009-01-06 02:30:10 +0000314 inputs.append((Types.ObjectType, a))
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000315 elif a.opt is self.parser.xOption:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000316 self.claim(a)
317 inputTypeOpt = a
318 value = args.getValue(a)
319 if value in Types.kTypeSpecifierMap:
320 inputType = Types.kTypeSpecifierMap[value]
321 else:
322 # FIXME: How are we going to handle diagnostics.
323 self.warning("language %s not recognized" % value)
Daniel Dunbara5677512009-01-05 19:53:30 +0000324
Daniel Dunbar5039f212009-01-06 02:30:10 +0000325 # FIXME: Its not clear why we shouldn't just
326 # revert to unknown. I think this is more likely a
327 # bug / unintended behavior in gcc. Not very
328 # important though.
329 inputType = ObjectType
Daniel Dunbara5677512009-01-05 19:53:30 +0000330
331 # We claim things here so that options for which we silently allow
332 # override only ever claim the used option.
333 if hasCombine:
334 self.claim(hasCombine)
335
336 finalPhase = Phases.Phase.eOrderPostAssemble
337 finalPhaseOpt = None
338
339 # Determine what compilation mode we are in.
340 if hasDashE:
341 finalPhase = Phases.Phase.eOrderPreprocess
342 finalPhaseOpt = hasDashE
343 elif hasSyntaxOnly:
344 finalPhase = Phases.Phase.eOrderCompile
345 finalPhaseOpt = hasSyntaxOnly
346 elif hasDashS:
347 finalPhase = Phases.Phase.eOrderCompile
348 finalPhaseOpt = hasDashS
349 elif hasDashC:
350 finalPhase = Phases.Phase.eOrderAssemble
351 finalPhaseOpt = hasDashC
352
353 if finalPhaseOpt:
354 self.claim(finalPhaseOpt)
355
356 # FIXME: Support -combine.
357 if hasCombine:
358 raise NotImplementedError,"-combine is not yet supported."
359
360 actions = []
361 linkerInputs = []
362 # FIXME: This is gross.
363 linkPhase = Phases.LinkPhase()
364 for klass,input in inputs:
365 # Figure out what step to start at.
366
367 # FIXME: This should be part of the input class probably?
368 # Altough it doesn't quite fit there either, things like
369 # asm-with-preprocess don't easily fit into a linear scheme.
370
371 # FIXME: I think we are going to end up wanting to just build
372 # a simple FSA which we run the inputs down.
373 sequence = []
374 if klass.preprocess:
375 sequence.append(Phases.PreprocessPhase())
376 if klass == Types.ObjectType:
377 sequence.append(linkPhase)
378 elif klass.onlyAssemble:
379 sequence.extend([Phases.AssemblePhase(),
380 linkPhase])
381 elif klass.onlyPrecompile:
382 sequence.append(Phases.PrecompilePhase())
383 else:
384 sequence.extend([Phases.CompilePhase(),
385 Phases.AssemblePhase(),
386 linkPhase])
387
388 if sequence[0].order > finalPhase:
389 assert finalPhaseOpt and finalPhaseOpt.opt
390 # FIXME: Explain what type of input file is. Or just match
391 # gcc warning.
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000392 self.warning("%s: %s input file unused when %s is present" % (args.getValue(input),
Daniel Dunbara5677512009-01-05 19:53:30 +0000393 sequence[0].name,
394 finalPhaseOpt.opt.name))
395 else:
396 # Build the pipeline for this file.
397
398 current = Phases.InputAction(input, klass)
399 for transition in sequence:
400 # If the current action produces no output, or we are
401 # past what the user requested, we are done.
402 if (current.type is Types.NothingType or
403 transition.order > finalPhase):
404 break
405 else:
406 if isinstance(transition, Phases.PreprocessPhase):
407 assert isinstance(klass.preprocess, Types.InputType)
408 current = Phases.JobAction(transition,
409 [current],
410 klass.preprocess)
411 elif isinstance(transition, Phases.PrecompilePhase):
412 current = Phases.JobAction(transition,
413 [current],
414 Types.PCHType)
415 elif isinstance(transition, Phases.CompilePhase):
416 if hasSyntaxOnly:
417 output = Types.NothingType
418 else:
419 output = Types.AsmTypeNoPP
420 current = Phases.JobAction(transition,
421 [current],
422 output)
423 elif isinstance(transition, Phases.AssemblePhase):
424 current = Phases.JobAction(transition,
425 [current],
426 Types.ObjectType)
427 elif transition is linkPhase:
428 linkerInputs.append(current)
429 current = None
430 break
431 else:
432 raise RuntimeError,'Unrecognized transition: %s.' % transition
433 pass
434
435 if current is not None:
436 assert not isinstance(current, Phases.InputAction)
437 actions.append(current)
438
439 if linkerInputs:
440 actions.append(Phases.JobAction(linkPhase,
441 linkerInputs,
442 Types.ImageType))
443
444 return actions
445
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000446 def buildPipeline(self, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000447 # FIXME: We need to handle canonicalization of the specified arch.
448
449 archs = []
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000450 hasDashM = None
451 hasSaveTemps = (args.getLastArg(self.parser.saveTempsOption) or
452 args.getLastArg(self.parser.saveTempsOption2))
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000453 for arg in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000454 if arg.opt is self.parser.archOption:
Daniel Dunbar5039f212009-01-06 02:30:10 +0000455 archs.append(arg)
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000456 elif arg.opt.name.startswith('-M'):
457 hasDashM = arg
Daniel Dunbara5677512009-01-05 19:53:30 +0000458
459 if not archs:
Daniel Dunbar9066af82009-01-09 01:00:40 +0000460 archs.append(args.makeSeparateArg(self.hostInfo.getArchName(),
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000461 self.parser.archOption))
Daniel Dunbara5677512009-01-05 19:53:30 +0000462
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000463 actions = self.buildNormalPipeline(args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000464
465 # FIXME: Use custom exception for this.
466 #
467 # FIXME: We killed off some others but these aren't yet detected in
468 # a functional manner. If we added information to jobs about which
469 # "auxiliary" files they wrote then we could detect the conflict
470 # these cause downstream.
471 if len(archs) > 1:
472 if hasDashM:
473 raise ValueError,"Cannot use -M options with multiple arch flags."
474 elif hasSaveTemps:
475 raise ValueError,"Cannot use -save-temps with multiple arch flags."
476
477 # Execute once per arch.
478 finalActions = []
479 for p in actions:
480 # Make sure we can lipo this kind of output. If not (and it
481 # is an actual output) then we disallow, since we can't
482 # create an output file with the right name without
483 # overwriting it. We could remove this oddity by just
484 # changing the output names to include the arch, which would
485 # also fix -save-temps. Compatibility wins for now.
486 #
487 # FIXME: Is this error substantially less useful than
488 # gcc-dd's? The main problem is that "Cannot use compiler
489 # output with multiple arch flags" won't make sense to most
490 # developers.
491 if (len(archs) > 1 and
492 p.type not in (Types.NothingType,Types.ObjectType,Types.ImageType)):
493 raise ValueError,'Cannot use %s output with multiple arch flags.' % p.type.name
494
495 inputs = []
496 for arch in archs:
497 inputs.append(Phases.BindArchAction(p, arch))
498
499 # Lipo if necessary. We do it this way because we need to set
500 # the arch flag so that -Xarch_ gets rewritten.
501 if len(inputs) == 1 or p.type == Types.NothingType:
502 finalActions.extend(inputs)
503 else:
504 finalActions.append(Phases.JobAction(Phases.LipoPhase(),
505 inputs,
506 p.type))
507
508 # FIXME: We need to add -Wl,arch_multiple and -Wl,final_output in
509 # certain cases. This may be icky because we need to figure out the
510 # mode first. Current plan is to hack on the pipeline once it is built
511 # and we know what is being spit out. This avoids having to handling
512 # things like -c and -combine in multiple places.
513 #
514 # The annoying one of these is -Wl,final_output because it involves
515 # communication across different phases.
516 #
517 # Hopefully we can do this purely as part of the binding, but
518 # leaving comment here for now until it is clear this works.
519
520 return finalActions
521
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000522 def bindPhases(self, phases, args):
Daniel Dunbara5677512009-01-05 19:53:30 +0000523 jobs = Jobs.JobList()
524
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000525 finalOutput = args.getLastArg(self.parser.oOption)
526 hasSaveTemps = (args.getLastArg(self.parser.saveTempsOption) or
527 args.getLastArg(self.parser.saveTempsOption2))
528 hasNoIntegratedCPP = args.getLastArg(self.parser.noIntegratedCPPOption)
529 hasPipe = args.getLastArg(self.parser.pipeOption)
Daniel Dunbar2ec55bc2009-01-12 03:33:58 +0000530
531 # FIXME: forward will die, this isn't really how things are
532 # done, instead everything comes from the arglist. For this we
533 # need a DerivedArgList for handling -Xarch, and some way to
534 # still figure out what to forward to the generic gcc tool.
Daniel Dunbara5677512009-01-05 19:53:30 +0000535 forward = []
536 for a in args:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000537 if a.opt is self.parser.inputOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000538 pass
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000539
540 # FIXME: Needs to be part of option.
Daniel Dunbar2ec55bc2009-01-12 03:33:58 +0000541 elif (a.opt.name in ('-E', '-S', '-c',
542 '-arch', '-fsyntax-only', '-combine', '-x',
543 '-###') or
544 a.opt.isLinkerInput):
Daniel Dunbar5039f212009-01-06 02:30:10 +0000545 pass
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000546
Daniel Dunbara5677512009-01-05 19:53:30 +0000547 else:
548 forward.append(a)
549
550 # 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)
560 if hasNoIntegratedCPP:
561 self.claim(hasNoIntegratedCPP)
562
Daniel Dunbara5677512009-01-05 19:53:30 +0000563 class InputInfo:
564 def __init__(self, source, type, baseInput):
565 self.source = source
566 self.type = type
567 self.baseInput = baseInput
568
569 def __repr__(self):
570 return '%s(%r, %r, %r)' % (self.__class__.__name__,
571 self.source, self.type, self.baseInput)
572
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000573 def createJobs(tc, phase, forwardArgs,
Daniel Dunbara5677512009-01-05 19:53:30 +0000574 canAcceptPipe=False, atTopLevel=False, arch=None):
575 if isinstance(phase, Phases.InputAction):
576 return InputInfo(phase.filename, phase.type, phase.filename)
577 elif isinstance(phase, Phases.BindArchAction):
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000578 archName = args.getValue(phase.arch)
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000579 tc = self.hostInfo.getToolChainForArch(archName)
Daniel Dunbara5677512009-01-05 19:53:30 +0000580 filteredArgs = []
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000581 for arg in forwardArgs:
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000582 if arg.opt is self.parser.archOption:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000583 if arg is phase.arch:
584 filteredArgs.append(arg)
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000585 elif arg.opt is self.parser.XarchOption:
Daniel Dunbara5677512009-01-05 19:53:30 +0000586 # FIXME: gcc-dd has another conditional for passing
587 # through, when the arch conditional array has an empty
588 # string. Why?
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000589 if args.getJoinedValue(arg) == archName:
Daniel Dunbara5677512009-01-05 19:53:30 +0000590 # FIXME: This is wrong, we don't want a
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000591 # unknown arg we want an actual parsed
592 # version of this arg.
593 filteredArgs.append(args.makeUnknownArg(args.getSeparateValue(arg)))
Daniel Dunbara5677512009-01-05 19:53:30 +0000594 else:
Daniel Dunbar1e5f3eb2009-01-06 01:35:44 +0000595 filteredArgs.append(arg)
Daniel Dunbara5677512009-01-05 19:53:30 +0000596
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000597 return createJobs(tc, phase.inputs[0], filteredArgs,
Daniel Dunbara5677512009-01-05 19:53:30 +0000598 canAcceptPipe, atTopLevel, phase.arch)
599
600 assert isinstance(phase, Phases.JobAction)
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000601 tool = tc.selectTool(phase)
Daniel Dunbara5677512009-01-05 19:53:30 +0000602
603 # See if we should use an integrated CPP. We only use an
604 # integrated cpp when we have exactly one input, since this is
605 # the only use case we care about.
606 useIntegratedCPP = False
607 inputList = phase.inputs
608 if (not hasNoIntegratedCPP and
609 not hasSaveTemps and
610 tool.hasIntegratedCPP()):
611 if (len(phase.inputs) == 1 and
612 isinstance(phase.inputs[0].phase, Phases.PreprocessPhase)):
613 useIntegratedCPP = True
614 inputList = phase.inputs[0].inputs
615
616 # Only try to use pipes when exactly one input.
617 canAcceptPipe = len(inputList) == 1 and tool.acceptsPipedInput()
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000618 inputs = [createJobs(tc, p, forwardArgs, canAcceptPipe, False, arch)
619 for p in inputList]
Daniel Dunbara5677512009-01-05 19:53:30 +0000620
621 # Determine if we should output to a pipe.
622 canOutputToPipe = canAcceptPipe and tool.canPipeOutput()
623 outputToPipe = False
624 if canOutputToPipe:
625 # Some things default to writing to a pipe if the final
626 # phase and there was no user override.
627 #
628 # FIXME: What is the best way to handle this?
629 if (atTopLevel and
630 isinstance(phase, Phases.PreprocessPhase) and
631 not finalOutput):
632 outputToPipe = True
633 elif hasPipe:
634 outputToPipe = True
635
636 # Figure out where to put the job (pipes).
637 jobList = jobs
638 if canAcceptPipe and isinstance(inputs[0].source, Jobs.PipedJob):
639 jobList = inputs[0].source
640
641 # Figure out where to put the output.
642 baseInput = inputs[0].baseInput
643 if phase.type == Types.NothingType:
644 output = None
645 elif outputToPipe:
646 if isinstance(jobList, Jobs.PipedJob):
647 output = jobList
648 else:
649 jobList = output = Jobs.PipedJob([])
650 jobs.addJob(output)
651 else:
652 # Figure out what the derived output location would be.
653 #
654 # FIXME: gcc has some special case in here so that it doesn't
655 # create output files if they would conflict with an input.
Daniel Dunbara5677512009-01-05 19:53:30 +0000656 if phase.type is Types.ImageType:
657 namedOutput = "a.out"
658 else:
Daniel Dunbar2ec55bc2009-01-12 03:33:58 +0000659 inputName = args.getValue(baseInput)
Daniel Dunbara5677512009-01-05 19:53:30 +0000660 base,_ = os.path.splitext(inputName)
661 assert phase.type.tempSuffix is not None
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000662 namedOutput = base + '.' + phase.type.tempSuffix
Daniel Dunbara5677512009-01-05 19:53:30 +0000663
664 # Output to user requested destination?
665 if atTopLevel and finalOutput:
666 output = finalOutput
667 # Contruct a named destination?
668 elif atTopLevel or hasSaveTemps:
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000669 output = args.makeSeparateArg(namedOutput,
670 self.parser.oOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000671 else:
672 # Output to temp file...
Daniel Dunbarba6e3232009-01-06 06:12:13 +0000673 fd,filename = tempfile.mkstemp(suffix='.'+phase.type.tempSuffix)
Daniel Dunbar39cbfaa2009-01-07 18:54:26 +0000674 output = args.makeSeparateArg(filename,
675 self.parser.oOption)
Daniel Dunbara5677512009-01-05 19:53:30 +0000676
Daniel Dunbardb439902009-01-07 18:40:45 +0000677 tool.constructJob(phase, arch, jobList, inputs, output, phase.type,
678 forwardArgs, args)
Daniel Dunbara5677512009-01-05 19:53:30 +0000679
680 return InputInfo(output, phase.type, baseInput)
681
682 # It is an error to provide a -o option if we are making multiple
683 # output files.
684 if finalOutput and len([a for a in phases if a.type is not Types.NothingType]) > 1:
685 # FIXME: Custom exception.
686 raise ValueError,"Cannot specify -o when generating multiple files."
687
688 for phase in phases:
Daniel Dunbarbee1f0d2009-01-11 22:06:22 +0000689 createJobs(self.toolChain, phase, forward,
690 canAcceptPipe=True, atTopLevel=True)
Daniel Dunbara5677512009-01-05 19:53:30 +0000691
692 return jobs