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