From de460978471562af6946fb9d39795fed48e939f0 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Tue, 20 Jan 2009 21:29:14 +0000 Subject: [PATCH] ccc: Allow downstream tools to be aware of final output name. - This is a hack to allow the Darwin linker to get -final_output when doing universal builds; the mechanism should be generalized. - Handle multiple redundant -arch arguments correctly. - Forward -arch_multiple and -final_output to gcc when necessary. - Simplified implementation of derived gcc tools. llvm-svn: 62618 --- clang/tools/ccc/ccclib/Driver.py | 138 ++++++++++++--------- clang/tools/ccc/ccclib/Tools.py | 87 ++++++------- clang/tools/ccc/test/ccc/universal-hello.c | 5 +- 3 files changed, 121 insertions(+), 109 deletions(-) diff --git a/clang/tools/ccc/ccclib/Driver.py b/clang/tools/ccc/ccclib/Driver.py index 42a789b61a29..c17d272795a9 100644 --- a/clang/tools/ccc/ccclib/Driver.py +++ b/clang/tools/ccc/ccclib/Driver.py @@ -521,14 +521,17 @@ class Driver(object): def buildPipeline(self, args): # FIXME: We need to handle canonicalization of the specified arch. - archs = [] + archs = {} hasDashM = args.getLastArg(self.parser.MGroup) hasSaveTemps = (args.getLastArg(self.parser.saveTempsOption) or args.getLastArg(self.parser.saveTempsOption2)) for arg in args: if arg.opt is self.parser.archOption: - archs.append(arg) - + # 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)) @@ -578,18 +581,6 @@ class Driver(object): inputs, p.type)) - # FIXME: We need to add -Wl,arch_multiple and -Wl,final_output in - # certain cases. This may be icky because we need to figure out the - # mode first. Current plan is to hack on the pipeline once it is built - # and we know what is being spit out. This avoids having to handling - # things like -c and -combine in multiple places. - # - # The annoying one of these is -Wl,final_output because it involves - # communication across different phases. - # - # Hopefully we can do this purely as part of the binding, but - # leaving comment here for now until it is clear this works. - return finalActions def bindPhases(self, phases, args): @@ -636,7 +627,7 @@ class Driver(object): def createJobs(tc, phase, canAcceptPipe=False, atTopLevel=False, arch=None, - tcArgs=None): + tcArgs=None, linkingOutput=None): if isinstance(phase, Phases.InputAction): return InputInfo(phase.filename, phase.type, phase.filename) elif isinstance(phase, Phases.BindArchAction): @@ -644,7 +635,7 @@ class Driver(object): tc = self.hostInfo.getToolChainForArch(archName) return createJobs(tc, phase.inputs[0], canAcceptPipe, atTopLevel, phase.arch, - tcArgs=None) + None, linkingOutput) if tcArgs is None: tcArgs = tc.translateArgs(args, arch) @@ -669,7 +660,8 @@ class Driver(object): # Only try to use pipes when exactly one input. canAcceptPipe = len(inputList) == 1 and tool.acceptsPipedInput() - inputs = [createJobs(tc, p, canAcceptPipe, False, arch, tcArgs) + inputs = [createJobs(tc, p, canAcceptPipe, False, + arch, tcArgs, linkingOutput) for p in inputList] # Determine if we should output to a pipe. @@ -691,51 +683,12 @@ class Driver(object): jobList = jobs if canAcceptPipe and isinstance(inputs[0].source, Jobs.PipedJob): jobList = inputs[0].source - - # Figure out where to put the output. + baseInput = inputs[0].baseInput - 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. - # - # FIXME: gcc has some special case in here so that it doesn't - # create output files if they would conflict with an input. - if phase.type is Types.ImageType: - namedOutput = "a.out" - else: - inputName = args.getValue(baseInput) - base,_ = os.path.splitext(inputName) - assert phase.type.tempSuffix is not None - namedOutput = base + '.' + phase.type.tempSuffix - - # Output to user requested destination? - if atTopLevel and finalOutput: - output = 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) - else: - # Output to temp file... - fd,filename = tempfile.mkstemp(suffix='.'+phase.type.tempSuffix) - output = args.makeSeparateArg(filename, - self.parser.oOption) - + output = self.getOutputName(phase, outputToPipe, jobs, jobList, baseInput, + args, atTopLevel, hasSaveTemps, finalOutput) tool.constructJob(phase, arch, jobList, inputs, output, phase.type, - tcArgs) + tcArgs, linkingOutput) return InputInfo(output, phase.type, baseInput) @@ -745,7 +698,68 @@ class Driver(object): 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 . 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) + 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. + # + # FIXME: gcc has some special case in here so that it doesn't + # create output files if they would conflict with an input. + if phase.type is Types.ImageType: + namedOutput = "a.out" + else: + inputName = args.getValue(baseInput) + base,_ = os.path.splitext(inputName) + assert phase.type.tempSuffix is not None + namedOutput = base + '.' + phase.type.tempSuffix + + # Output to user requested destination? + if atTopLevel and finalOutput: + output = 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) + else: + # Output to temp file... + fd,filename = tempfile.mkstemp(suffix='.'+phase.type.tempSuffix) + output = args.makeSeparateArg(filename, + self.parser.oOption) + return output diff --git a/clang/tools/ccc/ccclib/Tools.py b/clang/tools/ccc/ccclib/Tools.py index 06d1ab140872..2bb694c4e284 100644 --- a/clang/tools/ccc/ccclib/Tools.py +++ b/clang/tools/ccc/ccclib/Tools.py @@ -24,15 +24,17 @@ class Tool(object): return not not (self.flags & Tool.eFlagsIntegratedCPP) class GCC_Common_Tool(Tool): + def getGCCExtraArgs(self): + return [] + def constructJob(self, phase, arch, jobs, inputs, - output, outputType, arglist, - extraArgs): + output, outputType, arglist, linkingOutput): cmd_args = [] for arg in arglist.args: if arg.opt.forwardToGCC(): cmd_args.extend(arglist.render(arg)) - cmd_args.extend(extraArgs) + cmd_args.extend(self.getGCCExtraArgs()) if arch: cmd_args.extend(arglist.render(arch)) if isinstance(output, Jobs.PipedJob): @@ -42,6 +44,12 @@ class GCC_Common_Tool(Tool): else: cmd_args.extend(arglist.render(output)) + if (isinstance(self, GCC_LinkTool) and + linkingOutput): + cmd_args.append('-Wl,-arch_multiple') + cmd_args.append('-Wl,-final_output,' + + arglist.getValue(linkingOutput)) + # Only pass -x if gcc will understand it; otherwise hope gcc # understands the suffix correctly. The main use case this # would go wrong in is for linker inputs if they happened to @@ -74,11 +82,8 @@ class GCC_PreprocessTool(GCC_Common_Tool): (Tool.eFlagsPipedInput | Tool.eFlagsPipedOutput)) - def constructJob(self, phase, arch, jobs, inputs, - output, outputType, arglist): - return super(GCC_PreprocessTool, self).constructJob(phase, arch, jobs, inputs, - output, outputType, arglist, - ['-E']) + def getGCCExtraArgs(self): + return ['-E'] class GCC_CompileTool(GCC_Common_Tool): def __init__(self): @@ -87,11 +92,8 @@ class GCC_CompileTool(GCC_Common_Tool): Tool.eFlagsPipedOutput | Tool.eFlagsIntegratedCPP)) - def constructJob(self, phase, arch, jobs, inputs, - output, outputType, arglist): - return super(GCC_CompileTool, self).constructJob(phase, arch, jobs, inputs, - output, outputType, arglist, - ['-S']) + def getGCCExtraArgs(self): + return ['-S'] class GCC_PrecompileTool(GCC_Common_Tool): def __init__(self): @@ -99,11 +101,21 @@ class GCC_PrecompileTool(GCC_Common_Tool): (Tool.eFlagsPipedInput | Tool.eFlagsIntegratedCPP)) - def constructJob(self, phase, arch, jobs, inputs, - output, outputType, arglist): - return super(GCC_PrecompileTool, self).constructJob(phase, arch, jobs, inputs, - output, outputType, arglist, - []) + def getGCCExtraArgs(self): + return [] + +class GCC_AssembleTool(GCC_Common_Tool): + def __init__(self): + # We can't generally assume the assembler can take or output + # on pipes. + super(GCC_AssembleTool, self).__init__('gcc (as)') + + def getGCCExtraArgs(self): + return ['-c'] + +class GCC_LinkTool(GCC_Common_Tool): + def __init__(self): + super(GCC_LinkTool, self).__init__('gcc (ld)') class Darwin_AssembleTool(Tool): def __init__(self, toolChain): @@ -112,7 +124,7 @@ class Darwin_AssembleTool(Tool): self.toolChain = toolChain def constructJob(self, phase, arch, jobs, inputs, - output, outputType, arglist): + output, outputType, arglist, linkingOutput): assert len(inputs) == 1 assert outputType is Types.ObjectType @@ -150,28 +162,6 @@ class Darwin_AssembleTool(Tool): jobs.addJob(Jobs.Command(self.toolChain.getProgramPath('as'), cmd_args)) -class GCC_AssembleTool(GCC_Common_Tool): - def __init__(self): - # We can't generally assume the assembler can take or output - # on pipes. - super(GCC_AssembleTool, self).__init__('gcc (as)') - - def constructJob(self, phase, arch, jobs, inputs, - output, outputType, arglist): - return super(GCC_AssembleTool, self).constructJob(phase, arch, jobs, inputs, - output, outputType, arglist, - ['-c']) - -class GCC_LinkTool(GCC_Common_Tool): - def __init__(self): - super(GCC_LinkTool, self).__init__('gcc (ld)') - - def constructJob(self, phase, arch, jobs, inputs, - output, outputType, arglist): - return super(GCC_LinkTool, self).constructJob(phase, arch, jobs, inputs, - output, outputType, arglist, - []) - class Clang_CompileTool(Tool): def __init__(self): super(Clang_CompileTool, self).__init__('clang', @@ -180,7 +170,7 @@ class Clang_CompileTool(Tool): Tool.eFlagsIntegratedCPP)) def constructJob(self, phase, arch, jobs, inputs, - output, outputType, arglist): + output, outputType, arglist, linkingOutput): cmd_args = [] patchOutputNameForPTH = False @@ -580,7 +570,7 @@ class Darwin_X86_PreprocessTool(Darwin_X86_CC1Tool): self.toolChain = toolChain def constructJob(self, phase, arch, jobs, inputs, - output, outputType, arglist): + output, outputType, arglist, linkingOutput): inputType = inputs[0].type assert not [i for i in inputs if i.type != inputType] @@ -611,7 +601,7 @@ class Darwin_X86_CompileTool(Darwin_X86_CC1Tool): self.toolChain = toolChain def constructJob(self, phase, arch, jobs, inputs, - output, outputType, arglist): + output, outputType, arglist, linkingOutput): inputType = inputs[0].type assert not [i for i in inputs if i.type != inputType] @@ -897,7 +887,7 @@ class Darwin_X86_LinkTool(Tool): arglist.addLastArg(cmd_args, arglist.parser.MachOption) def constructJob(self, phase, arch, jobs, inputs, - output, outputType, arglist): + output, outputType, arglist, linkingOutput): assert outputType is Types.ImageType # The logic here is derived from gcc's behavior; most of which @@ -1017,6 +1007,11 @@ class Darwin_X86_LinkTool(Tool): for input in inputs: cmd_args.extend(arglist.renderAsInput(input.source)) + if linkingOutput: + cmd_args.append('-arch_multiple') + cmd_args.append('-final_output') + cmd_args.append(arglist.getValue(linkingOutput)) + if (arglist.getLastArg(arglist.parser.f_profileArcsOption) or arglist.getLastArg(arglist.parser.f_profileGenerateOption) or arglist.getLastArg(arglist.parser.f_createProfileOption) or @@ -1088,7 +1083,7 @@ class LipoTool(Tool): super(LipoTool, self).__init__('lipo') def constructJob(self, phase, arch, jobs, inputs, - output, outputType, arglist): + output, outputType, arglist, linkingOutput): assert outputType is Types.ImageType cmd_args = ['-create'] diff --git a/clang/tools/ccc/test/ccc/universal-hello.c b/clang/tools/ccc/test/ccc/universal-hello.c index a482e536acec..8d4b3e336465 100644 --- a/clang/tools/ccc/test/ccc/universal-hello.c +++ b/clang/tools/ccc/test/ccc/universal-hello.c @@ -1,5 +1,8 @@ // RUN: xcc -arch ppc -arch i386 -arch x86_64 %s -o %t && -// RUN: %t | grep "Hello, World" +// RUN: %t | grep "Hello, World" && + +// Check that multiple archs are handled properly. +// RUN: xcc -ccc-print-phases -### -arch ppc -arch ppc %s | grep linker- | count 1 int main() { printf("Hello, World!\n");