mirror of https://github.com/acidanthera/audk.git
436 lines
18 KiB
Java
436 lines
18 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.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.CompilerDef;
|
||
|
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.UndefineArgument;
|
||
|
import net.sf.antcontrib.cpptasks.TargetDef;
|
||
|
import org.apache.tools.ant.BuildException;
|
||
|
import org.apache.tools.ant.types.Environment;
|
||
|
import net.sf.antcontrib.cpptasks.OptimizationEnum;;
|
||
|
/**
|
||
|
* An abstract Compiler implementation which uses an external program to
|
||
|
* perform the compile.
|
||
|
*
|
||
|
* @author Adam Murdoch
|
||
|
*/
|
||
|
public abstract class CommandLineCompiler extends AbstractCompiler {
|
||
|
private String command;
|
||
|
private final Environment env;
|
||
|
private String identifier;
|
||
|
private String identifierArg;
|
||
|
private boolean libtool;
|
||
|
private CommandLineCompiler libtoolCompiler;
|
||
|
private final boolean newEnvironment;
|
||
|
protected CommandLineCompiler(String command, String identifierArg,
|
||
|
String[] sourceExtensions, String[] headerExtensions,
|
||
|
String outputSuffix, boolean libtool,
|
||
|
CommandLineCompiler libtoolCompiler, boolean newEnvironment,
|
||
|
Environment env) {
|
||
|
super(sourceExtensions, headerExtensions, outputSuffix);
|
||
|
this.command = command;
|
||
|
if (libtool && libtoolCompiler != null) {
|
||
|
throw new java.lang.IllegalArgumentException(
|
||
|
"libtoolCompiler should be null when libtool is true");
|
||
|
}
|
||
|
this.libtool = libtool;
|
||
|
this.libtoolCompiler = libtoolCompiler;
|
||
|
this.identifierArg = identifierArg;
|
||
|
this.newEnvironment = newEnvironment;
|
||
|
this.env = env;
|
||
|
}
|
||
|
abstract protected void addImpliedArgs(Vector args, boolean debug,
|
||
|
boolean multithreaded, boolean exceptions, LinkType linkType,
|
||
|
Boolean rtti, OptimizationEnum optimization, Boolean defaultflag);
|
||
|
/**
|
||
|
* Adds command-line arguments for include directories.
|
||
|
*
|
||
|
* If relativeArgs is not null will add corresponding relative paths
|
||
|
* include switches to that vector (for use in building a configuration
|
||
|
* identifier that is consistent between machines).
|
||
|
*
|
||
|
* @param baseDirPaths
|
||
|
* A vector containing the parts of the working directory,
|
||
|
* produced by CUtil.DecomposeFile.
|
||
|
* @param includeDirs
|
||
|
* Array of include directory paths
|
||
|
* @param args
|
||
|
* Vector of command line arguments used to execute the task
|
||
|
* @param relativeArgs
|
||
|
* Vector of command line arguments used to build the
|
||
|
* configuration identifier
|
||
|
*/
|
||
|
protected void addIncludes(String baseDirPath, File[] includeDirs,
|
||
|
Vector args, Vector relativeArgs, StringBuffer includePathId) {
|
||
|
for (int i = 0; i < includeDirs.length; i++) {
|
||
|
args.addElement(getIncludeDirSwitch(includeDirs[i]
|
||
|
.getAbsolutePath()));
|
||
|
if (relativeArgs != null) {
|
||
|
String relative = CUtil.getRelativePath(baseDirPath,
|
||
|
includeDirs[i]);
|
||
|
relativeArgs.addElement(getIncludeDirSwitch(relative));
|
||
|
if (includePathId != null) {
|
||
|
if (includePathId.length() == 0) {
|
||
|
includePathId.append("/I");
|
||
|
} else {
|
||
|
includePathId.append(" /I");
|
||
|
}
|
||
|
includePathId.append(relative);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
abstract protected void addWarningSwitch(Vector args, int warnings);
|
||
|
protected void buildDefineArguments(CompilerDef[] defs, Vector args) {
|
||
|
//
|
||
|
// assume that we aren't inheriting defines from containing <cc>
|
||
|
//
|
||
|
UndefineArgument[] merged = defs[0].getActiveDefines();
|
||
|
for (int i = 1; i < defs.length; i++) {
|
||
|
//
|
||
|
// if we are inheriting, merge the specific defines with the
|
||
|
// containing defines
|
||
|
merged = UndefineArgument.merge(defs[i].getActiveDefines(), merged);
|
||
|
}
|
||
|
StringBuffer buf = new StringBuffer(30);
|
||
|
for (int i = 0; i < merged.length; i++) {
|
||
|
buf.setLength(0);
|
||
|
UndefineArgument current = merged[i];
|
||
|
if (current.isDefine()) {
|
||
|
getDefineSwitch(buf, current.getName(), current.getValue());
|
||
|
} else {
|
||
|
getUndefineSwitch(buf, current.getName());
|
||
|
}
|
||
|
args.addElement(buf.toString());
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Compiles a source file.
|
||
|
*
|
||
|
* @author Curt Arnold
|
||
|
*/
|
||
|
public void compile(CCTask task, File outputDir, String[] sourceFiles,
|
||
|
String[] args, String[] endArgs, boolean relentless,
|
||
|
CommandLineCompilerConfiguration config, ProgressMonitor monitor)
|
||
|
throws BuildException {
|
||
|
BuildException exc = null;
|
||
|
//
|
||
|
// determine length of executable name and args
|
||
|
//
|
||
|
String command = getCommand();
|
||
|
int baseLength = command.length() + args.length + endArgs.length;
|
||
|
if (libtool) {
|
||
|
baseLength += 8;
|
||
|
}
|
||
|
for (int i = 0; i < args.length; i++) {
|
||
|
baseLength += args[i].length();
|
||
|
}
|
||
|
for (int i = 0; i < endArgs.length; i++) {
|
||
|
baseLength += endArgs[i].length();
|
||
|
}
|
||
|
if (baseLength > getMaximumCommandLength()) {
|
||
|
throw new BuildException(
|
||
|
"Command line is over maximum length without specifying source file");
|
||
|
}
|
||
|
//
|
||
|
// typically either 1 or Integer.MAX_VALUE
|
||
|
//
|
||
|
int maxInputFilesPerCommand = getMaximumInputFilesPerCommand();
|
||
|
int argumentCountPerInputFile = getArgumentCountPerInputFile();
|
||
|
for (int sourceIndex = 0; sourceIndex < sourceFiles.length;) {
|
||
|
int cmdLength = baseLength;
|
||
|
int firstFileNextExec;
|
||
|
for (firstFileNextExec = sourceIndex; firstFileNextExec < sourceFiles.length
|
||
|
&& (firstFileNextExec - sourceIndex) < maxInputFilesPerCommand; firstFileNextExec++) {
|
||
|
cmdLength += getTotalArgumentLengthForInputFile(outputDir,
|
||
|
sourceFiles[firstFileNextExec]);
|
||
|
if (cmdLength >= getMaximumCommandLength())
|
||
|
break;
|
||
|
}
|
||
|
if (firstFileNextExec == sourceIndex) {
|
||
|
throw new BuildException(
|
||
|
"Extremely long file name, can't fit on command line");
|
||
|
}
|
||
|
int argCount = args.length + 1 + endArgs.length
|
||
|
+ (firstFileNextExec - sourceIndex)
|
||
|
* argumentCountPerInputFile;
|
||
|
if (libtool) {
|
||
|
argCount++;
|
||
|
}
|
||
|
String[] commandline = new String[argCount];
|
||
|
int index = 0;
|
||
|
if (libtool) {
|
||
|
commandline[index++] = "libtool";
|
||
|
}
|
||
|
commandline[index++] = command;
|
||
|
for (int j = 0; j < args.length; j++) {
|
||
|
commandline[index++] = args[j];
|
||
|
}
|
||
|
for (int j = sourceIndex; j < firstFileNextExec; j++) {
|
||
|
for (int k = 0; k < argumentCountPerInputFile; k++) {
|
||
|
commandline[index++] = getInputFileArgument(outputDir,
|
||
|
sourceFiles[j], k);
|
||
|
}
|
||
|
}
|
||
|
for (int j = 0; j < endArgs.length; j++) {
|
||
|
commandline[index++] = endArgs[j];
|
||
|
}
|
||
|
int retval = runCommand(task, outputDir, commandline);
|
||
|
if (monitor != null) {
|
||
|
String[] fileNames = new String[firstFileNextExec - sourceIndex];
|
||
|
for (int j = 0; j < fileNames.length; j++) {
|
||
|
fileNames[j] = sourceFiles[sourceIndex + j];
|
||
|
}
|
||
|
monitor.progress(fileNames);
|
||
|
}
|
||
|
//
|
||
|
// if the process returned a failure code and
|
||
|
// we aren't holding an exception from an earlier
|
||
|
// interation
|
||
|
if (retval != 0 && exc == null) {
|
||
|
//
|
||
|
// construct the exception
|
||
|
//
|
||
|
exc = new BuildException(this.getCommand()
|
||
|
+ " failed with return code " + retval, task
|
||
|
.getLocation());
|
||
|
//
|
||
|
// and throw it now unless we are relentless
|
||
|
//
|
||
|
if (!relentless) {
|
||
|
throw exc;
|
||
|
}
|
||
|
}
|
||
|
sourceIndex = firstFileNextExec;
|
||
|
}
|
||
|
//
|
||
|
// if the compiler returned a failure value earlier
|
||
|
// then throw an exception
|
||
|
if (exc != null) {
|
||
|
throw exc;
|
||
|
}
|
||
|
}
|
||
|
protected CompilerConfiguration createConfiguration(final CCTask task,
|
||
|
final LinkType linkType,
|
||
|
final ProcessorDef[] baseDefs,
|
||
|
final CompilerDef specificDef,
|
||
|
final TargetDef targetPlatform) {
|
||
|
Vector args = new Vector();
|
||
|
CompilerDef[] defaultProviders = new CompilerDef[baseDefs.length + 1];
|
||
|
for (int i = 0; i < baseDefs.length; i++) {
|
||
|
defaultProviders[i + 1] = (CompilerDef) baseDefs[i];
|
||
|
}
|
||
|
defaultProviders[0] = specificDef;
|
||
|
Vector cmdArgs = new Vector();
|
||
|
//
|
||
|
// 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++) {
|
||
|
if (commandArgs[j].getLocation() == 0) {
|
||
|
args.addElement(commandArgs[j].getValue());
|
||
|
} else {
|
||
|
cmdArgs.addElement(commandArgs[j]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
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 multithreaded = specificDef.getMultithreaded(defaultProviders,
|
||
|
1);
|
||
|
boolean debug = specificDef.getDebug(baseDefs, 0);
|
||
|
boolean exceptions = specificDef.getExceptions(defaultProviders, 1);
|
||
|
Boolean rtti = specificDef.getRtti(defaultProviders, 1);
|
||
|
Boolean defaultflag = specificDef.getDefaultflag(defaultProviders, 1);
|
||
|
OptimizationEnum optimization = specificDef.getOptimization(defaultProviders, 1);
|
||
|
this.addImpliedArgs(args, debug, multithreaded, exceptions, linkType, rtti, optimization, defaultflag);
|
||
|
//
|
||
|
// add all appropriate defines and undefines
|
||
|
//
|
||
|
buildDefineArguments(defaultProviders, args);
|
||
|
//
|
||
|
// Want to have distinct set of arguments with relative
|
||
|
// path names for includes that are used to build
|
||
|
// the configuration identifier
|
||
|
//
|
||
|
Vector relativeArgs = (Vector) args.clone();
|
||
|
//
|
||
|
// add all active include and sysincludes
|
||
|
//
|
||
|
StringBuffer includePathIdentifier = new StringBuffer();
|
||
|
File baseDir = specificDef.getProject().getBaseDir();
|
||
|
String baseDirPath;
|
||
|
try {
|
||
|
baseDirPath = baseDir.getCanonicalPath();
|
||
|
} catch (IOException ex) {
|
||
|
baseDirPath = baseDir.toString();
|
||
|
}
|
||
|
Vector includePath = new Vector();
|
||
|
Vector sysIncludePath = new Vector();
|
||
|
for (int i = defaultProviders.length - 1; i >= 0; i--) {
|
||
|
String[] incPath = defaultProviders[i].getActiveIncludePaths();
|
||
|
for (int j = 0; j < incPath.length; j++) {
|
||
|
includePath.addElement(incPath[j]);
|
||
|
}
|
||
|
incPath = defaultProviders[i].getActiveSysIncludePaths();
|
||
|
for (int j = 0; j < incPath.length; j++) {
|
||
|
sysIncludePath.addElement(incPath[j]);
|
||
|
}
|
||
|
}
|
||
|
File[] incPath = new File[includePath.size()];
|
||
|
for (int i = 0; i < includePath.size(); i++) {
|
||
|
incPath[i] = new File((String) includePath.elementAt(i));
|
||
|
}
|
||
|
File[] sysIncPath = new File[sysIncludePath.size()];
|
||
|
for (int i = 0; i < sysIncludePath.size(); i++) {
|
||
|
sysIncPath[i] = new File((String) sysIncludePath.elementAt(i));
|
||
|
}
|
||
|
addIncludes(baseDirPath, incPath, args, relativeArgs,
|
||
|
includePathIdentifier);
|
||
|
addIncludes(baseDirPath, sysIncPath, args, null, null);
|
||
|
StringBuffer buf = new StringBuffer(getIdentifier());
|
||
|
for (int i = 0; i < relativeArgs.size(); i++) {
|
||
|
buf.append(relativeArgs.elementAt(i));
|
||
|
buf.append(' ');
|
||
|
}
|
||
|
buf.setLength(buf.length() - 1);
|
||
|
String configId = buf.toString();
|
||
|
int warnings = specificDef.getWarnings(defaultProviders, 0);
|
||
|
addWarningSwitch(args, warnings);
|
||
|
Enumeration argEnum = cmdArgs.elements();
|
||
|
int endCount = 0;
|
||
|
while (argEnum.hasMoreElements()) {
|
||
|
CommandLineArgument arg = (CommandLineArgument) argEnum
|
||
|
.nextElement();
|
||
|
switch (arg.getLocation()) {
|
||
|
case 1 :
|
||
|
args.addElement(arg.getValue());
|
||
|
break;
|
||
|
case 2 :
|
||
|
endCount++;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
String[] endArgs = new String[endCount];
|
||
|
argEnum = cmdArgs.elements();
|
||
|
int index = 0;
|
||
|
while (argEnum.hasMoreElements()) {
|
||
|
CommandLineArgument arg = (CommandLineArgument) argEnum
|
||
|
.nextElement();
|
||
|
if (arg.getLocation() == 2) {
|
||
|
endArgs[index++] = arg.getValue();
|
||
|
}
|
||
|
}
|
||
|
String[] argArray = new String[args.size()];
|
||
|
args.copyInto(argArray);
|
||
|
boolean rebuild = specificDef.getRebuild(baseDefs, 0);
|
||
|
File[] envIncludePath = getEnvironmentIncludePath();
|
||
|
return new CommandLineCompilerConfiguration(this, configId, incPath,
|
||
|
sysIncPath, envIncludePath, includePathIdentifier.toString(),
|
||
|
argArray, paramArray, rebuild, endArgs);
|
||
|
}
|
||
|
protected int getArgumentCountPerInputFile() {
|
||
|
return 1;
|
||
|
}
|
||
|
protected final String getCommand() {
|
||
|
return command;
|
||
|
}
|
||
|
abstract protected void getDefineSwitch(StringBuffer buffer, String define,
|
||
|
String value);
|
||
|
protected abstract File[] getEnvironmentIncludePath();
|
||
|
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;
|
||
|
}
|
||
|
abstract protected String getIncludeDirSwitch(String source);
|
||
|
protected String getInputFileArgument(File outputDir, String filename,
|
||
|
int index) {
|
||
|
//
|
||
|
// if there is an embedded space,
|
||
|
// must enclose in quotes
|
||
|
if (filename.indexOf(' ') >= 0) {
|
||
|
StringBuffer buf = new StringBuffer("\"");
|
||
|
buf.append(filename);
|
||
|
buf.append("\"");
|
||
|
return buf.toString();
|
||
|
}
|
||
|
return filename;
|
||
|
}
|
||
|
protected final boolean getLibtool() {
|
||
|
return libtool;
|
||
|
}
|
||
|
/**
|
||
|
* Obtains the same compiler, but with libtool set
|
||
|
*
|
||
|
* Default behavior is to ignore libtool
|
||
|
*/
|
||
|
public final CommandLineCompiler getLibtoolCompiler() {
|
||
|
if (libtoolCompiler != null) {
|
||
|
return libtoolCompiler;
|
||
|
}
|
||
|
return this;
|
||
|
}
|
||
|
abstract public int getMaximumCommandLength();
|
||
|
protected int getMaximumInputFilesPerCommand() {
|
||
|
return Integer.MAX_VALUE;
|
||
|
}
|
||
|
protected int getTotalArgumentLengthForInputFile(File outputDir,
|
||
|
String inputFile) {
|
||
|
return inputFile.length() + 1;
|
||
|
}
|
||
|
abstract protected void getUndefineSwitch(StringBuffer buffer, String define);
|
||
|
/**
|
||
|
* 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;
|
||
|
}
|
||
|
}
|