+++ /dev/null
-/*\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