--- /dev/null
+/*\r
+ * \r
+ * Copyright 2001-2005 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
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.util.Enumeration;\r
+import java.util.Vector;\r
+\r
+import net.sf.antcontrib.cpptasks.AssemblerDef;\r
+import net.sf.antcontrib.cpptasks.CCTask;\r
+import net.sf.antcontrib.cpptasks.CUtil;\r
+import net.sf.antcontrib.cpptasks.ProcessorDef;\r
+import net.sf.antcontrib.cpptasks.TargetDef;\r
+import net.sf.antcontrib.cpptasks.types.CommandLineArgument;\r
+\r
+import org.apache.tools.ant.BuildException;\r
+\r
+/**\r
+ * An abstract Assembler implementation which uses an external program to\r
+ * perform the assemble.\r
+ * \r
+ */\r
+public abstract class CommandLineAssembler extends AbstractAssembler {\r
+\r
+ private String command;\r
+\r
+ private String identifier;\r
+\r
+ private String identifierArg;\r
+\r
+ protected CommandLineAssembler (String command, String identifierArg,\r
+ String[] sourceExtensions, String[] headerExtensions,\r
+ String outputSuffix) {\r
+ super(sourceExtensions, headerExtensions, outputSuffix);\r
+ this.command = command;\r
+ this.identifierArg = identifierArg;\r
+ }\r
+\r
+ abstract protected void addImpliedArgs(Vector args, boolean debug,\r
+ Boolean defaultflag);\r
+\r
+ /**\r
+ * Adds command-line arguments for include directories.\r
+ * \r
+ * If relativeArgs is not null will add corresponding relative paths include\r
+ * switches to that vector (for use in building a configuration identifier\r
+ * 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
+\r
+ abstract protected String getIncludeDirSwitch(String source);\r
+\r
+ /**\r
+ * Assembles a source file\r
+ * \r
+ */\r
+ public void assembler(CCTask task, File outputDir, String[] sourceFiles,\r
+ String[] args, String[] endArgs) throws BuildException {\r
+ String command = getCommand();\r
+ int baseLength = command.length() + args.length + endArgs.length;\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 sepcifying source file");\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
+ String[] commandline = new String[argCount];\r
+ int index = 0;\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 with monitor, add more code\r
+ if (retval != 0) {\r
+ throw new BuildException(this.getCommand()\r
+ + " failed with return code " + retval, task\r
+ .getLocation());\r
+ }\r
+ sourceIndex = firstFileNextExec;\r
+ }\r
+ }\r
+\r
+ protected AssemblerConfiguration createConfiguration(final CCTask task,\r
+ final LinkType linkType, final ProcessorDef[] baseDefs,\r
+ final AssemblerDef specificDef,\r
+ final TargetDef targetPlatform) {\r
+ Vector args = new Vector();\r
+ AssemblerDef[] defaultProviders = new AssemblerDef[baseDefs.length + 1];\r
+ for (int i = 0; i < baseDefs.length; i++) {\r
+ defaultProviders[i + 1] = (AssemblerDef) 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 and specific AssemblerDef\r
+ //\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
+ // omit param\r
+ boolean debug = specificDef.getDebug(baseDefs, 0);\r
+ Boolean defaultflag = specificDef.getDefaultflag(defaultProviders, 1);\r
+ this.addImpliedArgs(args, debug, defaultflag);\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 an\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
+ 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
+ return new CommandLineAssemblerConfiguration(this, incPath, sysIncPath,\r
+ new File[0], argArray, true, endArgs, new String[0]);\r
+ }\r
+\r
+ protected int getArgumentCountPerInputFile() {\r
+ return 1;\r
+ }\r
+\r
+ protected abstract File[] getEnvironmentIncludePath();\r
+\r
+ public String getIdentifier() {\r
+ if (identifier == null) {\r
+ if (identifierArg == null) {\r
+ identifier = getIdentifier(new String[] { command }, command);\r
+ } else {\r
+ identifier = getIdentifier(new String[] { command,\r
+ identifierArg }, command);\r
+ }\r
+ }\r
+ return identifier;\r
+ }\r
+\r
+ public final String getCommand() {\r
+ return command;\r
+ }\r
+\r
+ abstract public int getMaximumCommandLength();\r
+\r
+ public void setCommand(String command) {\r
+ this.command = command;\r
+ }\r
+\r
+ protected int getTotalArgumentLengthForInputFile(File outputDir,\r
+ String inputFile) {\r
+ return inputFile.length() + 1;\r
+ }\r
+\r
+ protected int runCommand(CCTask task, File workingDir, String[] cmdline)\r
+ throws BuildException {\r
+ return CUtil.runCommand(task, workingDir, cmdline, false, null);\r
+ }\r
+\r
+ protected int getMaximumInputFilesPerCommand() {\r
+ return Integer.MAX_VALUE;\r
+ }\r
+\r
+ protected int getArgumentCountPerInputFIle() {\r
+ return 1;\r
+ }\r
+\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
+}\r