git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			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;
 | 
						|
    }
 | 
						|
}
 |