blob: e6aba65fc766ac49c42c56a8b5a40ae8dc927bae [file] [log] [blame]
Daniel Dunbar378530c2009-01-05 19:53:30 +00001import os
Daniel Dunbar4ed45ea2009-01-09 01:00:40 +00002import platform
Daniel Dunbara95c6392009-02-19 22:59:57 +00003import subprocess
Daniel Dunbar378530c2009-01-05 19:53:30 +00004import sys
5import tempfile
6from pprint import pprint
7
8###
9
10import Arguments
11import Jobs
Daniel Dunbar4ed45ea2009-01-09 01:00:40 +000012import HostInfo
Daniel Dunbar378530c2009-01-05 19:53:30 +000013import Phases
14import Tools
15import Types
16import Util
17
18# FIXME: Clean up naming of options and arguments. Decide whether to
19# rename Option and be consistent about use of Option/Arg.
20
21####
22
Daniel Dunbar378530c2009-01-05 19:53:30 +000023class Driver(object):
Daniel Dunbara0026f22009-01-16 23:12:12 +000024 def __init__(self, driverName, driverDir):
25 self.driverName = driverName
26 self.driverDir = driverDir
Daniel Dunbar4ed45ea2009-01-09 01:00:40 +000027 self.hostInfo = None
Daniel Dunbare9f1a692009-01-06 06:12:13 +000028 self.parser = Arguments.OptionParser()
Daniel Dunbar7c2f91b2009-01-14 01:03:36 +000029 self.cccHostBits = self.cccHostMachine = None
30 self.cccHostSystem = self.cccHostRelease = None
31 self.cccCXX = False
Daniel Dunbar4c751dc2009-01-14 01:32:05 +000032 self.cccEcho = False
Daniel Dunbar7c2f91b2009-01-14 01:03:36 +000033 self.cccFallback = False
Daniel Dunbar72999172009-01-29 23:54:06 +000034 self.cccNoClang = self.cccNoClangCXX = self.cccNoClangPreprocessor = False
35 self.cccClangArchs = None
Daniel Dunbar378530c2009-01-05 19:53:30 +000036
Daniel Dunbar8fd28cd2009-01-28 19:26:20 +000037 # Certain options suppress the 'no input files' warning.
38 self.suppressMissingInputWarning = False
39
Daniel Dunbar61320532009-02-22 01:23:52 +000040 # Temporary files used in compilation, removed on exit.
41 self.tempFiles = []
42 # Result files produced by compilation, removed on error.
43 self.resultFiles = []
44
Daniel Dunbardbc9ee92009-01-09 22:21:24 +000045 # Host queries which can be forcibly over-riden by the user for
46 # testing purposes.
47 #
48 # FIXME: We should make sure these are drawn from a fixed set so
49 # that nothing downstream ever plays a guessing game.
50
51 def getHostBits(self):
52 if self.cccHostBits:
53 return self.cccHostBits
54
55 return platform.architecture()[0].replace('bit','')
56
57 def getHostMachine(self):
58 if self.cccHostMachine:
59 return self.cccHostMachine
60
61 machine = platform.machine()
62 # Normalize names.
63 if machine == 'Power Macintosh':
64 return 'ppc'
Daniel Dunbar405327e2009-01-27 19:29:51 +000065 if machine == 'x86_64':
66 return 'i386'
Daniel Dunbardbc9ee92009-01-09 22:21:24 +000067 return machine
68
69 def getHostSystemName(self):
70 if self.cccHostSystem:
71 return self.cccHostSystem
72
73 return platform.system().lower()
74
Daniel Dunbarc2148562009-01-12 04:21:12 +000075 def getHostReleaseName(self):
76 if self.cccHostRelease:
77 return self.cccHostRelease
78
79 return platform.release()
80
Daniel Dunbar4c751dc2009-01-14 01:32:05 +000081 def getenvBool(self, name):
82 var = os.getenv(name)
83 if not var:
84 return False
85
86 try:
87 return bool(int(var))
88 except:
89 return False
90
Daniel Dunbardbc9ee92009-01-09 22:21:24 +000091 ###
92
Daniel Dunbarf677a602009-01-21 02:03:52 +000093 def getFilePath(self, name, toolChain=None):
94 tc = toolChain or self.toolChain
95 for p in tc.filePathPrefixes:
96 path = os.path.join(p, name)
97 if os.path.exists(path):
98 return path
99 return name
100
101 def getProgramPath(self, name, toolChain=None):
102 tc = toolChain or self.toolChain
103 for p in tc.programPathPrefixes:
104 path = os.path.join(p, name)
105 if os.path.exists(path):
106 return path
107 return name
108
109 ###
110
Daniel Dunbar74727872009-01-06 01:35:44 +0000111 def run(self, argv):
Daniel Dunbar378530c2009-01-05 19:53:30 +0000112 # FIXME: Things to support from environment: GCC_EXEC_PREFIX,
113 # COMPILER_PATH, LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS,
114 # QA_OVERRIDE_GCC3_OPTIONS, ...?
115
116 # FIXME: -V and -b processing
117
118 # Handle some special -ccc- options used for testing which are
119 # only allowed at the beginning of the command line.
120 cccPrintOptions = False
121 cccPrintPhases = False
Daniel Dunbardbc9ee92009-01-09 22:21:24 +0000122
123 # FIXME: How to handle override of host? ccc specific options?
124 # Abuse -b?
Daniel Dunbar72999172009-01-29 23:54:06 +0000125 arg = os.getenv('CCC_ADD_ARGS')
126 if arg:
127 args = filter(None, map(str.strip, arg.split(',')))
128 argv = args + argv
Daniel Dunbar4c751dc2009-01-14 01:32:05 +0000129
Daniel Dunbar74727872009-01-06 01:35:44 +0000130 while argv and argv[0].startswith('-ccc-'):
Daniel Dunbara0026f22009-01-16 23:12:12 +0000131 fullOpt,argv = argv[0],argv[1:]
132 opt = fullOpt[5:]
Daniel Dunbar378530c2009-01-05 19:53:30 +0000133
134 if opt == 'print-options':
135 cccPrintOptions = True
136 elif opt == 'print-phases':
137 cccPrintPhases = True
Daniel Dunbar7c2f91b2009-01-14 01:03:36 +0000138 elif opt == 'cxx':
139 self.cccCXX = True
Daniel Dunbar4c751dc2009-01-14 01:32:05 +0000140 elif opt == 'echo':
141 self.cccEcho = True
Daniel Dunbar7c2f91b2009-01-14 01:03:36 +0000142 elif opt == 'fallback':
143 self.cccFallback = True
Daniel Dunbar72999172009-01-29 23:54:06 +0000144
145 elif opt == 'no-clang':
146 self.cccNoClang = True
147 elif opt == 'no-clang-cxx':
148 self.cccNoClangCXX = True
149 elif opt == 'no-clang-cpp':
150 self.cccNoClangPreprocessor = True
151 elif opt == 'clang-archs':
152 self.cccClangArchs,argv = argv[0].split(','),argv[1:]
153
Daniel Dunbar4ed45ea2009-01-09 01:00:40 +0000154 elif opt == 'host-bits':
Daniel Dunbardbc9ee92009-01-09 22:21:24 +0000155 self.cccHostBits,argv = argv[0],argv[1:]
Daniel Dunbar4ed45ea2009-01-09 01:00:40 +0000156 elif opt == 'host-machine':
Daniel Dunbardbc9ee92009-01-09 22:21:24 +0000157 self.cccHostMachine,argv = argv[0],argv[1:]
Daniel Dunbar4ed45ea2009-01-09 01:00:40 +0000158 elif opt == 'host-system':
Daniel Dunbardbc9ee92009-01-09 22:21:24 +0000159 self.cccHostSystem,argv = argv[0],argv[1:]
Daniel Dunbarc2148562009-01-12 04:21:12 +0000160 elif opt == 'host-release':
161 self.cccHostRelease,argv = argv[0],argv[1:]
Daniel Dunbar378530c2009-01-05 19:53:30 +0000162 else:
Daniel Dunbara0026f22009-01-16 23:12:12 +0000163 raise Arguments.InvalidArgumentsError("invalid option: %r" % fullOpt)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000164
Daniel Dunbardbc9ee92009-01-09 22:21:24 +0000165 self.hostInfo = HostInfo.getHostInfo(self)
Daniel Dunbar08dea462009-01-10 02:07:54 +0000166 self.toolChain = self.hostInfo.getToolChain()
Daniel Dunbar4ed45ea2009-01-09 01:00:40 +0000167
Daniel Dunbar74727872009-01-06 01:35:44 +0000168 args = self.parser.parseArgs(argv)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000169
170 # FIXME: Ho hum I have just realized -Xarch_ is broken. We really
171 # need to reparse the Arguments after they have been expanded by
172 # -Xarch. How is this going to work?
173 #
174 # Scratch that, we aren't going to do that; it really disrupts the
175 # organization, doesn't consistently work with gcc-dd, and is
176 # confusing. Instead we are going to enforce that -Xarch_ is only
177 # used with options which do not alter the driver behavior. Let's
178 # hope this is ok, because the current architecture is a little
179 # tied to it.
180
181 if cccPrintOptions:
Daniel Dunbar74727872009-01-06 01:35:44 +0000182 self.printOptions(args)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000183 sys.exit(0)
184
Daniel Dunbar74727872009-01-06 01:35:44 +0000185 self.handleImmediateOptions(args)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000186
Daniel Dunbar4ed45ea2009-01-09 01:00:40 +0000187 if self.hostInfo.useDriverDriver():
Daniel Dunbar74727872009-01-06 01:35:44 +0000188 phases = self.buildPipeline(args)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000189 else:
Daniel Dunbar74727872009-01-06 01:35:44 +0000190 phases = self.buildNormalPipeline(args)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000191
192 if cccPrintPhases:
Daniel Dunbar74727872009-01-06 01:35:44 +0000193 self.printPhases(phases, args)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000194 sys.exit(0)
Daniel Dunbar4ed45ea2009-01-09 01:00:40 +0000195
Daniel Dunbar378530c2009-01-05 19:53:30 +0000196 if 0:
197 print Util.pprint(phases)
198
Daniel Dunbar74727872009-01-06 01:35:44 +0000199 jobs = self.bindPhases(phases, args)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000200
201 # FIXME: We should provide some basic sanity checking of the
202 # pipeline as a "verification" sort of stage. For example, the
203 # pipeline should never end up writing to an output file in two
204 # places (I think). The pipeline should also never end up writing
205 # to an output file that is an input.
206 #
207 # This is intended to just be a "verify" step, not a functionality
208 # step. It should catch things like the driver driver not
209 # preventing -save-temps, but it shouldn't change behavior (so we
210 # can turn it off in Release-Asserts builds).
211
212 # Print in -### syntax.
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000213 hasHashHashHash = args.getLastArg(self.parser.hashHashHashOption)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000214 if hasHashHashHash:
215 self.claim(hasHashHashHash)
216 for j in jobs.iterjobs():
217 if isinstance(j, Jobs.Command):
Daniel Dunbard87b6ec2009-01-12 19:36:35 +0000218 print >>sys.stderr, ' "%s"' % '" "'.join(j.getArgv())
Daniel Dunbar378530c2009-01-05 19:53:30 +0000219 elif isinstance(j, Jobs.PipedJob):
220 for c in j.commands:
Daniel Dunbard87b6ec2009-01-12 19:36:35 +0000221 print >>sys.stderr, ' "%s" %c' % ('" "'.join(c.getArgv()),
222 "| "[c is j.commands[-1]])
Daniel Dunbar378530c2009-01-05 19:53:30 +0000223 elif not isinstance(j, JobList):
224 raise ValueError,'Encountered unknown job.'
225 sys.exit(0)
226
Daniel Dunbar61320532009-02-22 01:23:52 +0000227 try:
228 try:
229 self.executeJobs(args, jobs)
230 except:
Daniel Dunbar5baec4d2009-02-23 23:37:18 +0000231 if not args.getLastArg(self.parser.saveTempsOption):
Daniel Dunbar1090fc22009-03-06 18:32:01 +0000232 # Fail if removing a result fails.
233 self.removeFiles(self.resultFiles, failOnError=True)
Daniel Dunbar61320532009-02-22 01:23:52 +0000234 raise
235 finally:
Daniel Dunbar1f76dea2009-03-06 18:35:43 +0000236 # Ignore failures in removing temporary files
237 self.removeFiles(self.tempFiles, failOnError=False)
Daniel Dunbar1090fc22009-03-06 18:32:01 +0000238
239 def removeFiles(self, fileList, failOnError=False):
240 for f in fileList:
241 try:
242 os.remove(f)
243 except OSError,e:
244 if failOnError:
245 import errno
246 if e.errno != errno.ENOENT:
247 raise
248 except:
249 if failOnError:
250 raise
251
Daniel Dunbar61320532009-02-22 01:23:52 +0000252 def executeJobs(self, args, jobs):
Daniel Dunbar8fd28cd2009-01-28 19:26:20 +0000253 vArg = args.getLastArg(self.parser.vOption)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000254 for j in jobs.iterjobs():
255 if isinstance(j, Jobs.Command):
Daniel Dunbar8fd28cd2009-01-28 19:26:20 +0000256 if vArg or self.cccEcho:
257 print >>sys.stderr, ' '.join(map(str,j.getArgv()))
Anders Carlsson76613bf2009-01-18 02:54:17 +0000258 sys.stderr.flush()
Daniel Dunbara95c6392009-02-19 22:59:57 +0000259 p = self.startSubprocess(j.getArgv(), j.executable)
260 res = p.wait()
Daniel Dunbar378530c2009-01-05 19:53:30 +0000261 if res:
262 sys.exit(res)
Daniel Dunbara95c6392009-02-19 22:59:57 +0000263
Daniel Dunbar378530c2009-01-05 19:53:30 +0000264 elif isinstance(j, Jobs.PipedJob):
Daniel Dunbare19ed8e2009-01-17 02:02:35 +0000265 procs = []
266 for sj in j.commands:
Daniel Dunbar8fd28cd2009-01-28 19:26:20 +0000267 if vArg or self.cccEcho:
268 print >> sys.stderr, ' '.join(map(str,sj.getArgv()))
Daniel Dunbare19ed8e2009-01-17 02:02:35 +0000269 sys.stdout.flush()
270
271 if not procs:
272 stdin = None
273 else:
274 stdin = procs[-1].stdout
275 if sj is j.commands[-1]:
276 stdout = None
277 else:
278 stdout = subprocess.PIPE
Daniel Dunbara95c6392009-02-19 22:59:57 +0000279
280 procs.append(self.startSubprocess(sj.getArgv(), sj.executable,
281 stdin=stdin,
282 stdout=stdout))
283
Daniel Dunbare19ed8e2009-01-17 02:02:35 +0000284 for proc in procs:
285 res = proc.wait()
286 if res:
287 sys.exit(res)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000288 else:
289 raise ValueError,'Encountered unknown job.'
290
Daniel Dunbara95c6392009-02-19 22:59:57 +0000291 def startSubprocess(self, argv, executable, **kwargs):
292 try:
293 return subprocess.Popen(argv, executable=executable, **kwargs)
294 except OSError, e:
295 self.warning("error trying to exec '%s': %s" %
296 (executable, e.args[1]))
297 sys.exit(1)
298
Daniel Dunbar378530c2009-01-05 19:53:30 +0000299 def claim(self, option):
300 # FIXME: Move to OptionList once introduced and implement.
301 pass
302
303 def warning(self, message):
Daniel Dunbara0026f22009-01-16 23:12:12 +0000304 print >>sys.stderr,'%s: %s' % (self.driverName, message)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000305
Daniel Dunbar74727872009-01-06 01:35:44 +0000306 def printOptions(self, args):
307 for i,arg in enumerate(args):
Daniel Dunbar74727872009-01-06 01:35:44 +0000308 if isinstance(arg, Arguments.MultipleValuesArg):
309 values = list(args.getValues(arg))
310 elif isinstance(arg, Arguments.ValueArg):
311 values = [args.getValue(arg)]
312 elif isinstance(arg, Arguments.JoinedAndSeparateValuesArg):
313 values = [args.getJoinedValue(arg), args.getSeparateValue(arg)]
Daniel Dunbar378530c2009-01-05 19:53:30 +0000314 else:
315 values = []
Daniel Dunbar927a5092009-01-06 02:30:10 +0000316 print 'Option %d - Name: "%s", Values: {%s}' % (i, arg.opt.name,
Daniel Dunbar378530c2009-01-05 19:53:30 +0000317 ', '.join(['"%s"' % v
318 for v in values]))
319
Daniel Dunbar74727872009-01-06 01:35:44 +0000320 def printPhases(self, phases, args):
Daniel Dunbar378530c2009-01-05 19:53:30 +0000321 def printPhase(p, f, steps, arch=None):
322 if p in steps:
323 return steps[p]
324 elif isinstance(p, Phases.BindArchAction):
325 for kid in p.inputs:
326 printPhase(kid, f, steps, p.arch)
327 steps[p] = len(steps)
328 return
329
330 if isinstance(p, Phases.InputAction):
331 phaseName = 'input'
Daniel Dunbar74727872009-01-06 01:35:44 +0000332 inputStr = '"%s"' % args.getValue(p.filename)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000333 else:
334 phaseName = p.phase.name
335 inputs = [printPhase(i, f, steps, arch)
336 for i in p.inputs]
337 inputStr = '{%s}' % ', '.join(map(str, inputs))
338 if arch is not None:
Daniel Dunbar74727872009-01-06 01:35:44 +0000339 phaseName += '-' + args.getValue(arch)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000340 steps[p] = index = len(steps)
341 print "%d: %s, %s, %s" % (index,phaseName,inputStr,p.type.name)
342 return index
343 steps = {}
344 for phase in phases:
345 printPhase(phase, sys.stdout, steps)
Daniel Dunbar8fd28cd2009-01-28 19:26:20 +0000346
347 def printVersion(self):
348 # FIXME: Print default target triple.
Mike Stump406abf62009-02-11 01:01:17 +0000349 vers = '$HeadURL$'
350 vers = vers.split('/tools/ccc')[0]
Mike Stump6bf3bd42009-02-11 01:11:36 +0000351 vers = vers.split('/clang/tools/clang')[0]
Mike Stump406abf62009-02-11 01:01:17 +0000352 vers = ' (' + vers[10:] + ')'
353 print >>sys.stderr,'ccc version 1.0' + vers
Daniel Dunbar378530c2009-01-05 19:53:30 +0000354
Daniel Dunbar74727872009-01-06 01:35:44 +0000355 def handleImmediateOptions(self, args):
Daniel Dunbar378530c2009-01-05 19:53:30 +0000356 # FIXME: Some driver Arguments are consumed right off the bat,
357 # like -dumpversion. Currently the gcc-dd handles these
358 # poorly, so we should be ok handling them upfront instead of
359 # after driver-driver level dispatching.
360 #
361 # FIXME: The actual order of these options in gcc is all over the
362 # place. The -dump ones seem to be first and in specification
363 # order, but there are other levels of precedence. For example,
364 # -print-search-dirs is evaluated before -print-prog-name=,
365 # regardless of order (and the last instance of -print-prog-name=
366 # wins verse itself).
367 #
368 # FIXME: Do we want to report "argument unused" type errors in the
369 # presence of things like -dumpmachine and -print-search-dirs?
370 # Probably not.
Daniel Dunbar8fd28cd2009-01-28 19:26:20 +0000371 if (args.getLastArg(self.parser.vOption) or
372 args.getLastArg(self.parser.hashHashHashOption)):
373 self.printVersion()
374 self.suppressMissingInputWarning = True
375
Daniel Dunbarf677a602009-01-21 02:03:52 +0000376 arg = (args.getLastArg(self.parser.dumpmachineOption) or
377 args.getLastArg(self.parser.dumpversionOption) or
378 args.getLastArg(self.parser.printSearchDirsOption))
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000379 if arg:
Daniel Dunbarf677a602009-01-21 02:03:52 +0000380 raise NotImplementedError('%s unsupported' % arg.opt.name)
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000381
Daniel Dunbarf677a602009-01-21 02:03:52 +0000382 arg = (args.getLastArg(self.parser.dumpspecsOption) or
383 args.getLastArg(self.parser.printMultiDirectoryOption) or
Daniel Dunbar73fb9072009-01-23 02:00:46 +0000384 args.getLastArg(self.parser.printMultiOsDirectoryOption) or
Daniel Dunbarf677a602009-01-21 02:03:52 +0000385 args.getLastArg(self.parser.printMultiLibOption))
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000386 if arg:
Daniel Dunbarf677a602009-01-21 02:03:52 +0000387 raise Arguments.InvalidArgumentsError('%s unsupported by this driver' % arg.opt.name)
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000388
389 arg = args.getLastArg(self.parser.printFileNameOption)
390 if arg:
Daniel Dunbarf677a602009-01-21 02:03:52 +0000391 print self.getFilePath(args.getValue(arg))
392 sys.exit(0)
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000393
394 arg = args.getLastArg(self.parser.printProgNameOption)
395 if arg:
Daniel Dunbarf677a602009-01-21 02:03:52 +0000396 print self.getProgramPath(args.getValue(arg))
397 sys.exit(0)
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000398
Daniel Dunbarf677a602009-01-21 02:03:52 +0000399 arg = args.getLastArg(self.parser.printLibgccFileNameOption)
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000400 if arg:
Daniel Dunbarf677a602009-01-21 02:03:52 +0000401 print self.getFilePath('libgcc.a')
402 sys.exit(0)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000403
Daniel Dunbar74727872009-01-06 01:35:44 +0000404 def buildNormalPipeline(self, args):
Daniel Dunbar90c72cd2009-01-21 01:07:49 +0000405 hasAnalyze = args.getLastArg(self.parser.analyzeOption)
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000406 hasCombine = args.getLastArg(self.parser.combineOption)
Daniel Dunbar34f60f62009-01-26 17:09:15 +0000407 hasEmitLLVM = args.getLastArg(self.parser.emitLLVMOption)
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000408 hasSyntaxOnly = args.getLastArg(self.parser.syntaxOnlyOption)
409 hasDashC = args.getLastArg(self.parser.cOption)
410 hasDashE = args.getLastArg(self.parser.EOption)
411 hasDashS = args.getLastArg(self.parser.SOption)
Daniel Dunbar445c46d2009-01-20 01:53:54 +0000412 hasDashM = args.getLastArg(self.parser.MOption)
413 hasDashMM = args.getLastArg(self.parser.MMOption)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000414
415 inputType = None
416 inputTypeOpt = None
417 inputs = []
418 for a in args:
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000419 if a.opt is self.parser.inputOption:
Daniel Dunbara0026f22009-01-16 23:12:12 +0000420 inputValue = args.getValue(a)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000421 if inputType is None:
Daniel Dunbara0026f22009-01-16 23:12:12 +0000422 base,ext = os.path.splitext(inputValue)
Daniel Dunbar6dbfa662009-02-05 23:44:44 +0000423 # stdin is handled specially.
424 if inputValue == '-':
425 if args.getLastArg(self.parser.EOption):
426 # Treat as a C input needing preprocessing
427 # (or Obj-C if over-ridden below).
428 klass = Types.CType
429 else:
430 raise Arguments.InvalidArgumentsError("-E or -x required when input is from standard input")
431 elif ext and ext in Types.kTypeSuffixMap:
Daniel Dunbar378530c2009-01-05 19:53:30 +0000432 klass = Types.kTypeSuffixMap[ext]
433 else:
434 # FIXME: Its not clear why we shouldn't just
435 # revert to unknown. I think this is more likely a
436 # bug / unintended behavior in gcc. Not very
437 # important though.
438 klass = Types.ObjectType
Daniel Dunbar6dbfa662009-02-05 23:44:44 +0000439
440 # -ObjC and -ObjC++ over-ride the default
441 # language, but only for "source files". We
442 # just treat everything that isn't a linker
443 # input as a source file.
444 #
445 # FIXME: Clean this up if we move the phase
446 # sequence into the type.
447 if klass is not Types.ObjectType:
448 if args.getLastArg(self.parser.ObjCOption):
449 klass = Types.ObjCType
450 elif args.getLastArg(self.parser.ObjCXXOption):
451 klass = Types.ObjCType
Daniel Dunbar378530c2009-01-05 19:53:30 +0000452 else:
453 assert inputTypeOpt is not None
454 self.claim(inputTypeOpt)
455 klass = inputType
Daniel Dunbara0026f22009-01-16 23:12:12 +0000456
457 # Check that the file exists. It isn't clear this is
458 # worth doing, since the tool presumably does this
459 # anyway, and this just adds an extra stat to the
460 # equation, but this is gcc compatible.
Daniel Dunbar34f60f62009-01-26 17:09:15 +0000461 if inputValue != '-' and not os.path.exists(inputValue):
Daniel Dunbara0026f22009-01-16 23:12:12 +0000462 self.warning("%s: No such file or directory" % inputValue)
463 else:
464 inputs.append((klass, a))
Daniel Dunbarfc2ad022009-01-12 03:33:58 +0000465 elif a.opt.isLinkerInput:
466 # Treat as a linker input.
Daniel Dunbar927a5092009-01-06 02:30:10 +0000467 #
468 # FIXME: This might not be good enough. We may
469 # need to introduce another type for this case, so
470 # that other code which needs to know the inputs
471 # handles this properly. Best not to try and lipo
472 # this, for example.
473 inputs.append((Types.ObjectType, a))
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000474 elif a.opt is self.parser.xOption:
Daniel Dunbar927a5092009-01-06 02:30:10 +0000475 inputTypeOpt = a
476 value = args.getValue(a)
477 if value in Types.kTypeSpecifierMap:
478 inputType = Types.kTypeSpecifierMap[value]
479 else:
480 # FIXME: How are we going to handle diagnostics.
481 self.warning("language %s not recognized" % value)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000482
Daniel Dunbar927a5092009-01-06 02:30:10 +0000483 # FIXME: Its not clear why we shouldn't just
484 # revert to unknown. I think this is more likely a
485 # bug / unintended behavior in gcc. Not very
486 # important though.
Daniel Dunbar6cb42052009-01-13 21:07:43 +0000487 inputType = Types.ObjectType
Daniel Dunbar378530c2009-01-05 19:53:30 +0000488
489 # We claim things here so that options for which we silently allow
490 # override only ever claim the used option.
491 if hasCombine:
492 self.claim(hasCombine)
493
494 finalPhase = Phases.Phase.eOrderPostAssemble
495 finalPhaseOpt = None
496
497 # Determine what compilation mode we are in.
Daniel Dunbar445c46d2009-01-20 01:53:54 +0000498 if hasDashE or hasDashM or hasDashMM:
Daniel Dunbar378530c2009-01-05 19:53:30 +0000499 finalPhase = Phases.Phase.eOrderPreprocess
500 finalPhaseOpt = hasDashE
Daniel Dunbar34f60f62009-01-26 17:09:15 +0000501 elif (hasAnalyze or hasSyntaxOnly or
502 hasEmitLLVM or hasDashS):
Daniel Dunbar90c72cd2009-01-21 01:07:49 +0000503 finalPhase = Phases.Phase.eOrderCompile
Daniel Dunbar34f60f62009-01-26 17:09:15 +0000504 finalPhaseOpt = (hasAnalyze or hasSyntaxOnly or
505 hasEmitLLVM or hasDashS)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000506 elif hasDashC:
507 finalPhase = Phases.Phase.eOrderAssemble
508 finalPhaseOpt = hasDashC
509
510 if finalPhaseOpt:
511 self.claim(finalPhaseOpt)
512
Daniel Dunbar80e48b72009-01-17 00:53:19 +0000513 # Reject -Z* at the top level for now.
514 arg = args.getLastArg(self.parser.ZOption)
515 if arg:
516 raise Arguments.InvalidArgumentsError("%s: unsupported use of internal gcc option" % ' '.join(args.render(arg)))
517
Daniel Dunbar8fd28cd2009-01-28 19:26:20 +0000518 if not inputs and not self.suppressMissingInputWarning:
Daniel Dunbara0026f22009-01-16 23:12:12 +0000519 raise Arguments.InvalidArgumentsError("no input files")
Daniel Dunbar378530c2009-01-05 19:53:30 +0000520
521 actions = []
522 linkerInputs = []
523 # FIXME: This is gross.
524 linkPhase = Phases.LinkPhase()
525 for klass,input in inputs:
526 # Figure out what step to start at.
527
528 # FIXME: This should be part of the input class probably?
529 # Altough it doesn't quite fit there either, things like
530 # asm-with-preprocess don't easily fit into a linear scheme.
531
532 # FIXME: I think we are going to end up wanting to just build
533 # a simple FSA which we run the inputs down.
534 sequence = []
535 if klass.preprocess:
536 sequence.append(Phases.PreprocessPhase())
537 if klass == Types.ObjectType:
538 sequence.append(linkPhase)
539 elif klass.onlyAssemble:
540 sequence.extend([Phases.AssemblePhase(),
541 linkPhase])
542 elif klass.onlyPrecompile:
543 sequence.append(Phases.PrecompilePhase())
Daniel Dunbar90c72cd2009-01-21 01:07:49 +0000544 elif hasAnalyze:
545 sequence.append(Phases.AnalyzePhase())
546 elif hasSyntaxOnly:
547 sequence.append(Phases.SyntaxOnlyPhase())
Daniel Dunbar34f60f62009-01-26 17:09:15 +0000548 elif hasEmitLLVM:
549 sequence.append(Phases.EmitLLVMPhase())
Daniel Dunbar378530c2009-01-05 19:53:30 +0000550 else:
551 sequence.extend([Phases.CompilePhase(),
552 Phases.AssemblePhase(),
553 linkPhase])
554
555 if sequence[0].order > finalPhase:
556 assert finalPhaseOpt and finalPhaseOpt.opt
557 # FIXME: Explain what type of input file is. Or just match
558 # gcc warning.
Daniel Dunbar74727872009-01-06 01:35:44 +0000559 self.warning("%s: %s input file unused when %s is present" % (args.getValue(input),
Daniel Dunbar378530c2009-01-05 19:53:30 +0000560 sequence[0].name,
561 finalPhaseOpt.opt.name))
562 else:
563 # Build the pipeline for this file.
564
565 current = Phases.InputAction(input, klass)
566 for transition in sequence:
567 # If the current action produces no output, or we are
568 # past what the user requested, we are done.
569 if (current.type is Types.NothingType or
570 transition.order > finalPhase):
571 break
572 else:
573 if isinstance(transition, Phases.PreprocessPhase):
574 assert isinstance(klass.preprocess, Types.InputType)
575 current = Phases.JobAction(transition,
576 [current],
577 klass.preprocess)
578 elif isinstance(transition, Phases.PrecompilePhase):
579 current = Phases.JobAction(transition,
580 [current],
581 Types.PCHType)
Daniel Dunbar90c72cd2009-01-21 01:07:49 +0000582 elif isinstance(transition, Phases.AnalyzePhase):
583 output = Types.PlistType
584 current = Phases.JobAction(transition,
585 [current],
586 output)
587 elif isinstance(transition, Phases.SyntaxOnlyPhase):
588 output = Types.NothingType
589 current = Phases.JobAction(transition,
590 [current],
591 output)
Daniel Dunbar34f60f62009-01-26 17:09:15 +0000592 elif isinstance(transition, Phases.EmitLLVMPhase):
593 if hasDashS:
594 output = Types.LLVMAsmType
595 else:
596 output = Types.LLVMBCType
597 current = Phases.JobAction(transition,
598 [current],
599 output)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000600 elif isinstance(transition, Phases.CompilePhase):
Daniel Dunbar90c72cd2009-01-21 01:07:49 +0000601 output = Types.AsmTypeNoPP
Daniel Dunbar378530c2009-01-05 19:53:30 +0000602 current = Phases.JobAction(transition,
603 [current],
604 output)
605 elif isinstance(transition, Phases.AssemblePhase):
606 current = Phases.JobAction(transition,
607 [current],
608 Types.ObjectType)
609 elif transition is linkPhase:
610 linkerInputs.append(current)
611 current = None
612 break
613 else:
614 raise RuntimeError,'Unrecognized transition: %s.' % transition
615 pass
616
617 if current is not None:
618 assert not isinstance(current, Phases.InputAction)
619 actions.append(current)
620
621 if linkerInputs:
622 actions.append(Phases.JobAction(linkPhase,
623 linkerInputs,
624 Types.ImageType))
625
626 return actions
627
Daniel Dunbar74727872009-01-06 01:35:44 +0000628 def buildPipeline(self, args):
Daniel Dunbar378530c2009-01-05 19:53:30 +0000629 # FIXME: We need to handle canonicalization of the specified arch.
630
Daniel Dunbar31c80812009-01-20 21:29:14 +0000631 archs = {}
Daniel Dunbar445c46d2009-01-20 01:53:54 +0000632 hasDashM = args.getLastArg(self.parser.MGroup)
Daniel Dunbara33176f2009-01-21 18:49:34 +0000633 hasSaveTemps = args.getLastArg(self.parser.saveTempsOption)
Daniel Dunbar74727872009-01-06 01:35:44 +0000634 for arg in args:
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000635 if arg.opt is self.parser.archOption:
Daniel Dunbar31c80812009-01-20 21:29:14 +0000636 # FIXME: Canonicalize this.
637 archName = args.getValue(arg)
638 archs[archName] = arg
639
640 archs = archs.values()
Daniel Dunbar378530c2009-01-05 19:53:30 +0000641 if not archs:
Daniel Dunbarf3d5ca02009-01-13 04:05:40 +0000642 archs.append(args.makeSeparateArg(self.hostInfo.getArchName(args),
Daniel Dunbar1ba90982009-01-07 18:54:26 +0000643 self.parser.archOption))
Daniel Dunbar378530c2009-01-05 19:53:30 +0000644
Daniel Dunbar74727872009-01-06 01:35:44 +0000645 actions = self.buildNormalPipeline(args)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000646
647 # FIXME: Use custom exception for this.
648 #
649 # FIXME: We killed off some others but these aren't yet detected in
650 # a functional manner. If we added information to jobs about which
651 # "auxiliary" files they wrote then we could detect the conflict
652 # these cause downstream.
653 if len(archs) > 1:
654 if hasDashM:
Daniel Dunbara0026f22009-01-16 23:12:12 +0000655 raise Arguments.InvalidArgumentsError("Cannot use -M options with multiple arch flags.")
Daniel Dunbar378530c2009-01-05 19:53:30 +0000656 elif hasSaveTemps:
Daniel Dunbara0026f22009-01-16 23:12:12 +0000657 raise Arguments.InvalidArgumentsError("Cannot use -save-temps with multiple arch flags.")
Daniel Dunbar378530c2009-01-05 19:53:30 +0000658
659 # Execute once per arch.
660 finalActions = []
661 for p in actions:
662 # Make sure we can lipo this kind of output. If not (and it
663 # is an actual output) then we disallow, since we can't
664 # create an output file with the right name without
665 # overwriting it. We could remove this oddity by just
666 # changing the output names to include the arch, which would
667 # also fix -save-temps. Compatibility wins for now.
668 #
669 # FIXME: Is this error substantially less useful than
670 # gcc-dd's? The main problem is that "Cannot use compiler
671 # output with multiple arch flags" won't make sense to most
672 # developers.
673 if (len(archs) > 1 and
674 p.type not in (Types.NothingType,Types.ObjectType,Types.ImageType)):
Daniel Dunbara0026f22009-01-16 23:12:12 +0000675 raise Arguments.InvalidArgumentsError('Cannot use %s output with multiple arch flags.' % p.type.name)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000676
677 inputs = []
678 for arch in archs:
679 inputs.append(Phases.BindArchAction(p, arch))
680
681 # Lipo if necessary. We do it this way because we need to set
682 # the arch flag so that -Xarch_ gets rewritten.
683 if len(inputs) == 1 or p.type == Types.NothingType:
684 finalActions.extend(inputs)
685 else:
686 finalActions.append(Phases.JobAction(Phases.LipoPhase(),
687 inputs,
688 p.type))
689
Daniel Dunbar378530c2009-01-05 19:53:30 +0000690 return finalActions
691
Daniel Dunbar74727872009-01-06 01:35:44 +0000692 def bindPhases(self, phases, args):
Daniel Dunbar378530c2009-01-05 19:53:30 +0000693 jobs = Jobs.JobList()
694
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000695 finalOutput = args.getLastArg(self.parser.oOption)
Daniel Dunbara33176f2009-01-21 18:49:34 +0000696 hasSaveTemps = args.getLastArg(self.parser.saveTempsOption)
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000697 hasNoIntegratedCPP = args.getLastArg(self.parser.noIntegratedCPPOption)
Daniel Dunbarf86e98a2009-01-12 09:23:15 +0000698 hasTraditionalCPP = args.getLastArg(self.parser.traditionalCPPOption)
Daniel Dunbare9f1a692009-01-06 06:12:13 +0000699 hasPipe = args.getLastArg(self.parser.pipeOption)
Daniel Dunbarfc2ad022009-01-12 03:33:58 +0000700
Daniel Dunbar378530c2009-01-05 19:53:30 +0000701 # We claim things here so that options for which we silently allow
702 # override only ever claim the used option.
703 if hasPipe:
704 self.claim(hasPipe)
705 # FIXME: Hack, override -pipe till we support it.
Daniel Dunbare19ed8e2009-01-17 02:02:35 +0000706 if hasSaveTemps:
707 self.warning('-pipe ignored because -save-temps specified')
708 hasPipe = None
Daniel Dunbar378530c2009-01-05 19:53:30 +0000709 # Claim these here. Its not completely accurate but any warnings
710 # about these being unused are likely to be noise anyway.
711 if hasSaveTemps:
712 self.claim(hasSaveTemps)
Daniel Dunbarf86e98a2009-01-12 09:23:15 +0000713
714 if hasTraditionalCPP:
715 self.claim(hasTraditionalCPP)
716 elif hasNoIntegratedCPP:
Daniel Dunbar378530c2009-01-05 19:53:30 +0000717 self.claim(hasNoIntegratedCPP)
Daniel Dunbarf86e98a2009-01-12 09:23:15 +0000718
Daniel Dunbare5fb6792009-01-13 06:25:31 +0000719 # FIXME: Move to... somewhere else.
Daniel Dunbar378530c2009-01-05 19:53:30 +0000720 class InputInfo:
721 def __init__(self, source, type, baseInput):
722 self.source = source
723 self.type = type
724 self.baseInput = baseInput
725
726 def __repr__(self):
727 return '%s(%r, %r, %r)' % (self.__class__.__name__,
728 self.source, self.type, self.baseInput)
Daniel Dunbare5fb6792009-01-13 06:25:31 +0000729
730 def isOriginalInput(self):
731 return self.source is self.baseInput
Daniel Dunbar378530c2009-01-05 19:53:30 +0000732
Daniel Dunbarb3492762009-01-13 18:51:26 +0000733 def createJobs(tc, phase,
734 canAcceptPipe=False, atTopLevel=False, arch=None,
Daniel Dunbar31c80812009-01-20 21:29:14 +0000735 tcArgs=None, linkingOutput=None):
Daniel Dunbar378530c2009-01-05 19:53:30 +0000736 if isinstance(phase, Phases.InputAction):
737 return InputInfo(phase.filename, phase.type, phase.filename)
738 elif isinstance(phase, Phases.BindArchAction):
Daniel Dunbar74727872009-01-06 01:35:44 +0000739 archName = args.getValue(phase.arch)
Daniel Dunbar758cf642009-01-11 22:06:22 +0000740 tc = self.hostInfo.getToolChainForArch(archName)
Daniel Dunbarb3492762009-01-13 18:51:26 +0000741 return createJobs(tc, phase.inputs[0],
742 canAcceptPipe, atTopLevel, phase.arch,
Daniel Dunbar31c80812009-01-20 21:29:14 +0000743 None, linkingOutput)
Daniel Dunbarb3492762009-01-13 18:51:26 +0000744
745 if tcArgs is None:
746 tcArgs = tc.translateArgs(args, arch)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000747
748 assert isinstance(phase, Phases.JobAction)
Daniel Dunbar758cf642009-01-11 22:06:22 +0000749 tool = tc.selectTool(phase)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000750
751 # See if we should use an integrated CPP. We only use an
752 # integrated cpp when we have exactly one input, since this is
753 # the only use case we care about.
754 useIntegratedCPP = False
755 inputList = phase.inputs
756 if (not hasNoIntegratedCPP and
Daniel Dunbarf86e98a2009-01-12 09:23:15 +0000757 not hasTraditionalCPP and
Daniel Dunbar378530c2009-01-05 19:53:30 +0000758 not hasSaveTemps and
759 tool.hasIntegratedCPP()):
760 if (len(phase.inputs) == 1 and
Daniel Dunbar7d494092009-01-20 00:47:24 +0000761 isinstance(phase.inputs[0], Phases.JobAction) and
Daniel Dunbar378530c2009-01-05 19:53:30 +0000762 isinstance(phase.inputs[0].phase, Phases.PreprocessPhase)):
763 useIntegratedCPP = True
764 inputList = phase.inputs[0].inputs
765
766 # Only try to use pipes when exactly one input.
Daniel Dunbar1e46f552009-01-22 23:19:32 +0000767 attemptToPipeInput = len(inputList) == 1 and tool.acceptsPipedInput()
768 inputs = [createJobs(tc, p, attemptToPipeInput, False,
Daniel Dunbar31c80812009-01-20 21:29:14 +0000769 arch, tcArgs, linkingOutput)
Daniel Dunbar758cf642009-01-11 22:06:22 +0000770 for p in inputList]
Daniel Dunbar378530c2009-01-05 19:53:30 +0000771
772 # Determine if we should output to a pipe.
773 canOutputToPipe = canAcceptPipe and tool.canPipeOutput()
774 outputToPipe = False
775 if canOutputToPipe:
776 # Some things default to writing to a pipe if the final
777 # phase and there was no user override.
778 #
779 # FIXME: What is the best way to handle this?
Daniel Dunbar1b391272009-01-18 21:35:24 +0000780 if atTopLevel:
781 if (isinstance(phase.phase, Phases.PreprocessPhase) and
782 not finalOutput):
783 outputToPipe = True
Daniel Dunbar378530c2009-01-05 19:53:30 +0000784 elif hasPipe:
785 outputToPipe = True
786
787 # Figure out where to put the job (pipes).
788 jobList = jobs
Daniel Dunbar1e46f552009-01-22 23:19:32 +0000789 if isinstance(inputs[0].source, Jobs.PipedJob):
Daniel Dunbar378530c2009-01-05 19:53:30 +0000790 jobList = inputs[0].source
Daniel Dunbar31c80812009-01-20 21:29:14 +0000791
Daniel Dunbar378530c2009-01-05 19:53:30 +0000792 baseInput = inputs[0].baseInput
Daniel Dunbard9b7a742009-01-21 00:05:15 +0000793 output,jobList = self.getOutputName(phase, outputToPipe, jobs, jobList, baseInput,
794 args, atTopLevel, hasSaveTemps, finalOutput)
Daniel Dunbarb421dba2009-01-07 18:40:45 +0000795 tool.constructJob(phase, arch, jobList, inputs, output, phase.type,
Daniel Dunbar31c80812009-01-20 21:29:14 +0000796 tcArgs, linkingOutput)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000797
798 return InputInfo(output, phase.type, baseInput)
799
800 # It is an error to provide a -o option if we are making multiple
801 # output files.
802 if finalOutput and len([a for a in phases if a.type is not Types.NothingType]) > 1:
Daniel Dunbara0026f22009-01-16 23:12:12 +0000803 raise Arguments.InvalidArgumentsError("cannot specify -o when generating multiple files")
Daniel Dunbar378530c2009-01-05 19:53:30 +0000804
805 for phase in phases:
Daniel Dunbar31c80812009-01-20 21:29:14 +0000806 # If we are linking an image for multiple archs then the
807 # linker wants -arch_multiple and -final_output <final image
808 # name>. Unfortunately this requires some gross contortions.
809 #
810 # FIXME: This is a hack; find a cleaner way to integrate this
811 # into the process.
812 linkingOutput = None
813 if (isinstance(phase, Phases.JobAction) and
814 isinstance(phase.phase, Phases.LipoPhase)):
815 finalOutput = args.getLastArg(self.parser.oOption)
816 if finalOutput:
817 linkingOutput = finalOutput
818 else:
819 linkingOutput = args.makeSeparateArg('a.out',
820 self.parser.oOption)
821
Daniel Dunbarb3492762009-01-13 18:51:26 +0000822 createJobs(self.toolChain, phase,
Daniel Dunbar31c80812009-01-20 21:29:14 +0000823 canAcceptPipe=True, atTopLevel=True,
824 linkingOutput=linkingOutput)
Daniel Dunbar378530c2009-01-05 19:53:30 +0000825
826 return jobs
Daniel Dunbar31c80812009-01-20 21:29:14 +0000827
828 def getOutputName(self, phase, outputToPipe, jobs, jobList, baseInput,
829 args, atTopLevel, hasSaveTemps, finalOutput):
830 # Figure out where to put the output.
831 if phase.type == Types.NothingType:
832 output = None
833 elif outputToPipe:
834 if isinstance(jobList, Jobs.PipedJob):
835 output = jobList
836 else:
837 jobList = output = Jobs.PipedJob([])
838 jobs.addJob(output)
839 else:
840 # Figure out what the derived output location would be.
Daniel Dunbar31c80812009-01-20 21:29:14 +0000841 if phase.type is Types.ImageType:
842 namedOutput = "a.out"
843 else:
Daniel Dunbar31c80812009-01-20 21:29:14 +0000844 assert phase.type.tempSuffix is not None
Daniel Dunbar0e8c48c2009-02-13 17:42:34 +0000845 inputName = args.getValue(baseInput)
846 if phase.type.appendSuffix:
847 namedOutput = inputName + '.' + phase.type.tempSuffix
848 else:
849 base,_ = os.path.splitext(inputName)
850 namedOutput = base + '.' + phase.type.tempSuffix
Daniel Dunbar31c80812009-01-20 21:29:14 +0000851
Daniel Dunbar61320532009-02-22 01:23:52 +0000852 isTemp = False
Daniel Dunbar31c80812009-01-20 21:29:14 +0000853 # Output to user requested destination?
854 if atTopLevel and finalOutput:
855 output = finalOutput
Daniel Dunbar61320532009-02-22 01:23:52 +0000856 self.resultFiles.append(args.getValue(finalOutput))
857
Daniel Dunbar31c80812009-01-20 21:29:14 +0000858 # Contruct a named destination?
859 elif atTopLevel or hasSaveTemps:
860 # As an annoying special case, pch generation
861 # doesn't strip the pathname.
862 if phase.type is Types.PCHType:
863 outputName = namedOutput
864 else:
865 outputName = os.path.basename(namedOutput)
866 output = args.makeSeparateArg(outputName,
867 self.parser.oOption)
Daniel Dunbar61320532009-02-22 01:23:52 +0000868 self.resultFiles.append(outputName)
869
Daniel Dunbar31c80812009-01-20 21:29:14 +0000870 else:
871 # Output to temp file...
872 fd,filename = tempfile.mkstemp(suffix='.'+phase.type.tempSuffix)
873 output = args.makeSeparateArg(filename,
874 self.parser.oOption)
Daniel Dunbar61320532009-02-22 01:23:52 +0000875 self.tempFiles.append(filename)
Daniel Dunbard9b7a742009-01-21 00:05:15 +0000876 return output,jobList