| 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 |
| |
| def shouldUseClangCompiler(self, action): |
| # If user requested no clang, or this isn't a "compile" phase, |
| # or this isn't a C family option, then don't use clang. |
| if (self.driver.cccNoClang or |
| not isinstance(action.phase, (Phases.PreprocessPhase, |
| Phases.CompilePhase, |
| Phases.SyntaxOnlyPhase, |
| Phases.EmitLLVMPhase, |
| Phases.PrecompilePhase)) or |
| action.inputs[0].type not in Types.cTypesSet): |
| return False |
| |
| if self.driver.cccNoClangPreprocessor: |
| if isinstance(action.phase, Phases.PreprocessPhase): |
| return False |
| |
| if self.driver.cccNoClangCXX: |
| if action.inputs[0].type in Types.cxxTypesSet: |
| return False |
| |
| return True |
| |
| def isMathErrnoDefault(self): |
| return True |
| |
| 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) |
| cc = Tools.Darwin_X86_CompileTool(self) |
| self.toolMap = { |
| Phases.PreprocessPhase : Tools.Darwin_X86_PreprocessTool(self), |
| Phases.AnalyzePhase : self.clangTool, |
| Phases.SyntaxOnlyPhase : cc, |
| Phases.EmitLLVMPhase : cc, |
| Phases.CompilePhase : cc, |
| Phases.PrecompilePhase : cc, |
| Phases.AssemblePhase : Tools.Darwin_AssembleTool(self), |
| Phases.LinkPhase : Tools.Darwin_X86_LinkTool(self), |
| Phases.LipoPhase : Tools.LipoTool(), |
| } |
| |
| if archName == 'x86_64': |
| self.filePathPrefixes.append(os.path.join(self.driver.driverDir, |
| '../lib/gcc', |
| self.getToolChainDir(), |
| 'x86_64')) |
| self.filePathPrefixes.append(os.path.join('/usr/lib/gcc', |
| self.getToolChainDir(), |
| 'x86_64')) |
| self.filePathPrefixes.append(os.path.join(self.driver.driverDir, |
| '../lib/gcc', |
| self.getToolChainDir())) |
| self.filePathPrefixes.append(os.path.join('/usr/lib/gcc', |
| self.getToolChainDir())) |
| |
| self.programPathPrefixes.append(os.path.join(self.driver.driverDir, |
| '../libexec/gcc', |
| self.getToolChainDir())) |
| self.programPathPrefixes.append(os.path.join('/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 shouldUseClangCompiler(self, action): |
| if not super(Darwin_X86_ToolChain, self).shouldUseClangCompiler(action): |
| return False |
| |
| # Only use clang if user didn't override archs, or this is one |
| # of the ones they provided. |
| if (not self.driver.cccClangArchs or |
| self.archName in self.driver.cccClangArchs): |
| return True |
| |
| return False |
| |
| def selectTool(self, action): |
| assert isinstance(action, Phases.JobAction) |
| |
| if self.shouldUseClangCompiler(action): |
| 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.sharedOption: |
| al.append(al.makeFlagArg(args.parser.dynamiclibOption)) |
| 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 |
| |
| def isMathErrnoDefault(self): |
| return False |
| |
| 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) |
| cc = Tools.GCC_CompileTool() |
| self.clangTool = Tools.Clang_CompileTool(self) |
| self.toolMap = { |
| Phases.PreprocessPhase : Tools.GCC_PreprocessTool(), |
| Phases.AnalyzePhase : self.clangTool, |
| Phases.SyntaxOnlyPhase : cc, |
| Phases.EmitLLVMPhase : cc, |
| Phases.CompilePhase : cc, |
| Phases.PrecompilePhase : Tools.GCC_PrecompileTool(), |
| Phases.AssemblePhase : Tools.GCC_AssembleTool(), |
| Phases.LinkPhase : Tools.GCC_LinkTool(), |
| } |
| |
| def selectTool(self, action): |
| assert isinstance(action, Phases.JobAction) |
| |
| if self.shouldUseClangCompiler(action): |
| return self.clangTool |
| |
| return self.toolMap[action.phase.__class__] |