]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Tools/Java/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineCompiler.java
Restructuring for better separation of Tool packages.
[mirror_edk2.git] / Tools / Java / Source / Cpptasks / net / sf / antcontrib / cpptasks / compiler / CommandLineCompiler.java
diff --git a/Tools/Java/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineCompiler.java b/Tools/Java/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineCompiler.java
new file mode 100644 (file)
index 0000000..3f45ce5
--- /dev/null
@@ -0,0 +1,435 @@
+/*\r
+ * \r
+ * Copyright 2002-2004 The Ant-Contrib project\r
+ *\r
+ *  Licensed under the Apache License, Version 2.0 (the "License");\r
+ *  you may not use this file except in compliance with the License.\r
+ *  You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *  Unless required by applicable law or agreed to in writing, software\r
+ *  distributed under the License is distributed on an "AS IS" BASIS,\r
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *  See the License for the specific language governing permissions and\r
+ *  limitations under the License.\r
+ */\r
+package net.sf.antcontrib.cpptasks.compiler;\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.util.Enumeration;\r
+import java.util.Vector;\r
+import net.sf.antcontrib.cpptasks.CCTask;\r
+import net.sf.antcontrib.cpptasks.CUtil;\r
+import net.sf.antcontrib.cpptasks.CompilerDef;\r
+import net.sf.antcontrib.cpptasks.ProcessorDef;\r
+import net.sf.antcontrib.cpptasks.ProcessorParam;\r
+import net.sf.antcontrib.cpptasks.types.CommandLineArgument;\r
+import net.sf.antcontrib.cpptasks.types.UndefineArgument;\r
+import net.sf.antcontrib.cpptasks.TargetDef;\r
+import org.apache.tools.ant.BuildException;\r
+import org.apache.tools.ant.types.Environment;\r
+import net.sf.antcontrib.cpptasks.OptimizationEnum;;\r
+/**\r
+ * An abstract Compiler implementation which uses an external program to\r
+ * perform the compile.\r
+ * \r
+ * @author Adam Murdoch\r
+ */\r
+public abstract class CommandLineCompiler extends AbstractCompiler {\r
+    private String command;\r
+    private final Environment env;\r
+    private String identifier;\r
+    private String identifierArg;\r
+    private boolean libtool;\r
+    private CommandLineCompiler libtoolCompiler;\r
+    private final boolean newEnvironment;\r
+    protected CommandLineCompiler(String command, String identifierArg,\r
+            String[] sourceExtensions, String[] headerExtensions,\r
+            String outputSuffix, boolean libtool,\r
+            CommandLineCompiler libtoolCompiler, boolean newEnvironment,\r
+            Environment env) {\r
+        super(sourceExtensions, headerExtensions, outputSuffix);\r
+        this.command = command;\r
+        if (libtool && libtoolCompiler != null) {\r
+            throw new java.lang.IllegalArgumentException(\r
+                    "libtoolCompiler should be null when libtool is true");\r
+        }\r
+        this.libtool = libtool;\r
+        this.libtoolCompiler = libtoolCompiler;\r
+        this.identifierArg = identifierArg;\r
+        this.newEnvironment = newEnvironment;\r
+        this.env = env;\r
+    }\r
+    abstract protected void addImpliedArgs(Vector args, boolean debug,\r
+            boolean multithreaded, boolean exceptions, LinkType linkType,\r
+                       Boolean rtti, OptimizationEnum optimization, Boolean defaultflag);\r
+    /**\r
+     * Adds command-line arguments for include directories.\r
+     * \r
+     * If relativeArgs is not null will add corresponding relative paths\r
+     * include switches to that vector (for use in building a configuration\r
+     * identifier that is consistent between machines).\r
+     * \r
+     * @param baseDirPaths\r
+     *            A vector containing the parts of the working directory,\r
+     *            produced by CUtil.DecomposeFile.\r
+     * @param includeDirs\r
+     *            Array of include directory paths\r
+     * @param args\r
+     *            Vector of command line arguments used to execute the task\r
+     * @param relativeArgs\r
+     *            Vector of command line arguments used to build the\r
+     *            configuration identifier\r
+     */\r
+    protected void addIncludes(String baseDirPath, File[] includeDirs,\r
+            Vector args, Vector relativeArgs, StringBuffer includePathId) {\r
+        for (int i = 0; i < includeDirs.length; i++) {\r
+            args.addElement(getIncludeDirSwitch(includeDirs[i]\r
+                    .getAbsolutePath()));\r
+            if (relativeArgs != null) {\r
+                String relative = CUtil.getRelativePath(baseDirPath,\r
+                        includeDirs[i]);\r
+                relativeArgs.addElement(getIncludeDirSwitch(relative));\r
+                if (includePathId != null) {\r
+                    if (includePathId.length() == 0) {\r
+                        includePathId.append("/I");\r
+                    } else {\r
+                        includePathId.append(" /I");\r
+                    }\r
+                    includePathId.append(relative);\r
+                }\r
+            }\r
+        }\r
+    }\r
+    abstract protected void addWarningSwitch(Vector args, int warnings);\r
+    protected void buildDefineArguments(CompilerDef[] defs, Vector args) {\r
+        //\r
+        //   assume that we aren't inheriting defines from containing <cc>\r
+        //\r
+        UndefineArgument[] merged = defs[0].getActiveDefines();\r
+        for (int i = 1; i < defs.length; i++) {\r
+            //\r
+            //  if we are inheriting, merge the specific defines with the\r
+            //      containing defines\r
+            merged = UndefineArgument.merge(defs[i].getActiveDefines(), merged);\r
+        }\r
+        StringBuffer buf = new StringBuffer(30);\r
+        for (int i = 0; i < merged.length; i++) {\r
+            buf.setLength(0);\r
+            UndefineArgument current = merged[i];\r
+            if (current.isDefine()) {\r
+                getDefineSwitch(buf, current.getName(), current.getValue());\r
+            } else {\r
+                getUndefineSwitch(buf, current.getName());\r
+            }\r
+            args.addElement(buf.toString());\r
+        }\r
+    }\r
+    /**\r
+     * Compiles a source file.\r
+     * \r
+     * @author Curt Arnold\r
+     */\r
+    public void compile(CCTask task, File outputDir, String[] sourceFiles,\r
+            String[] args, String[] endArgs, boolean relentless,\r
+            CommandLineCompilerConfiguration config, ProgressMonitor monitor)\r
+            throws BuildException {\r
+        BuildException exc = null;\r
+        //\r
+        //   determine length of executable name and args\r
+        //\r
+        String command = getCommand();\r
+        int baseLength = command.length() + args.length + endArgs.length;\r
+        if (libtool) {\r
+            baseLength += 8;\r
+        }\r
+        for (int i = 0; i < args.length; i++) {\r
+            baseLength += args[i].length();\r
+        }\r
+        for (int i = 0; i < endArgs.length; i++) {\r
+            baseLength += endArgs[i].length();\r
+        }\r
+        if (baseLength > getMaximumCommandLength()) {\r
+            throw new BuildException(\r
+                    "Command line is over maximum length without specifying source file");\r
+        }\r
+        //\r
+        //  typically either 1 or Integer.MAX_VALUE\r
+        //\r
+        int maxInputFilesPerCommand = getMaximumInputFilesPerCommand();\r
+        int argumentCountPerInputFile = getArgumentCountPerInputFile();\r
+        for (int sourceIndex = 0; sourceIndex < sourceFiles.length;) {\r
+            int cmdLength = baseLength;\r
+            int firstFileNextExec;\r
+            for (firstFileNextExec = sourceIndex; firstFileNextExec < sourceFiles.length\r
+                    && (firstFileNextExec - sourceIndex) < maxInputFilesPerCommand; firstFileNextExec++) {\r
+                cmdLength += getTotalArgumentLengthForInputFile(outputDir,\r
+                        sourceFiles[firstFileNextExec]);\r
+                if (cmdLength >= getMaximumCommandLength())\r
+                    break;\r
+            }\r
+            if (firstFileNextExec == sourceIndex) {\r
+                throw new BuildException(\r
+                        "Extremely long file name, can't fit on command line");\r
+            }\r
+            int argCount = args.length + 1 + endArgs.length\r
+                    + (firstFileNextExec - sourceIndex)\r
+                    * argumentCountPerInputFile;\r
+            if (libtool) {\r
+                argCount++;\r
+            }\r
+            String[] commandline = new String[argCount];\r
+            int index = 0;\r
+            if (libtool) {\r
+                commandline[index++] = "libtool";\r
+            }\r
+            commandline[index++] = command;\r
+            for (int j = 0; j < args.length; j++) {\r
+                commandline[index++] = args[j];\r
+            }\r
+            for (int j = sourceIndex; j < firstFileNextExec; j++) {\r
+                for (int k = 0; k < argumentCountPerInputFile; k++) {\r
+                    commandline[index++] = getInputFileArgument(outputDir,\r
+                            sourceFiles[j], k);\r
+                }\r
+            }\r
+            for (int j = 0; j < endArgs.length; j++) {\r
+                commandline[index++] = endArgs[j];\r
+            }\r
+            int retval = runCommand(task, outputDir, commandline);\r
+            if (monitor != null) {\r
+                String[] fileNames = new String[firstFileNextExec - sourceIndex];\r
+                for (int j = 0; j < fileNames.length; j++) {\r
+                    fileNames[j] = sourceFiles[sourceIndex + j];\r
+                }\r
+                monitor.progress(fileNames);\r
+            }\r
+            //\r
+            //   if the process returned a failure code and\r
+            //      we aren't holding an exception from an earlier\r
+            //      interation\r
+            if (retval != 0 && exc == null) {\r
+                //\r
+                //   construct the exception\r
+                //\r
+                exc = new BuildException(this.getCommand()\r
+                        + " failed with return code " + retval, task\r
+                        .getLocation());\r
+                //\r
+                //   and throw it now unless we are relentless\r
+                //\r
+                if (!relentless) {\r
+                    throw exc;\r
+                }\r
+            }\r
+            sourceIndex = firstFileNextExec;\r
+        }\r
+        //\r
+        //   if the compiler returned a failure value earlier\r
+        //      then throw an exception\r
+        if (exc != null) {\r
+            throw exc;\r
+        }\r
+    }\r
+    protected CompilerConfiguration createConfiguration(final CCTask task,\r
+            final LinkType linkType, \r
+                       final ProcessorDef[] baseDefs, \r
+                       final CompilerDef specificDef,\r
+                       final TargetDef targetPlatform) {\r
+        Vector args = new Vector();\r
+        CompilerDef[] defaultProviders = new CompilerDef[baseDefs.length + 1];\r
+        for (int i = 0; i < baseDefs.length; i++) {\r
+            defaultProviders[i + 1] = (CompilerDef) baseDefs[i];\r
+        }\r
+        defaultProviders[0] = specificDef;\r
+        Vector cmdArgs = new Vector();\r
+        //\r
+        //   add command line arguments inherited from <cc> element\r
+        //     any "extends" and finally the specific CompilerDef\r
+        CommandLineArgument[] commandArgs;\r
+        for (int i = defaultProviders.length - 1; i >= 0; i--) {\r
+            commandArgs = defaultProviders[i].getActiveProcessorArgs();\r
+            for (int j = 0; j < commandArgs.length; j++) {\r
+                if (commandArgs[j].getLocation() == 0) {\r
+                    args.addElement(commandArgs[j].getValue());\r
+                } else {\r
+                    cmdArgs.addElement(commandArgs[j]);\r
+                }\r
+            }\r
+        }\r
+        Vector params = new Vector();\r
+        //\r
+        //   add command line arguments inherited from <cc> element\r
+        //     any "extends" and finally the specific CompilerDef\r
+        ProcessorParam[] paramArray;\r
+        for (int i = defaultProviders.length - 1; i >= 0; i--) {\r
+            paramArray = defaultProviders[i].getActiveProcessorParams();\r
+            for (int j = 0; j < paramArray.length; j++) {\r
+                params.add(paramArray[j]);\r
+            }\r
+        }\r
+        paramArray = (ProcessorParam[]) (params\r
+                .toArray(new ProcessorParam[params.size()]));\r
+        boolean multithreaded = specificDef.getMultithreaded(defaultProviders,\r
+                1);\r
+        boolean debug = specificDef.getDebug(baseDefs, 0);\r
+        boolean exceptions = specificDef.getExceptions(defaultProviders, 1);\r
+        Boolean rtti = specificDef.getRtti(defaultProviders, 1);\r
+        Boolean defaultflag = specificDef.getDefaultflag(defaultProviders, 1);\r
+        OptimizationEnum optimization = specificDef.getOptimization(defaultProviders, 1);\r
+        this.addImpliedArgs(args, debug, multithreaded, exceptions, linkType, rtti, optimization, defaultflag);\r
+        //\r
+        //    add all appropriate defines and undefines\r
+        //\r
+        buildDefineArguments(defaultProviders, args);\r
+        //\r
+        //   Want to have distinct set of arguments with relative\r
+        //      path names for includes that are used to build\r
+        //      the configuration identifier\r
+        //\r
+        Vector relativeArgs = (Vector) args.clone();\r
+        //\r
+        //    add all active include and sysincludes\r
+        //\r
+        StringBuffer includePathIdentifier = new StringBuffer();\r
+        File baseDir = specificDef.getProject().getBaseDir();\r
+        String baseDirPath;\r
+        try {\r
+            baseDirPath = baseDir.getCanonicalPath();\r
+        } catch (IOException ex) {\r
+            baseDirPath = baseDir.toString();\r
+        }\r
+        Vector includePath = new Vector();\r
+        Vector sysIncludePath = new Vector();\r
+        for (int i = defaultProviders.length - 1; i >= 0; i--) {\r
+            String[] incPath = defaultProviders[i].getActiveIncludePaths();\r
+            for (int j = 0; j < incPath.length; j++) {\r
+                includePath.addElement(incPath[j]);\r
+            }\r
+            incPath = defaultProviders[i].getActiveSysIncludePaths();\r
+            for (int j = 0; j < incPath.length; j++) {\r
+                sysIncludePath.addElement(incPath[j]);\r
+            }\r
+        }\r
+        File[] incPath = new File[includePath.size()];\r
+        for (int i = 0; i < includePath.size(); i++) {\r
+            incPath[i] = new File((String) includePath.elementAt(i));\r
+        }\r
+        File[] sysIncPath = new File[sysIncludePath.size()];\r
+        for (int i = 0; i < sysIncludePath.size(); i++) {\r
+            sysIncPath[i] = new File((String) sysIncludePath.elementAt(i));\r
+        }\r
+        addIncludes(baseDirPath, incPath, args, relativeArgs,\r
+                includePathIdentifier);\r
+        addIncludes(baseDirPath, sysIncPath, args, null, null);\r
+        StringBuffer buf = new StringBuffer(getIdentifier());\r
+        for (int i = 0; i < relativeArgs.size(); i++) {\r
+            buf.append(relativeArgs.elementAt(i));\r
+            buf.append(' ');\r
+        }\r
+        buf.setLength(buf.length() - 1);\r
+        String configId = buf.toString();\r
+        int warnings = specificDef.getWarnings(defaultProviders, 0);\r
+        addWarningSwitch(args, warnings);\r
+        Enumeration argEnum = cmdArgs.elements();\r
+        int endCount = 0;\r
+        while (argEnum.hasMoreElements()) {\r
+            CommandLineArgument arg = (CommandLineArgument) argEnum\r
+                    .nextElement();\r
+            switch (arg.getLocation()) {\r
+                case 1 :\r
+                    args.addElement(arg.getValue());\r
+                    break;\r
+                case 2 :\r
+                    endCount++;\r
+                    break;\r
+            }\r
+        }\r
+        String[] endArgs = new String[endCount];\r
+        argEnum = cmdArgs.elements();\r
+        int index = 0;\r
+        while (argEnum.hasMoreElements()) {\r
+            CommandLineArgument arg = (CommandLineArgument) argEnum\r
+                    .nextElement();\r
+            if (arg.getLocation() == 2) {\r
+                endArgs[index++] = arg.getValue();\r
+            }\r
+        }\r
+        String[] argArray = new String[args.size()];\r
+        args.copyInto(argArray);\r
+        boolean rebuild = specificDef.getRebuild(baseDefs, 0);\r
+        File[] envIncludePath = getEnvironmentIncludePath();\r
+        return new CommandLineCompilerConfiguration(this, configId, incPath,\r
+                sysIncPath, envIncludePath, includePathIdentifier.toString(),\r
+                argArray, paramArray, rebuild, endArgs);\r
+    }\r
+    protected int getArgumentCountPerInputFile() {\r
+        return 1;\r
+    }\r
+    protected final String getCommand() {\r
+        return command;\r
+    }\r
+    abstract protected void getDefineSwitch(StringBuffer buffer, String define,\r
+            String value);\r
+    protected abstract File[] getEnvironmentIncludePath();\r
+    public String getIdentifier() {\r
+        if (identifier == null) {\r
+            if (identifierArg == null) {\r
+                identifier = getIdentifier(new String[]{command}, command);\r
+            } else {\r
+                identifier = getIdentifier(\r
+                        new String[]{command, identifierArg}, command);\r
+            }\r
+        }\r
+        return identifier;\r
+    }\r
+    abstract protected String getIncludeDirSwitch(String source);\r
+    protected String getInputFileArgument(File outputDir, String filename,\r
+            int index) {\r
+        //\r
+        //   if there is an embedded space,\r
+        //      must enclose in quotes\r
+        if (filename.indexOf(' ') >= 0) {\r
+            StringBuffer buf = new StringBuffer("\"");\r
+            buf.append(filename);\r
+            buf.append("\"");\r
+            return buf.toString();\r
+        }\r
+        return filename;\r
+    }\r
+    protected final boolean getLibtool() {\r
+        return libtool;\r
+    }\r
+    /**\r
+     * Obtains the same compiler, but with libtool set\r
+     * \r
+     * Default behavior is to ignore libtool\r
+     */\r
+    public final CommandLineCompiler getLibtoolCompiler() {\r
+        if (libtoolCompiler != null) {\r
+            return libtoolCompiler;\r
+        }\r
+        return this;\r
+    }\r
+    abstract public int getMaximumCommandLength();\r
+    protected int getMaximumInputFilesPerCommand() {\r
+        return Integer.MAX_VALUE;\r
+    }\r
+    protected int getTotalArgumentLengthForInputFile(File outputDir,\r
+            String inputFile) {\r
+        return inputFile.length() + 1;\r
+    }\r
+    abstract protected void getUndefineSwitch(StringBuffer buffer, String define);\r
+    /**\r
+     * This method is exposed so test classes can overload and test the\r
+     * arguments without actually spawning the compiler\r
+     */\r
+    protected int runCommand(CCTask task, File workingDir, String[] cmdline)\r
+            throws BuildException {\r
+        return CUtil.runCommand(task, workingDir, cmdline, newEnvironment, env);\r
+    }\r
+    protected final void setCommand(String command) {\r
+        this.command = command;\r
+    }\r
+}\r