aboutsummaryrefslogtreecommitdiff
path: root/tools/ccc/ccclib/Driver.py
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2009-05-02 22:13:56 +0000
committerDaniel Dunbar <daniel@zuster.org>2009-05-02 22:13:56 +0000
commitb83074dfa3885da91543e54e7dcc0ac68e4e4a27 (patch)
tree0db9fafa795e50ba070af61ea0b7c80dba2b11c5 /tools/ccc/ccclib/Driver.py
parent08617b1b475e5ae9c61c9b3536cf712283647284 (diff)
ccc is dead.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@70649 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/ccc/ccclib/Driver.py')
-rw-r--r--tools/ccc/ccclib/Driver.py873
1 files changed, 0 insertions, 873 deletions
diff --git a/tools/ccc/ccclib/Driver.py b/tools/ccc/ccclib/Driver.py
deleted file mode 100644
index 92f7c87ca0..0000000000
--- a/tools/ccc/ccclib/Driver.py
+++ /dev/null
@@ -1,873 +0,0 @@
-import os
-import platform
-import subprocess
-import sys
-import tempfile
-from pprint import pprint
-
-###
-
-import Arguments
-import Jobs
-import HostInfo
-import Phases
-import Tools
-import Types
-import Util
-
-# FIXME: Clean up naming of options and arguments. Decide whether to
-# rename Option and be consistent about use of Option/Arg.
-
-####
-
-class Driver(object):
- def __init__(self, driverName, driverDir):
- self.driverName = driverName
- self.driverDir = driverDir
- self.hostInfo = None
- self.parser = Arguments.OptionParser()
- self.cccHostBits = self.cccHostMachine = None
- self.cccHostSystem = self.cccHostRelease = None
- self.cccCXX = False
- self.cccEcho = False
- self.cccNoClang = self.cccNoClangCXX = self.cccNoClangPreprocessor = False
- self.cccClangArchs = None
-
- # Certain options suppress the 'no input files' warning.
- self.suppressMissingInputWarning = False
-
- # Temporary files used in compilation, removed on exit.
- self.tempFiles = []
- # Result files produced by compilation, removed on error.
- self.resultFiles = []
-
- # Host queries which can be forcibly over-riden by the user for
- # testing purposes.
- #
- # FIXME: We should make sure these are drawn from a fixed set so
- # that nothing downstream ever plays a guessing game.
-
- def getHostBits(self):
- if self.cccHostBits:
- return self.cccHostBits
-
- return platform.architecture()[0].replace('bit','')
-
- def getHostMachine(self):
- if self.cccHostMachine:
- return self.cccHostMachine
-
- machine = platform.machine()
- # Normalize names.
- if machine == 'Power Macintosh':
- return 'ppc'
- if machine == 'x86_64':
- return 'i386'
- return machine
-
- def getHostSystemName(self):
- if self.cccHostSystem:
- return self.cccHostSystem
-
- return platform.system().lower()
-
- def getHostReleaseName(self):
- if self.cccHostRelease:
- return self.cccHostRelease
-
- return platform.release()
-
- def getenvBool(self, name):
- var = os.getenv(name)
- if not var:
- return False
-
- try:
- return bool(int(var))
- except:
- return False
-
- ###
-
- def getFilePath(self, name, toolChain=None):
- tc = toolChain or self.toolChain
- for p in tc.filePathPrefixes:
- path = os.path.join(p, name)
- if os.path.exists(path):
- return path
- return name
-
- def getProgramPath(self, name, toolChain=None):
- tc = toolChain or self.toolChain
- for p in tc.programPathPrefixes:
- path = os.path.join(p, name)
- if os.path.exists(path):
- return path
- return name
-
- ###
-
- def run(self, argv):
- # FIXME: Things to support from environment: GCC_EXEC_PREFIX,
- # COMPILER_PATH, LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS,
- # QA_OVERRIDE_GCC3_OPTIONS, ...?
-
- # FIXME: -V and -b processing
-
- # Handle some special -ccc- options used for testing which are
- # only allowed at the beginning of the command line.
- cccPrintOptions = False
- cccPrintPhases = False
-
- # FIXME: How to handle override of host? ccc specific options?
- # Abuse -b?
- arg = os.getenv('CCC_ADD_ARGS')
- if arg:
- args = filter(None, map(str.strip, arg.split(',')))
- argv = args + argv
-
- while argv and argv[0].startswith('-ccc-'):
- fullOpt,argv = argv[0],argv[1:]
- opt = fullOpt[5:]
-
- if opt == 'print-options':
- cccPrintOptions = True
- elif opt == 'print-phases':
- cccPrintPhases = True
- elif opt == 'cxx':
- self.cccCXX = True
- elif opt == 'echo':
- self.cccEcho = True
-
- elif opt == 'no-clang':
- self.cccNoClang = True
- elif opt == 'no-clang-cxx':
- self.cccNoClangCXX = True
- elif opt == 'no-clang-cpp':
- self.cccNoClangPreprocessor = True
- elif opt == 'clang-archs':
- self.cccClangArchs,argv = argv[0].split(','),argv[1:]
-
- elif opt == 'host-bits':
- self.cccHostBits,argv = argv[0],argv[1:]
- elif opt == 'host-machine':
- self.cccHostMachine,argv = argv[0],argv[1:]
- elif opt == 'host-system':
- self.cccHostSystem,argv = argv[0],argv[1:]
- elif opt == 'host-release':
- self.cccHostRelease,argv = argv[0],argv[1:]
- elif opt == 'host-triple':
- # This is a complete hack, but only exists for testing
- # compatibility with the new driver. We will be six
- # feet under soon enough.
- triple,argv = argv[0],argv[1:]
- self.cccHostMachine,_,self.cccHostSystem = triple.split('-', 2)
- if self.cccHostSystem.startswith('darwin'):
- self.cccHostSystem = 'darwin'
- self.cccHostRelease = '10.5.0'
- if self.cccHostMachine == 'x86_64':
- self.cccHostMachine = 'i386'
- self.cccHostBits = '64'
- elif self.cccHostMachine == 'i386':
- self.cccHostBits = '32'
- else:
- raise Arguments.InvalidArgumentsError("invalid option: %r" % fullOpt)
-
- self.hostInfo = HostInfo.getHostInfo(self)
- self.toolChain = self.hostInfo.getToolChain()
-
- args = self.parser.parseArgs(argv)
-
- # FIXME: Ho hum I have just realized -Xarch_ is broken. We really
- # need to reparse the Arguments after they have been expanded by
- # -Xarch. How is this going to work?
- #
- # Scratch that, we aren't going to do that; it really disrupts the
- # organization, doesn't consistently work with gcc-dd, and is
- # confusing. Instead we are going to enforce that -Xarch_ is only
- # used with options which do not alter the driver behavior. Let's
- # hope this is ok, because the current architecture is a little
- # tied to it.
-
- if cccPrintOptions:
- self.printOptions(args)
- sys.exit(0)
-
- self.handleImmediateOptions(args)
-
- if self.hostInfo.useDriverDriver():
- phases = self.buildPipeline(args)
- else:
- phases = self.buildNormalPipeline(args)
-
- if cccPrintPhases:
- self.printPhases(phases, args)
- sys.exit(0)
-
- if 0:
- print Util.pprint(phases)
-
- jobs = self.bindPhases(phases, args)
-
- # FIXME: We should provide some basic sanity checking of the
- # pipeline as a "verification" sort of stage. For example, the
- # pipeline should never end up writing to an output file in two
- # places (I think). The pipeline should also never end up writing
- # to an output file that is an input.
- #
- # This is intended to just be a "verify" step, not a functionality
- # step. It should catch things like the driver driver not
- # preventing -save-temps, but it shouldn't change behavior (so we
- # can turn it off in Release-Asserts builds).
-
- # Print in -### syntax.
- hasHashHashHash = args.getLastArg(self.parser.hashHashHashOption)
- if hasHashHashHash:
- self.claim(hasHashHashHash)
- for j in jobs.iterjobs():
- if isinstance(j, Jobs.Command):
- print >>sys.stderr, ' "%s"' % '" "'.join(j.getArgv())
- elif isinstance(j, Jobs.PipedJob):
- for c in j.commands:
- print >>sys.stderr, ' "%s" %c' % ('" "'.join(c.getArgv()),
- "| "[c is j.commands[-1]])
- elif not isinstance(j, JobList):
- raise ValueError,'Encountered unknown job.'
- sys.exit(0)
-
- try:
- try:
- self.executeJobs(args, jobs)
- except:
- if not args.getLastArg(self.parser.saveTempsOption):
- # Fail if removing a result fails.
- self.removeFiles(self.resultFiles, failOnError=True)
- raise
- finally:
- # Ignore failures in removing temporary files
- self.removeFiles(self.tempFiles, failOnError=False)
-
- def removeFiles(self, fileList, failOnError=False):
- for f in fileList:
- try:
- os.remove(f)
- except OSError,e:
- if failOnError:
- import errno
- if e.errno != errno.ENOENT:
- raise
- except:
- if failOnError:
- raise
-
- def executeJobs(self, args, jobs):
- vArg = args.getLastArg(self.parser.vOption)
- for j in jobs.iterjobs():
- if isinstance(j, Jobs.Command):
- if vArg or self.cccEcho:
- print >>sys.stderr, ' '.join(map(str,j.getArgv()))
- sys.stderr.flush()
- p = self.startSubprocess(j.getArgv(), j.executable)
- res = p.wait()
- if res:
- sys.exit(res)
-
- elif isinstance(j, Jobs.PipedJob):
- procs = []
- for sj in j.commands:
- if vArg or self.cccEcho:
- print >> sys.stderr, ' '.join(map(str,sj.getArgv()))
- sys.stdout.flush()
-
- if not procs:
- stdin = None
- else:
- stdin = procs[-1].stdout
- if sj is j.commands[-1]:
- stdout = None
- else:
- stdout = subprocess.PIPE
-
- procs.append(self.startSubprocess(sj.getArgv(), sj.executable,
- stdin=stdin,
- stdout=stdout))
-
- for proc in procs:
- res = proc.wait()
- if res:
- sys.exit(res)
- else:
- raise ValueError,'Encountered unknown job.'
-
- def startSubprocess(self, argv, executable, **kwargs):
- try:
- return subprocess.Popen(argv, executable=executable, **kwargs)
- except OSError, e:
- self.warning("error trying to exec '%s': %s" %
- (executable, e.args[1]))
- sys.exit(1)
-
- def claim(self, option):
- # FIXME: Move to OptionList once introduced and implement.
- pass
-
- def warning(self, message):
- print >>sys.stderr,'%s: %s' % (self.driverName, message)
-
- def printOptions(self, args):
- for i,arg in enumerate(args):
- if isinstance(arg, Arguments.MultipleValuesArg):
- values = list(args.getValues(arg))
- elif isinstance(arg, Arguments.ValueArg):
- values = [args.getValue(arg)]
- elif isinstance(arg, Arguments.JoinedAndSeparateValuesArg):
- values = [args.getJoinedValue(arg), args.getSeparateValue(arg)]
- else:
- values = []
- print 'Option %d - Name: "%s", Values: {%s}' % (i, arg.opt.name,
- ', '.join(['"%s"' % v
- for v in values]))
-
- def printPhases(self, phases, args):
- def printPhase(p, f, steps):
- if p in steps:
- return steps[p]
-
- if isinstance(p, Phases.InputAction):
- phaseName = 'input'
- inputStr = '"%s"' % args.getValue(p.filename)
- elif isinstance(p, Phases.BindArchAction):
- phaseName = 'bind-arch'
- inputs = [printPhase(i, f, steps)
- for i in p.inputs]
- inputStr = '"%s", {%s}' % (args.getValue(p.arch),
- ', '.join(map(str, inputs)))
- else:
- phaseName = p.phase.name
- inputs = [printPhase(i, f, steps)
- for i in p.inputs]
- inputStr = '{%s}' % ', '.join(map(str, inputs))
- steps[p] = index = len(steps)
- print "%d: %s, %s, %s" % (index,phaseName,inputStr,p.type.name)
- return index
- steps = {}
- for phase in phases:
- printPhase(phase, sys.stdout, steps)
-
- def printVersion(self):
- # FIXME: Print default target triple.
- vers = '$HeadURL$'
- vers = vers.split('/tools/ccc')[0]
- vers = vers.split('/clang/tools/clang')[0]
- vers = ' (' + vers[10:] + ')'
- print >>sys.stderr,'ccc version 1.0' + vers
-
- def handleImmediateOptions(self, args):
- # FIXME: Some driver Arguments are consumed right off the bat,
- # like -dumpversion. Currently the gcc-dd handles these
- # poorly, so we should be ok handling them upfront instead of
- # after driver-driver level dispatching.
- #
- # FIXME: The actual order of these options in gcc is all over the
- # place. The -dump ones seem to be first and in specification
- # order, but there are other levels of precedence. For example,
- # -print-search-dirs is evaluated before -print-prog-name=,
- # regardless of order (and the last instance of -print-prog-name=
- # wins verse itself).
- #
- # FIXME: Do we want to report "argument unused" type errors in the
- # presence of things like -dumpmachine and -print-search-dirs?
- # Probably not.
- if (args.getLastArg(self.parser.vOption) or
- args.getLastArg(self.parser.hashHashHashOption)):
- self.printVersion()
- self.suppressMissingInputWarning = True
-
- arg = args.getLastArg(self.parser.printFileNameOption)
- if arg:
- print self.getFilePath(args.getValue(arg))
- sys.exit(0)
-
- arg = args.getLastArg(self.parser.printProgNameOption)
- if arg:
- print self.getProgramPath(args.getValue(arg))
- sys.exit(0)
-
- arg = args.getLastArg(self.parser.printLibgccFileNameOption)
- if arg:
- print self.getFilePath('libgcc.a')
- sys.exit(0)
-
- def buildNormalPipeline(self, args):
- hasAnalyze = args.getLastArg(self.parser.analyzeOption)
- hasCombine = args.getLastArg(self.parser.combineOption)
- hasEmitLLVM = args.getLastArg(self.parser.emitLLVMOption)
- hasSyntaxOnly = args.getLastArg(self.parser.syntaxOnlyOption)
- hasDashC = args.getLastArg(self.parser.cOption)
- hasDashE = args.getLastArg(self.parser.EOption)
- hasDashS = args.getLastArg(self.parser.SOption)
- hasDashM = args.getLastArg(self.parser.MOption)
- hasDashMM = args.getLastArg(self.parser.MMOption)
-
- inputType = None
- inputTypeOpt = None
- inputs = []
- for a in args:
- if a.opt is self.parser.inputOption:
- inputValue = args.getValue(a)
- if inputType is None:
- base,ext = os.path.splitext(inputValue)
- # stdin is handled specially.
- if inputValue == '-':
- if args.getLastArg(self.parser.EOption):
- # Treat as a C input needing preprocessing
- # (or Obj-C if over-ridden below).
- klass = Types.CType
- else:
- raise Arguments.InvalidArgumentsError("-E or -x required when input is from standard input")
- elif ext and ext in Types.kTypeSuffixMap:
- klass = self.hostInfo.lookupTypeForExtension(ext)
- else:
- # FIXME: Its not clear why we shouldn't just
- # revert to unknown. I think this is more likely a
- # bug / unintended behavior in gcc. Not very
- # important though.
- klass = Types.ObjectType
-
- # -ObjC and -ObjC++ over-ride the default
- # language, but only for "source files". We
- # just treat everything that isn't a linker
- # input as a source file.
- #
- # FIXME: Clean this up if we move the phase
- # sequence into the type.
- if klass is not Types.ObjectType:
- if args.getLastArg(self.parser.ObjCOption):
- klass = Types.ObjCType
- elif args.getLastArg(self.parser.ObjCXXOption):
- klass = Types.ObjCType
- else:
- assert inputTypeOpt is not None
- self.claim(inputTypeOpt)
- klass = inputType
-
- # Check that the file exists. It isn't clear this is
- # worth doing, since the tool presumably does this
- # anyway, and this just adds an extra stat to the
- # equation, but this is gcc compatible.
- if inputValue != '-' and not os.path.exists(inputValue):
- self.warning("%s: No such file or directory" % inputValue)
- else:
- inputs.append((klass, a))
- elif a.opt.isLinkerInput:
- # Treat as a linker input.
- #
- # FIXME: This might not be good enough. We may
- # need to introduce another type for this case, so
- # that other code which needs to know the inputs
- # handles this properly. Best not to try and lipo
- # this, for example.
- inputs.append((Types.ObjectType, a))
- elif a.opt is self.parser.xOption:
- inputTypeOpt = a
- value = args.getValue(a)
- if value in Types.kTypeSpecifierMap:
- inputType = Types.kTypeSpecifierMap[value]
- else:
- # FIXME: How are we going to handle diagnostics.
- self.warning("language %s not recognized" % value)
-
- # FIXME: Its not clear why we shouldn't just
- # revert to unknown. I think this is more likely a
- # bug / unintended behavior in gcc. Not very
- # important though.
- inputType = Types.ObjectType
-
- # We claim things here so that options for which we silently allow
- # override only ever claim the used option.
- if hasCombine:
- self.claim(hasCombine)
-
- finalPhase = Phases.Phase.eOrderPostAssemble
- finalPhaseOpt = None
-
- # Determine what compilation mode we are in.
- if hasDashE or hasDashM or hasDashMM:
- finalPhase = Phases.Phase.eOrderPreprocess
- finalPhaseOpt = hasDashE
- elif (hasAnalyze or hasSyntaxOnly or
- hasEmitLLVM or hasDashS):
- finalPhase = Phases.Phase.eOrderCompile
- finalPhaseOpt = (hasAnalyze or hasSyntaxOnly or
- hasEmitLLVM or hasDashS)
- elif hasDashC:
- finalPhase = Phases.Phase.eOrderAssemble
- finalPhaseOpt = hasDashC
-
- if finalPhaseOpt:
- self.claim(finalPhaseOpt)
-
- # Reject -Z* at the top level for now.
- arg = args.getLastArg(self.parser.ZOption)
- if arg:
- raise Arguments.InvalidArgumentsError("%s: unsupported use of internal gcc option" % ' '.join(args.render(arg)))
-
- if not inputs and not self.suppressMissingInputWarning:
- raise Arguments.InvalidArgumentsError("no input files")
-
- actions = []
- linkerInputs = []
- # FIXME: This is gross.
- linkPhase = Phases.LinkPhase()
- for klass,input in inputs:
- # Figure out what step to start at.
-
- # FIXME: This should be part of the input class probably?
- # Altough it doesn't quite fit there either, things like
- # asm-with-preprocess don't easily fit into a linear scheme.
-
- # FIXME: I think we are going to end up wanting to just build
- # a simple FSA which we run the inputs down.
- sequence = []
- if klass.preprocess:
- sequence.append(Phases.PreprocessPhase())
- if klass == Types.ObjectType:
- sequence.append(linkPhase)
- elif klass.onlyAssemble:
- sequence.extend([Phases.AssemblePhase(),
- linkPhase])
- elif klass.onlyPrecompile:
- sequence.append(Phases.PrecompilePhase())
- elif hasAnalyze:
- sequence.append(Phases.AnalyzePhase())
- elif hasSyntaxOnly:
- sequence.append(Phases.SyntaxOnlyPhase())
- elif hasEmitLLVM:
- sequence.append(Phases.EmitLLVMPhase())
- else:
- sequence.extend([Phases.CompilePhase(),
- Phases.AssemblePhase(),
- linkPhase])
-
- if sequence[0].order > finalPhase:
- assert finalPhaseOpt and finalPhaseOpt.opt
- # FIXME: Explain what type of input file is. Or just match
- # gcc warning.
- self.warning("%s: %s input file unused when %s is present" % (args.getValue(input),
- sequence[0].name,
- finalPhaseOpt.opt.name))
- else:
- # Build the pipeline for this file.
-
- current = Phases.InputAction(input, klass)
- for transition in sequence:
- # If the current action produces no output, or we are
- # past what the user requested, we are done.
- if (current.type is Types.NothingType or
- transition.order > finalPhase):
- break
- else:
- if isinstance(transition, Phases.PreprocessPhase):
- assert isinstance(klass.preprocess, Types.InputType)
- current = Phases.JobAction(transition,
- [current],
- klass.preprocess)
- elif isinstance(transition, Phases.PrecompilePhase):
- current = Phases.JobAction(transition,
- [current],
- Types.PCHType)
- elif isinstance(transition, Phases.AnalyzePhase):
- output = Types.PlistType
- current = Phases.JobAction(transition,
- [current],
- output)
- elif isinstance(transition, Phases.SyntaxOnlyPhase):
- output = Types.NothingType
- current = Phases.JobAction(transition,
- [current],
- output)
- elif isinstance(transition, Phases.EmitLLVMPhase):
- if hasDashS:
- output = Types.LLVMAsmType
- else:
- output = Types.LLVMBCType
- current = Phases.JobAction(transition,
- [current],
- output)
- elif isinstance(transition, Phases.CompilePhase):
- output = Types.AsmTypeNoPP
- current = Phases.JobAction(transition,
- [current],
- output)
- elif isinstance(transition, Phases.AssemblePhase):
- current = Phases.JobAction(transition,
- [current],
- Types.ObjectType)
- elif transition is linkPhase:
- linkerInputs.append(current)
- current = None
- break
- else:
- raise RuntimeError,'Unrecognized transition: %s.' % transition
- pass
-
- if current is not None:
- assert not isinstance(current, Phases.InputAction)
- actions.append(current)
-
- if linkerInputs:
- actions.append(Phases.JobAction(linkPhase,
- linkerInputs,
- Types.ImageType))
-
- return actions
-
- def buildPipeline(self, args):
- # FIXME: We need to handle canonicalization of the specified arch.
-
- archs = {}
- hasDashM = args.getLastArg(self.parser.MGroup)
- hasSaveTemps = args.getLastArg(self.parser.saveTempsOption)
- for arg in args:
- if arg.opt is self.parser.archOption:
- # FIXME: Canonicalize this.
- archName = args.getValue(arg)
- archs[archName] = arg
-
- archs = archs.values()
- if not archs:
- archs.append(args.makeSeparateArg(self.hostInfo.getArchName(args),
- self.parser.archOption))
-
- actions = self.buildNormalPipeline(args)
-
- # FIXME: Use custom exception for this.
- #
- # FIXME: We killed off some others but these aren't yet detected in
- # a functional manner. If we added information to jobs about which
- # "auxiliary" files they wrote then we could detect the conflict
- # these cause downstream.
- if len(archs) > 1:
- if hasDashM:
- raise Arguments.InvalidArgumentsError("Cannot use -M options with multiple arch flags.")
- elif hasSaveTemps:
- raise Arguments.InvalidArgumentsError("Cannot use -save-temps with multiple arch flags.")
-
- # Execute once per arch.
- finalActions = []
- for p in actions:
- # Make sure we can lipo this kind of output. If not (and it
- # is an actual output) then we disallow, since we can't
- # create an output file with the right name without
- # overwriting it. We could remove this oddity by just
- # changing the output names to include the arch, which would
- # also fix -save-temps. Compatibility wins for now.
- #
- # FIXME: Is this error substantially less useful than
- # gcc-dd's? The main problem is that "Cannot use compiler
- # output with multiple arch flags" won't make sense to most
- # developers.
- if (len(archs) > 1 and
- p.type not in (Types.NothingType,Types.ObjectType,Types.ImageType)):
- raise Arguments.InvalidArgumentsError('Cannot use %s output with multiple arch flags.' % p.type.name)
-
- inputs = []
- for arch in archs:
- inputs.append(Phases.BindArchAction(p, arch))
-
- # Lipo if necessary. We do it this way because we need to set
- # the arch flag so that -Xarch_ gets rewritten.
- if len(inputs) == 1 or p.type == Types.NothingType:
- finalActions.extend(inputs)
- else:
- finalActions.append(Phases.JobAction(Phases.LipoPhase(),
- inputs,
- p.type))
-
- return finalActions
-
- def bindPhases(self, phases, args):
- jobs = Jobs.JobList()
-
- finalOutput = args.getLastArg(self.parser.oOption)
- hasSaveTemps = args.getLastArg(self.parser.saveTempsOption)
- hasNoIntegratedCPP = args.getLastArg(self.parser.noIntegratedCPPOption)
- hasTraditionalCPP = args.getLastArg(self.parser.traditionalCPPOption)
- hasPipe = args.getLastArg(self.parser.pipeOption)
-
- # We claim things here so that options for which we silently allow
- # override only ever claim the used option.
- if hasPipe:
- self.claim(hasPipe)
- # FIXME: Hack, override -pipe till we support it.
- if hasSaveTemps:
- self.warning('-pipe ignored because -save-temps specified')
- hasPipe = None
- # Claim these here. Its not completely accurate but any warnings
- # about these being unused are likely to be noise anyway.
- if hasSaveTemps:
- self.claim(hasSaveTemps)
-
- if hasTraditionalCPP:
- self.claim(hasTraditionalCPP)
- elif hasNoIntegratedCPP:
- self.claim(hasNoIntegratedCPP)
-
- # FIXME: Move to... somewhere else.
- class InputInfo:
- def __init__(self, source, type, baseInput):
- self.source = source
- self.type = type
- self.baseInput = baseInput
-
- def __repr__(self):
- return '%s(%r, %r, %r)' % (self.__class__.__name__,
- self.source, self.type, self.baseInput)
-
- def isOriginalInput(self):
- return self.source is self.baseInput
-
- def createJobs(tc, phase,
- canAcceptPipe=False, atTopLevel=False, arch=None,
- tcArgs=None, linkingOutput=None):
- if isinstance(phase, Phases.InputAction):
- return InputInfo(phase.filename, phase.type, phase.filename)
- elif isinstance(phase, Phases.BindArchAction):
- archName = args.getValue(phase.arch)
- tc = self.hostInfo.getToolChainForArch(archName)
- return createJobs(tc, phase.inputs[0],
- canAcceptPipe, atTopLevel, phase.arch,
- None, linkingOutput)
-
- if tcArgs is None:
- tcArgs = tc.translateArgs(args, arch)
-
- assert isinstance(phase, Phases.JobAction)
- tool = tc.selectTool(phase)
-
- # See if we should use an integrated CPP. We only use an
- # integrated cpp when we have exactly one input, since this is
- # the only use case we care about.
- useIntegratedCPP = False
- inputList = phase.inputs
- if (not hasNoIntegratedCPP and
- not hasTraditionalCPP and
- not hasSaveTemps and
- tool.hasIntegratedCPP()):
- if (len(phase.inputs) == 1 and
- isinstance(phase.inputs[0], Phases.JobAction) and
- isinstance(phase.inputs[0].phase, Phases.PreprocessPhase)):
- useIntegratedCPP = True
- inputList = phase.inputs[0].inputs
-
- # Only try to use pipes when exactly one input.
- attemptToPipeInput = len(inputList) == 1 and tool.acceptsPipedInput()
- inputs = [createJobs(tc, p, attemptToPipeInput, False,
- arch, tcArgs, linkingOutput)
- for p in inputList]
-
- # Determine if we should output to a pipe.
- canOutputToPipe = canAcceptPipe and tool.canPipeOutput()
- outputToPipe = False
- if canOutputToPipe:
- # Some things default to writing to a pipe if the final
- # phase and there was no user override.
- #
- # FIXME: What is the best way to handle this?
- if atTopLevel:
- if (isinstance(phase.phase, Phases.PreprocessPhase) and
- not finalOutput):
- outputToPipe = True
- elif hasPipe:
- outputToPipe = True
-
- # Figure out where to put the job (pipes).
- jobList = jobs
- if isinstance(inputs[0].source, Jobs.PipedJob):
- jobList = inputs[0].source
-
- baseInput = inputs[0].baseInput
- output,jobList = self.getOutputName(phase, outputToPipe, jobs, jobList, baseInput,
- args, atTopLevel, hasSaveTemps, finalOutput)
- tool.constructJob(phase, arch, jobList, inputs, output, phase.type,
- tcArgs, linkingOutput)
-
- return InputInfo(output, phase.type, baseInput)
-
- # It is an error to provide a -o option if we are making multiple
- # output files.
- if finalOutput and len([a for a in phases if a.type is not Types.NothingType]) > 1:
- raise Arguments.InvalidArgumentsError("cannot specify -o when generating multiple files")
-
- for phase in phases:
- # If we are linking an image for multiple archs then the
- # linker wants -arch_multiple and -final_output <final image
- # name>. Unfortunately this requires some gross contortions.
- #
- # FIXME: This is a hack; find a cleaner way to integrate this
- # into the process.
- linkingOutput = None
- if (isinstance(phase, Phases.JobAction) and
- isinstance(phase.phase, Phases.LipoPhase)):
- finalOutput = args.getLastArg(self.parser.oOption)
- if finalOutput:
- linkingOutput = finalOutput
- else:
- linkingOutput = args.makeSeparateArg('a.out',
- self.parser.oOption)
-
- createJobs(self.toolChain, phase,
- canAcceptPipe=True, atTopLevel=True,
- linkingOutput=linkingOutput)
-
- return jobs
-
- def getOutputName(self, phase, outputToPipe, jobs, jobList, baseInput,
- args, atTopLevel, hasSaveTemps, finalOutput):
- # Figure out where to put the output.
- if phase.type == Types.NothingType:
- output = None
- elif outputToPipe:
- if isinstance(jobList, Jobs.PipedJob):
- output = jobList
- else:
- jobList = output = Jobs.PipedJob([])
- jobs.addJob(output)
- else:
- # Figure out what the derived output location would be.
- if phase.type is Types.ImageType:
- namedOutput = "a.out"
- else:
- assert phase.type.tempSuffix is not None
- inputName = args.getValue(baseInput)
- if phase.type.appendSuffix:
- namedOutput = inputName + '.' + phase.type.tempSuffix
- else:
- base,_ = os.path.splitext(inputName)
- namedOutput = base + '.' + phase.type.tempSuffix
-
- isTemp = False
- # Output to user requested destination?
- if atTopLevel and finalOutput:
- output = finalOutput
- self.resultFiles.append(args.getValue(finalOutput))
-
- # Contruct a named destination?
- elif atTopLevel or hasSaveTemps:
- # As an annoying special case, pch generation
- # doesn't strip the pathname.
- if phase.type is Types.PCHType:
- outputName = namedOutput
- else:
- outputName = os.path.basename(namedOutput)
- output = args.makeSeparateArg(outputName,
- self.parser.oOption)
- self.resultFiles.append(outputName)
-
- else:
- # Output to temp file...
- fd,filename = tempfile.mkstemp(suffix='.'+phase.type.tempSuffix)
- output = args.makeSeparateArg(filename,
- self.parser.oOption)
- self.tempFiles.append(filename)
- return output,jobList