mirror of https://github.com/acidanthera/audk.git
405 lines
14 KiB
Java
405 lines
14 KiB
Java
/*
|
|
*
|
|
* Copyright 2002-2004 The Ant-Contrib project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package net.sf.antcontrib.cpptasks.compiler;
|
|
|
|
import java.io.File;
|
|
import java.io.FileWriter;
|
|
import java.io.IOException;
|
|
import java.util.Enumeration;
|
|
import java.util.Vector;
|
|
|
|
import net.sf.antcontrib.cpptasks.CCTask;
|
|
import net.sf.antcontrib.cpptasks.CUtil;
|
|
import net.sf.antcontrib.cpptasks.LinkerDef;
|
|
import net.sf.antcontrib.cpptasks.ProcessorDef;
|
|
import net.sf.antcontrib.cpptasks.ProcessorParam;
|
|
import net.sf.antcontrib.cpptasks.types.CommandLineArgument;
|
|
import net.sf.antcontrib.cpptasks.types.LibrarySet;
|
|
import net.sf.antcontrib.cpptasks.TargetDef;
|
|
|
|
import org.apache.tools.ant.BuildException;
|
|
import org.apache.tools.ant.types.Environment;
|
|
|
|
|
|
/**
|
|
* An abstract Linker implementation that performs the link via an external
|
|
* command.
|
|
*
|
|
* @author Adam Murdoch
|
|
*/
|
|
public abstract class CommandLineLinker extends AbstractLinker
|
|
{
|
|
private String command;
|
|
private Environment env = null;
|
|
private String identifier;
|
|
private String identifierArg;
|
|
private boolean isLibtool;
|
|
private String[] librarySets;
|
|
private CommandLineLinker libtoolLinker;
|
|
private boolean newEnvironment = false;
|
|
private String outputSuffix;
|
|
|
|
|
|
/** Creates a comand line linker invocation */
|
|
public CommandLineLinker(String command,
|
|
String identifierArg,
|
|
String[] extensions,
|
|
String[] ignoredExtensions, String outputSuffix,
|
|
boolean isLibtool, CommandLineLinker libtoolLinker)
|
|
{
|
|
super(extensions, ignoredExtensions);
|
|
this.command = command;
|
|
this.identifierArg = identifierArg;
|
|
this.outputSuffix = outputSuffix;
|
|
this.isLibtool = isLibtool;
|
|
this.libtoolLinker = libtoolLinker;
|
|
}
|
|
protected abstract void addBase(long base, Vector args);
|
|
|
|
protected abstract void addFixed(Boolean fixed, Vector args);
|
|
|
|
abstract protected void addImpliedArgs(boolean debug,
|
|
LinkType linkType, Vector args, Boolean defaultflag);
|
|
protected abstract void addIncremental(boolean incremental, Vector args);
|
|
|
|
//
|
|
// Windows processors handle these through file list
|
|
//
|
|
protected String[] addLibrarySets(CCTask task, LibrarySet[] libsets, Vector preargs,
|
|
Vector midargs, Vector endargs) {
|
|
return null;
|
|
}
|
|
protected abstract void addMap(boolean map, Vector args);
|
|
protected abstract void addStack(int stack, Vector args);
|
|
protected abstract void addEntry(String entry, Vector args);
|
|
|
|
protected LinkerConfiguration createConfiguration(
|
|
CCTask task,
|
|
LinkType linkType,
|
|
ProcessorDef[] baseDefs, LinkerDef specificDef, TargetDef targetPlatform) {
|
|
|
|
Vector preargs = new Vector();
|
|
Vector midargs = new Vector();
|
|
Vector endargs = new Vector();
|
|
Vector[] args = new Vector[] { preargs, midargs, endargs };
|
|
|
|
LinkerDef[] defaultProviders = new LinkerDef[baseDefs.length+1];
|
|
defaultProviders[0] = specificDef;
|
|
for(int i = 0; i < baseDefs.length; i++) {
|
|
defaultProviders[i+1] = (LinkerDef) baseDefs[i];
|
|
}
|
|
//
|
|
// add command line arguments inherited from <cc> element
|
|
// any "extends" and finally the specific CompilerDef
|
|
CommandLineArgument[] commandArgs;
|
|
for(int i = defaultProviders.length-1; i >= 0; i--) {
|
|
commandArgs = defaultProviders[i].getActiveProcessorArgs();
|
|
for(int j = 0; j < commandArgs.length; j++) {
|
|
args[commandArgs[j].getLocation()].
|
|
addElement(commandArgs[j].getValue());
|
|
}
|
|
}
|
|
|
|
Vector params = new Vector();
|
|
//
|
|
// add command line arguments inherited from <cc> element
|
|
// any "extends" and finally the specific CompilerDef
|
|
ProcessorParam[] paramArray;
|
|
for (int i = defaultProviders.length - 1; i >= 0; i--) {
|
|
paramArray = defaultProviders[i].getActiveProcessorParams();
|
|
for (int j = 0; j < paramArray.length; j++) {
|
|
params.add(paramArray[j]);
|
|
}
|
|
}
|
|
|
|
paramArray = (ProcessorParam[])(params.toArray(new ProcessorParam[params.size()]));
|
|
|
|
boolean debug = specificDef.getDebug(baseDefs,0);
|
|
|
|
|
|
String startupObject = getStartupObject(linkType);
|
|
Boolean defaultflag = specificDef.getDefaultflag(defaultProviders, 1);
|
|
addImpliedArgs(debug, linkType, preargs, defaultflag);
|
|
addIncremental(specificDef.getIncremental(defaultProviders,1), preargs);
|
|
addFixed(specificDef.getFixed(defaultProviders,1), preargs);
|
|
addMap(specificDef.getMap(defaultProviders,1), preargs);
|
|
addBase(specificDef.getBase(defaultProviders,1), preargs);
|
|
addStack(specificDef.getStack(defaultProviders,1), preargs);
|
|
addEntry(specificDef.getEntry(defaultProviders, 1), preargs);
|
|
|
|
String[] libnames = null;
|
|
LibrarySet[] libsets = specificDef.getActiveLibrarySets(defaultProviders,1);
|
|
if (libsets.length > 0) {
|
|
libnames = addLibrarySets(task, libsets, preargs, midargs, endargs);
|
|
}
|
|
|
|
StringBuffer buf = new StringBuffer(getIdentifier());
|
|
for (int i = 0; i < 3; i++) {
|
|
Enumeration argenum = args[i].elements();
|
|
while (argenum.hasMoreElements()) {
|
|
buf.append(' ');
|
|
buf.append(argenum.nextElement().toString());
|
|
}
|
|
}
|
|
String configId = buf.toString();
|
|
|
|
String[][] options = new String[][] {
|
|
new String[args[0].size() + args[1].size()],
|
|
new String[args[2].size()] };
|
|
args[0].copyInto(options[0]);
|
|
int offset = args[0].size();
|
|
for (int i = 0; i < args[1].size(); i++) {
|
|
options[0][i+offset] = (String) args[1].elementAt(i);
|
|
}
|
|
args[2].copyInto(options[1]);
|
|
|
|
|
|
boolean rebuild = specificDef.getRebuild(baseDefs,0);
|
|
boolean map = specificDef.getMap(defaultProviders,1);
|
|
|
|
//task.log("libnames:"+libnames.length, Project.MSG_VERBOSE);
|
|
return new CommandLineLinkerConfiguration(this,configId,options,
|
|
paramArray,
|
|
rebuild,map,libnames, startupObject);
|
|
}
|
|
|
|
/**
|
|
* Allows drived linker to decorate linker option.
|
|
* Override by GccLinker to prepend a "-Wl," to
|
|
* pass option to through gcc to linker.
|
|
*
|
|
* @param buf buffer that may be used and abused in the decoration process,
|
|
* must not be null.
|
|
* @param arg linker argument
|
|
*/
|
|
protected String decorateLinkerOption(StringBuffer buf, String arg) {
|
|
return arg;
|
|
}
|
|
|
|
protected final String getCommand() {
|
|
return command;
|
|
}
|
|
protected abstract String getCommandFileSwitch(String commandFile);
|
|
|
|
|
|
public String getIdentifier() {
|
|
if(identifier == null) {
|
|
if (identifierArg == null) {
|
|
identifier = getIdentifier(new String[] { command }, command);
|
|
} else {
|
|
identifier = getIdentifier(new String[] { command, identifierArg },
|
|
command);
|
|
}
|
|
}
|
|
return identifier;
|
|
}
|
|
public final CommandLineLinker getLibtoolLinker() {
|
|
if (libtoolLinker != null) {
|
|
return libtoolLinker;
|
|
}
|
|
return this;
|
|
}
|
|
protected abstract int getMaximumCommandLength();
|
|
|
|
public String getOutputFileName(String baseName) {
|
|
return baseName + outputSuffix;
|
|
}
|
|
|
|
protected String[] getOutputFileSwitch(CCTask task, String outputFile) {
|
|
return getOutputFileSwitch(outputFile);
|
|
}
|
|
protected abstract String[] getOutputFileSwitch(String outputFile);
|
|
protected String getStartupObject(LinkType linkType) {
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Performs a link using a command line linker
|
|
*
|
|
*/
|
|
public void link(CCTask task,
|
|
File outputFile,
|
|
String[] sourceFiles,
|
|
CommandLineLinkerConfiguration config)
|
|
throws BuildException
|
|
{
|
|
File parentDir = new File(outputFile.getParent());
|
|
String parentPath;
|
|
try {
|
|
parentPath = parentDir.getCanonicalPath();
|
|
} catch(IOException ex) {
|
|
parentPath = parentDir.getAbsolutePath();
|
|
}
|
|
String[] execArgs = prepareArguments(task, parentPath,outputFile.getName(),
|
|
sourceFiles, config);
|
|
int commandLength = 0;
|
|
for(int i = 0; i < execArgs.length; i++) {
|
|
commandLength += execArgs[i].length() + 1;
|
|
}
|
|
|
|
//
|
|
// if command length exceeds maximum
|
|
// (1024 for Windows) then create a temporary
|
|
// file containing everything but the command name
|
|
if(commandLength >= this.getMaximumCommandLength()) {
|
|
try {
|
|
execArgs = prepareResponseFile(outputFile,execArgs);
|
|
}
|
|
catch(IOException ex) {
|
|
throw new BuildException(ex);
|
|
}
|
|
}
|
|
|
|
int retval = runCommand(task,parentDir,execArgs);
|
|
//
|
|
// if the process returned a failure code then
|
|
// throw an BuildException
|
|
//
|
|
if(retval != 0) {
|
|
//
|
|
// construct the exception
|
|
//
|
|
throw new BuildException(this.getCommand() + " failed with return code " + retval, task.getLocation());
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Prepares argument list for exec command. Will return null
|
|
* if command line would exceed allowable command line buffer.
|
|
*
|
|
* @param outputFile linker output file
|
|
* @param sourceFiles linker input files (.obj, .o, .res)
|
|
* @param args linker arguments
|
|
* @return arguments for runTask
|
|
*/
|
|
protected String[] prepareArguments(
|
|
CCTask task,
|
|
String outputDir,
|
|
String outputFile,
|
|
String[] sourceFiles,
|
|
CommandLineLinkerConfiguration config) {
|
|
|
|
String[] preargs = config.getPreArguments();
|
|
String[] endargs = config.getEndArguments();
|
|
String outputSwitch[] = getOutputFileSwitch(task, outputFile);
|
|
int allArgsCount = preargs.length + 1 + outputSwitch.length +
|
|
sourceFiles.length + endargs.length;
|
|
if (isLibtool) {
|
|
allArgsCount++;
|
|
}
|
|
String[] allArgs = new String[allArgsCount];
|
|
int index = 0;
|
|
if (isLibtool) {
|
|
allArgs[index++] = "libtool";
|
|
}
|
|
allArgs[index++] = this.getCommand();
|
|
StringBuffer buf = new StringBuffer();
|
|
for (int i = 0; i < preargs.length; i++) {
|
|
allArgs[index++] = decorateLinkerOption(buf, preargs[i]);
|
|
}
|
|
for (int i = 0; i < outputSwitch.length; i++) {
|
|
allArgs[index++] = outputSwitch[i];
|
|
}
|
|
for (int i = 0; i < sourceFiles.length; i++) {
|
|
allArgs[index++] = prepareFilename(buf,outputDir,sourceFiles[i]);
|
|
}
|
|
for (int i = 0; i < endargs.length; i++) {
|
|
allArgs[index++] = decorateLinkerOption(buf, endargs[i]);
|
|
}
|
|
return allArgs;
|
|
}
|
|
|
|
/**
|
|
* Processes filename into argument form
|
|
*
|
|
*/
|
|
protected String prepareFilename(StringBuffer buf,
|
|
String outputDir, String sourceFile) {
|
|
String relativePath = CUtil.getRelativePath(outputDir,
|
|
new File(sourceFile));
|
|
return quoteFilename(buf,relativePath);
|
|
}
|
|
|
|
/**
|
|
* Prepares argument list to execute the linker using a
|
|
* response file.
|
|
*
|
|
* @param outputFile linker output file
|
|
* @param args output of prepareArguments
|
|
* @return arguments for runTask
|
|
*/
|
|
protected String[] prepareResponseFile(File outputFile,String[] args) throws IOException
|
|
{
|
|
String baseName = outputFile.getName();
|
|
File commandFile = new File(outputFile.getParent(),baseName + ".rsp");
|
|
FileWriter writer = new FileWriter(commandFile);
|
|
int execArgCount = 1;
|
|
if (isLibtool) {
|
|
execArgCount++;
|
|
}
|
|
String[] execArgs = new String[execArgCount+1];
|
|
for (int i = 0; i < execArgCount; i++) {
|
|
execArgs[i] = args[i];
|
|
}
|
|
execArgs[execArgCount] = getCommandFileSwitch(commandFile.toString());
|
|
for(int i = execArgCount; i < args.length; i++) {
|
|
//
|
|
// if embedded space and not quoted then
|
|
// quote argument
|
|
if (args[i].indexOf(" ") >= 0 && args[i].charAt(0) != '\"') {
|
|
writer.write('\"');
|
|
writer.write(args[i]);
|
|
writer.write("\"\n");
|
|
} else {
|
|
writer.write(args[i]);
|
|
writer.write('\n');
|
|
}
|
|
}
|
|
writer.close();
|
|
return execArgs;
|
|
}
|
|
|
|
|
|
protected String quoteFilename(StringBuffer buf,String filename) {
|
|
if(filename.indexOf(' ') >= 0) {
|
|
buf.setLength(0);
|
|
buf.append('\"');
|
|
buf.append(filename);
|
|
buf.append('\"');
|
|
return buf.toString();
|
|
}
|
|
return filename;
|
|
}
|
|
|
|
/**
|
|
* This method is exposed so test classes can overload
|
|
* and test the arguments without actually spawning the
|
|
* compiler
|
|
*/
|
|
protected int runCommand(CCTask task, File workingDir,String[] cmdline)
|
|
throws BuildException {
|
|
return CUtil.runCommand(task,workingDir,cmdline, newEnvironment, env);
|
|
}
|
|
|
|
protected final void setCommand(String command) {
|
|
this.command = command;
|
|
}
|
|
|
|
}
|