3 * Copyright 2001-2005 The Ant-Contrib project
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 package net
.sf
.antcontrib
.cpptasks
.compiler
;
20 import java
.io
.IOException
;
21 import java
.util
.Enumeration
;
22 import java
.util
.Vector
;
24 import net
.sf
.antcontrib
.cpptasks
.AssemblerDef
;
25 import net
.sf
.antcontrib
.cpptasks
.CCTask
;
26 import net
.sf
.antcontrib
.cpptasks
.CUtil
;
27 import net
.sf
.antcontrib
.cpptasks
.ProcessorDef
;
28 import net
.sf
.antcontrib
.cpptasks
.TargetDef
;
29 import net
.sf
.antcontrib
.cpptasks
.types
.CommandLineArgument
;
31 import org
.apache
.tools
.ant
.BuildException
;
34 * An abstract Assembler implementation which uses an external program to
35 * perform the assemble.
38 public abstract class CommandLineAssembler
extends AbstractAssembler
{
40 private String command
;
42 private String identifier
;
44 private String identifierArg
;
46 protected CommandLineAssembler (String command
, String identifierArg
,
47 String
[] sourceExtensions
, String
[] headerExtensions
,
48 String outputSuffix
) {
49 super(sourceExtensions
, headerExtensions
, outputSuffix
);
50 this.command
= command
;
51 this.identifierArg
= identifierArg
;
54 abstract protected void addImpliedArgs(Vector args
, boolean debug
,
58 * Adds command-line arguments for include directories.
60 * If relativeArgs is not null will add corresponding relative paths include
61 * switches to that vector (for use in building a configuration identifier
62 * that is consistent between machines).
65 * A vector containing the parts of the working directory,
66 * produced by CUtil.DecomposeFile.
68 * Array of include directory paths
70 * Vector of command line arguments used to execute the task
72 * Vector of command line arguments used to build the
73 * configuration identifier
75 protected void addIncludes(String baseDirPath
, File
[] includeDirs
,
76 Vector args
, Vector relativeArgs
, StringBuffer includePathId
) {
77 for (int i
= 0; i
< includeDirs
.length
; i
++) {
78 args
.addElement(getIncludeDirSwitch(includeDirs
[i
]
80 if (relativeArgs
!= null) {
81 String relative
= CUtil
.getRelativePath(baseDirPath
,
83 relativeArgs
.addElement(getIncludeDirSwitch(relative
));
84 if (includePathId
!= null) {
85 if (includePathId
.length() == 0) {
86 includePathId
.append("/I");
88 includePathId
.append(" /I");
90 includePathId
.append(relative
);
96 abstract protected String
getIncludeDirSwitch(String source
);
99 * Assembles a source file
102 public void assembler(CCTask task
, File outputDir
, String
[] sourceFiles
,
103 String
[] args
, String
[] endArgs
) throws BuildException
{
104 String command
= getCommand();
105 int baseLength
= command
.length() + args
.length
+ endArgs
.length
;
106 for (int i
= 0; i
< args
.length
; i
++) {
107 baseLength
+= args
[i
].length();
109 for (int i
= 0; i
< endArgs
.length
; i
++) {
110 baseLength
+= endArgs
[i
].length();
112 if (baseLength
> getMaximumCommandLength()) {
113 throw new BuildException(
114 "Command line is over maximum length without sepcifying source file");
116 int maxInputFilesPerCommand
= getMaximumInputFilesPerCommand();
117 int argumentCountPerInputFile
= getArgumentCountPerInputFIle();
118 for (int sourceIndex
= 0; sourceIndex
< sourceFiles
.length
;) {
119 int cmdLength
= baseLength
;
120 int firstFileNextExec
;
121 for (firstFileNextExec
= sourceIndex
; firstFileNextExec
< sourceFiles
.length
122 && (firstFileNextExec
- sourceIndex
) < maxInputFilesPerCommand
; firstFileNextExec
++) {
123 cmdLength
+= getTotalArgumentLengthForInputFile(outputDir
,
124 sourceFiles
[firstFileNextExec
]);
125 if (cmdLength
>= getMaximumCommandLength())
128 if (firstFileNextExec
== sourceIndex
) {
129 throw new BuildException(
130 "Extremely long file name, can't fit on command line");
132 int argCount
= args
.length
+ 1 + endArgs
.length
133 + (firstFileNextExec
- sourceIndex
)
134 * argumentCountPerInputFile
;
135 String
[] commandline
= new String
[argCount
];
137 commandline
[index
++] = command
;
138 for (int j
= 0; j
< args
.length
; j
++) {
139 commandline
[index
++] = args
[j
];
141 for (int j
= sourceIndex
; j
< firstFileNextExec
; j
++) {
142 for (int k
= 0; k
< argumentCountPerInputFile
; k
++) {
143 commandline
[index
++] = getInputFileArgument(outputDir
,
147 for (int j
= 0; j
< endArgs
.length
; j
++) {
148 commandline
[index
++] = endArgs
[j
];
150 int retval
= runCommand(task
, outputDir
, commandline
);
151 // if with monitor, add more code
153 throw new BuildException(this.getCommand()
154 + " failed with return code " + retval
, task
157 sourceIndex
= firstFileNextExec
;
161 protected AssemblerConfiguration
createConfiguration(final CCTask task
,
162 final LinkType linkType
, final ProcessorDef
[] baseDefs
,
163 final AssemblerDef specificDef
,
164 final TargetDef targetPlatform
) {
165 Vector args
= new Vector();
166 AssemblerDef
[] defaultProviders
= new AssemblerDef
[baseDefs
.length
+ 1];
167 for (int i
= 0; i
< baseDefs
.length
; i
++) {
168 defaultProviders
[i
+ 1] = (AssemblerDef
) baseDefs
[i
];
170 defaultProviders
[0] = specificDef
;
171 Vector cmdArgs
= new Vector();
173 // add command line arguments inherited from <cc> element
174 // any "extends" and finally and specific AssemblerDef
176 CommandLineArgument
[] commandArgs
;
177 for (int i
= defaultProviders
.length
- 1; i
>= 0; i
--) {
178 commandArgs
= defaultProviders
[i
].getActiveProcessorArgs();
179 for (int j
= 0; j
< commandArgs
.length
; j
++) {
180 if (commandArgs
[j
].getLocation() == 0) {
181 args
.addElement(commandArgs
[j
].getValue());
183 cmdArgs
.addElement(commandArgs
[j
]);
188 boolean debug
= specificDef
.getDebug(baseDefs
, 0);
189 Boolean defaultflag
= specificDef
.getDefaultflag(defaultProviders
, 1);
190 this.addImpliedArgs(args
, debug
, defaultflag
);
192 // Want to have distinct set of arguments with relative
193 // path names for includes that are used to build
194 // the configuration identifier
196 Vector relativeArgs
= (Vector
) args
.clone();
198 // add all active include an
200 StringBuffer includePathIdentifier
= new StringBuffer();
201 File baseDir
= specificDef
.getProject().getBaseDir();
204 baseDirPath
= baseDir
.getCanonicalPath();
205 } catch (IOException ex
) {
206 baseDirPath
= baseDir
.toString();
208 Vector includePath
= new Vector();
209 Vector sysIncludePath
= new Vector();
210 for (int i
= defaultProviders
.length
- 1; i
>= 0; i
--) {
211 String
[] incPath
= defaultProviders
[i
].getActiveIncludePaths();
212 for (int j
= 0; j
< incPath
.length
; j
++) {
213 includePath
.addElement(incPath
[j
]);
215 incPath
= defaultProviders
[i
].getActiveSysIncludePaths();
216 for (int j
= 0; j
< incPath
.length
; j
++) {
217 sysIncludePath
.addElement(incPath
[j
]);
220 File
[] incPath
= new File
[includePath
.size()];
221 for (int i
= 0; i
< includePath
.size(); i
++) {
222 incPath
[i
] = new File((String
) includePath
.elementAt(i
));
224 File
[] sysIncPath
= new File
[sysIncludePath
.size()];
225 for (int i
= 0; i
< sysIncludePath
.size(); i
++) {
226 sysIncPath
[i
] = new File((String
) sysIncludePath
.elementAt(i
));
228 addIncludes(baseDirPath
, incPath
, args
, relativeArgs
,
229 includePathIdentifier
);
230 addIncludes(baseDirPath
, sysIncPath
, args
, null, null);
231 StringBuffer buf
= new StringBuffer(getIdentifier());
232 for (int i
= 0; i
< relativeArgs
.size(); i
++) {
233 buf
.append(relativeArgs
.elementAt(i
));
236 buf
.setLength(buf
.length() - 1);
237 Enumeration argEnum
= cmdArgs
.elements();
239 while (argEnum
.hasMoreElements()) {
240 CommandLineArgument arg
= (CommandLineArgument
) argEnum
242 switch (arg
.getLocation()) {
244 args
.addElement(arg
.getValue());
251 String
[] endArgs
= new String
[endCount
];
252 argEnum
= cmdArgs
.elements();
254 while (argEnum
.hasMoreElements()) {
255 CommandLineArgument arg
= (CommandLineArgument
) argEnum
257 if (arg
.getLocation() == 2) {
258 endArgs
[index
++] = arg
.getValue();
261 String
[] argArray
= new String
[args
.size()];
262 args
.copyInto(argArray
);
263 return new CommandLineAssemblerConfiguration(this, incPath
, sysIncPath
,
264 new File
[0], argArray
, true, endArgs
, new String
[0]);
267 protected int getArgumentCountPerInputFile() {
271 protected abstract File
[] getEnvironmentIncludePath();
273 public String
getIdentifier() {
274 if (identifier
== null) {
275 if (identifierArg
== null) {
276 identifier
= getIdentifier(new String
[] { command
}, command
);
278 identifier
= getIdentifier(new String
[] { command
,
279 identifierArg
}, command
);
285 public final String
getCommand() {
289 abstract public int getMaximumCommandLength();
291 public void setCommand(String command
) {
292 this.command
= command
;
295 protected int getTotalArgumentLengthForInputFile(File outputDir
,
297 return inputFile
.length() + 1;
300 protected int runCommand(CCTask task
, File workingDir
, String
[] cmdline
)
301 throws BuildException
{
302 return CUtil
.runCommand(task
, workingDir
, cmdline
, false, null);
305 protected int getMaximumInputFilesPerCommand() {
306 return Integer
.MAX_VALUE
;
309 protected int getArgumentCountPerInputFIle() {
313 protected String
getInputFileArgument(File outputDir
, String filename
,
316 // if there is an embedded space,
317 // must enclose in quotes
318 if (filename
.indexOf(' ') >= 0) {
319 StringBuffer buf
= new StringBuffer("\"");
320 buf
.append(filename
);
322 return buf
.toString();