210 lines
9.7 KiB
Python
210 lines
9.7 KiB
Python
import os
|
|
|
|
import Arguments
|
|
import Phases
|
|
import Tools
|
|
import Types
|
|
|
|
###
|
|
|
|
class ToolChain(object):
|
|
"""ToolChain - Provide mappings of Actions to Tools."""
|
|
|
|
def __init__(self, driver,
|
|
filePathPrefixes=[],
|
|
programPathPrefixes=[]):
|
|
self.driver = driver
|
|
self.filePathPrefixes = list(filePathPrefixes)
|
|
self.programPathPrefixes = list(programPathPrefixes)
|
|
|
|
def getFilePath(self, name):
|
|
return self.driver.getFilePath(name, self)
|
|
|
|
def getProgramPath(self, name):
|
|
return self.driver.getProgramPath(name, self)
|
|
|
|
def selectTool(self, action):
|
|
"""selectTool - Return a Tool instance to use for handling
|
|
some particular action."""
|
|
abstract
|
|
|
|
def translateArgs(self, args, arch):
|
|
"""translateArgs - Callback to allow argument translation for
|
|
an entire toolchain."""
|
|
|
|
# FIXME: Would be nice to move arch handling out of generic
|
|
# code.
|
|
if arch:
|
|
archName = args.getValue(arch)
|
|
al = Arguments.DerivedArgList(args)
|
|
for arg in args.args:
|
|
if arg.opt is args.parser.archOption:
|
|
if arg is arch:
|
|
al.append(arg)
|
|
elif arg.opt is args.parser.XarchOption:
|
|
if args.getJoinedValue(arg) == archName:
|
|
# FIXME: Fix this.
|
|
arg = args.parser.lookupOptForArg(Arguments.InputIndex(0, arg.index.pos + 1),
|
|
args.getSeparateValue(arg),
|
|
iter([]))
|
|
al.append(arg)
|
|
else:
|
|
al.append(arg)
|
|
return al
|
|
else:
|
|
return args
|
|
|
|
class Darwin_X86_ToolChain(ToolChain):
|
|
def __init__(self, driver, darwinVersion, gccVersion, archName):
|
|
super(Darwin_X86_ToolChain, self).__init__(driver)
|
|
assert isinstance(darwinVersion, tuple) and len(darwinVersion) == 3
|
|
assert isinstance(gccVersion, tuple) and len(gccVersion) == 3
|
|
self.darwinVersion = darwinVersion
|
|
self.gccVersion = gccVersion
|
|
self.archName = archName
|
|
|
|
self.clangTool = Tools.Clang_CompileTool(self)
|
|
self.toolMap = {
|
|
Phases.PreprocessPhase : Tools.Darwin_X86_PreprocessTool(self),
|
|
Phases.AnalyzePhase : self.clangTool,
|
|
Phases.SyntaxOnlyPhase : Tools.Darwin_X86_CompileTool(self),
|
|
Phases.CompilePhase : Tools.Darwin_X86_CompileTool(self),
|
|
Phases.PrecompilePhase : Tools.Darwin_X86_CompileTool(self),
|
|
Phases.AssemblePhase : Tools.Darwin_AssembleTool(self),
|
|
Phases.LinkPhase : Tools.Darwin_X86_LinkTool(self),
|
|
Phases.LipoPhase : Tools.LipoTool(),
|
|
}
|
|
|
|
self.filePathPrefixes.append(os.path.join(self.driver.driverDir,
|
|
'../lib/gcc',
|
|
self.getToolChainDir()))
|
|
self.filePathPrefixes.append(os.path.join(self.driver.driverDir,
|
|
'/usr/lib/gcc',
|
|
self.getToolChainDir()))
|
|
|
|
self.programPathPrefixes.append(os.path.join(self.driver.driverDir,
|
|
'../libexec/gcc',
|
|
self.getToolChainDir()))
|
|
self.programPathPrefixes.append(os.path.join(self.driver.driverDir,
|
|
'/usr/libexec/gcc',
|
|
self.getToolChainDir()))
|
|
self.programPathPrefixes.append(self.driver.driverDir)
|
|
|
|
def getToolChainDir(self):
|
|
return 'i686-apple-darwin%d/%s' % (self.darwinVersion[0],
|
|
'.'.join(map(str,self.gccVersion)))
|
|
|
|
def getMacosxVersionMin(self):
|
|
major,minor,minorminor = self.darwinVersion
|
|
return '%d.%d.%d' % (10, major-4, minor)
|
|
|
|
def selectTool(self, action):
|
|
assert isinstance(action, Phases.JobAction)
|
|
|
|
if self.driver.cccClang and self.archName == 'i386':
|
|
if (action.inputs[0].type in (Types.CType, Types.CTypeNoPP,
|
|
Types.ObjCType, Types.ObjCTypeNoPP) and
|
|
isinstance(action.phase, Phases.CompilePhase)):
|
|
return self.clangTool
|
|
elif (action.inputs[0].type in (Types.CHeaderType, Types.CHeaderNoPPType,
|
|
Types.ObjCHeaderType, Types.ObjCHeaderNoPPType) and
|
|
isinstance(action.phase, Phases.PrecompilePhase)):
|
|
return self.clangTool
|
|
|
|
return self.toolMap[action.phase.__class__]
|
|
|
|
def translateArgs(self, args, arch):
|
|
args = super(Darwin_X86_ToolChain, self).translateArgs(args, arch)
|
|
|
|
# If arch hasn't been bound we don't need to do anything yet.
|
|
if not arch:
|
|
return args
|
|
|
|
# FIXME: We really want to get out of the tool chain level
|
|
# argument translation business, as it makes the driver
|
|
# functionality much more opaque. For now, we follow gcc
|
|
# closely solely for the purpose of easily achieving feature
|
|
# parity & testability. Once we have something that works, we
|
|
# should reevaluate each translation and try to push it down
|
|
# into tool specific logic.
|
|
|
|
al = Arguments.DerivedArgList(args)
|
|
if not args.getLastArg(args.parser.m_macosxVersionMinOption):
|
|
al.append(al.makeJoinedArg(self.getMacosxVersionMin(),
|
|
args.parser.m_macosxVersionMinOption))
|
|
for arg in args:
|
|
# Sob. These is strictly gcc compatible for the time
|
|
# being. Apple gcc translates options twice, which means
|
|
# that self-expanding options add duplicates.
|
|
if arg.opt is args.parser.m_kernelOption:
|
|
al.append(arg)
|
|
al.append(al.makeFlagArg(args.parser.staticOption))
|
|
al.append(al.makeFlagArg(args.parser.staticOption))
|
|
elif arg.opt is args.parser.dependencyFileOption:
|
|
al.append(al.makeSeparateArg(args.getValue(arg),
|
|
args.parser.MFOption))
|
|
elif arg.opt is args.parser.gfullOption:
|
|
al.append(al.makeFlagArg(args.parser.gOption))
|
|
al.append(al.makeFlagArg(args.parser.f_noEliminateUnusedDebugSymbolsOption))
|
|
elif arg.opt is args.parser.gusedOption:
|
|
al.append(al.makeFlagArg(args.parser.gOption))
|
|
al.append(al.makeFlagArg(args.parser.f_eliminateUnusedDebugSymbolsOption))
|
|
elif arg.opt is args.parser.f_appleKextOption:
|
|
al.append(arg)
|
|
al.append(al.makeFlagArg(args.parser.staticOption))
|
|
al.append(al.makeFlagArg(args.parser.staticOption))
|
|
elif arg.opt is args.parser.f_terminatedVtablesOption:
|
|
al.append(al.makeFlagArg(args.parser.f_appleKextOption))
|
|
al.append(al.makeFlagArg(args.parser.staticOption))
|
|
elif arg.opt is args.parser.f_indirectVirtualCallsOption:
|
|
al.append(al.makeFlagArg(args.parser.f_appleKextOption))
|
|
al.append(al.makeFlagArg(args.parser.staticOption))
|
|
elif arg.opt is args.parser.f_constantCfstringsOption:
|
|
al.append(al.makeFlagArg(args.parser.m_constantCfstringsOption))
|
|
elif arg.opt is args.parser.f_noConstantCfstringsOption:
|
|
al.append(al.makeFlagArg(args.parser.m_noConstantCfstringsOption))
|
|
elif arg.opt is args.parser.WnonportableCfstringsOption:
|
|
al.append(al.makeFlagArg(args.parser.m_warnNonportableCfstringsOption))
|
|
elif arg.opt is args.parser.WnoNonportableCfstringsOption:
|
|
al.append(al.makeFlagArg(args.parser.m_noWarnNonportableCfstringsOption))
|
|
elif arg.opt is args.parser.f_pascalStringsOption:
|
|
al.append(al.makeFlagArg(args.parser.m_pascalStringsOption))
|
|
elif arg.opt is args.parser.f_noPascalStringsOption:
|
|
al.append(al.makeFlagArg(args.parser.m_noPascalStringsOption))
|
|
else:
|
|
al.append(arg)
|
|
|
|
# FIXME: Actually, gcc always adds this, but it is filtered
|
|
# for duplicates somewhere. This also changes the order of
|
|
# things, so look it up.
|
|
if arch and args.getValue(arch) == 'x86_64':
|
|
if not args.getLastArg(args.parser.m_64Option):
|
|
al.append(al.makeFlagArg(args.parser.m_64Option))
|
|
|
|
if not args.getLastArg(args.parser.m_tuneOption):
|
|
al.append(al.makeJoinedArg('core2',
|
|
args.parser.m_tuneOption))
|
|
|
|
return al
|
|
|
|
class Generic_GCC_ToolChain(ToolChain):
|
|
"""Generic_GCC_ToolChain - A tool chain using the 'gcc' command to
|
|
perform all subcommands; this relies on gcc translating the
|
|
options appropriately."""
|
|
|
|
def __init__(self, driver):
|
|
super(Generic_GCC_ToolChain, self).__init__(driver)
|
|
self.toolMap = {
|
|
Phases.PreprocessPhase : Tools.GCC_PreprocessTool(),
|
|
Phases.AnalyzePhase : Tools.Clang_CompileTool(self),
|
|
Phases.SyntaxOnlyPhase : Tools.GCC_CompileTool(),
|
|
Phases.CompilePhase : Tools.GCC_CompileTool(),
|
|
Phases.PrecompilePhase : Tools.GCC_PrecompileTool(),
|
|
Phases.AssemblePhase : Tools.GCC_AssembleTool(),
|
|
Phases.LinkPhase : Tools.GCC_LinkTool(),
|
|
}
|
|
|
|
def selectTool(self, action):
|
|
assert isinstance(action, Phases.JobAction)
|
|
return self.toolMap[action.phase.__class__]
|