]> git.proxmox.com Git - mirror_edk2.git/blob - 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
1 /*
2 *
3 * Copyright 2002-2004 The Ant-Contrib project
4 *
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17 package net.sf.antcontrib.cpptasks.compiler;
18 import java.io.File;
19 import java.io.IOException;
20 import java.util.Enumeration;
21 import java.util.Vector;
22 import net.sf.antcontrib.cpptasks.CCTask;
23 import net.sf.antcontrib.cpptasks.CUtil;
24 import net.sf.antcontrib.cpptasks.CompilerDef;
25 import net.sf.antcontrib.cpptasks.ProcessorDef;
26 import net.sf.antcontrib.cpptasks.ProcessorParam;
27 import net.sf.antcontrib.cpptasks.types.CommandLineArgument;
28 import net.sf.antcontrib.cpptasks.types.UndefineArgument;
29 import net.sf.antcontrib.cpptasks.TargetDef;
30 import org.apache.tools.ant.BuildException;
31 import org.apache.tools.ant.types.Environment;
32 import net.sf.antcontrib.cpptasks.OptimizationEnum;;
33 /**
34 * An abstract Compiler implementation which uses an external program to
35 * perform the compile.
36 *
37 * @author Adam Murdoch
38 */
39 public abstract class CommandLineCompiler extends AbstractCompiler {
40 private String command;
41 private final Environment env;
42 private String identifier;
43 private String identifierArg;
44 private boolean libtool;
45 private CommandLineCompiler libtoolCompiler;
46 private final boolean newEnvironment;
47 protected CommandLineCompiler(String command, String identifierArg,
48 String[] sourceExtensions, String[] headerExtensions,
49 String outputSuffix, boolean libtool,
50 CommandLineCompiler libtoolCompiler, boolean newEnvironment,
51 Environment env) {
52 super(sourceExtensions, headerExtensions, outputSuffix);
53 this.command = command;
54 if (libtool && libtoolCompiler != null) {
55 throw new java.lang.IllegalArgumentException(
56 "libtoolCompiler should be null when libtool is true");
57 }
58 this.libtool = libtool;
59 this.libtoolCompiler = libtoolCompiler;
60 this.identifierArg = identifierArg;
61 this.newEnvironment = newEnvironment;
62 this.env = env;
63 }
64 abstract protected void addImpliedArgs(Vector args, boolean debug,
65 boolean multithreaded, boolean exceptions, LinkType linkType,
66 Boolean rtti, OptimizationEnum optimization, Boolean defaultflag);
67 /**
68 * Adds command-line arguments for include directories.
69 *
70 * If relativeArgs is not null will add corresponding relative paths
71 * include switches to that vector (for use in building a configuration
72 * identifier that is consistent between machines).
73 *
74 * @param baseDirPaths
75 * A vector containing the parts of the working directory,
76 * produced by CUtil.DecomposeFile.
77 * @param includeDirs
78 * Array of include directory paths
79 * @param args
80 * Vector of command line arguments used to execute the task
81 * @param relativeArgs
82 * Vector of command line arguments used to build the
83 * configuration identifier
84 */
85 protected void addIncludes(String baseDirPath, File[] includeDirs,
86 Vector args, Vector relativeArgs, StringBuffer includePathId) {
87 for (int i = 0; i < includeDirs.length; i++) {
88 args.addElement(getIncludeDirSwitch(includeDirs[i]
89 .getAbsolutePath()));
90 if (relativeArgs != null) {
91 String relative = CUtil.getRelativePath(baseDirPath,
92 includeDirs[i]);
93 relativeArgs.addElement(getIncludeDirSwitch(relative));
94 if (includePathId != null) {
95 if (includePathId.length() == 0) {
96 includePathId.append("/I");
97 } else {
98 includePathId.append(" /I");
99 }
100 includePathId.append(relative);
101 }
102 }
103 }
104 }
105 abstract protected void addWarningSwitch(Vector args, int warnings);
106 protected void buildDefineArguments(CompilerDef[] defs, Vector args) {
107 //
108 // assume that we aren't inheriting defines from containing <cc>
109 //
110 UndefineArgument[] merged = defs[0].getActiveDefines();
111 for (int i = 1; i < defs.length; i++) {
112 //
113 // if we are inheriting, merge the specific defines with the
114 // containing defines
115 merged = UndefineArgument.merge(defs[i].getActiveDefines(), merged);
116 }
117 StringBuffer buf = new StringBuffer(30);
118 for (int i = 0; i < merged.length; i++) {
119 buf.setLength(0);
120 UndefineArgument current = merged[i];
121 if (current.isDefine()) {
122 getDefineSwitch(buf, current.getName(), current.getValue());
123 } else {
124 getUndefineSwitch(buf, current.getName());
125 }
126 args.addElement(buf.toString());
127 }
128 }
129 /**
130 * Compiles a source file.
131 *
132 * @author Curt Arnold
133 */
134 public void compile(CCTask task, File outputDir, String[] sourceFiles,
135 String[] args, String[] endArgs, boolean relentless,
136 CommandLineCompilerConfiguration config, ProgressMonitor monitor)
137 throws BuildException {
138 BuildException exc = null;
139 //
140 // determine length of executable name and args
141 //
142 String command = getCommand();
143 int baseLength = command.length() + args.length + endArgs.length;
144 if (libtool) {
145 baseLength += 8;
146 }
147 for (int i = 0; i < args.length; i++) {
148 baseLength += args[i].length();
149 }
150 for (int i = 0; i < endArgs.length; i++) {
151 baseLength += endArgs[i].length();
152 }
153 if (baseLength > getMaximumCommandLength()) {
154 throw new BuildException(
155 "Command line is over maximum length without specifying source file");
156 }
157 //
158 // typically either 1 or Integer.MAX_VALUE
159 //
160 int maxInputFilesPerCommand = getMaximumInputFilesPerCommand();
161 int argumentCountPerInputFile = getArgumentCountPerInputFile();
162 for (int sourceIndex = 0; sourceIndex < sourceFiles.length;) {
163 int cmdLength = baseLength;
164 int firstFileNextExec;
165 for (firstFileNextExec = sourceIndex; firstFileNextExec < sourceFiles.length
166 && (firstFileNextExec - sourceIndex) < maxInputFilesPerCommand; firstFileNextExec++) {
167 cmdLength += getTotalArgumentLengthForInputFile(outputDir,
168 sourceFiles[firstFileNextExec]);
169 if (cmdLength >= getMaximumCommandLength())
170 break;
171 }
172 if (firstFileNextExec == sourceIndex) {
173 throw new BuildException(
174 "Extremely long file name, can't fit on command line");
175 }
176 int argCount = args.length + 1 + endArgs.length
177 + (firstFileNextExec - sourceIndex)
178 * argumentCountPerInputFile;
179 if (libtool) {
180 argCount++;
181 }
182 String[] commandline = new String[argCount];
183 int index = 0;
184 if (libtool) {
185 commandline[index++] = "libtool";
186 }
187 commandline[index++] = command;
188 for (int j = 0; j < args.length; j++) {
189 commandline[index++] = args[j];
190 }
191 for (int j = sourceIndex; j < firstFileNextExec; j++) {
192 for (int k = 0; k < argumentCountPerInputFile; k++) {
193 commandline[index++] = getInputFileArgument(outputDir,
194 sourceFiles[j], k);
195 }
196 }
197 for (int j = 0; j < endArgs.length; j++) {
198 commandline[index++] = endArgs[j];
199 }
200 int retval = runCommand(task, outputDir, commandline);
201 if (monitor != null) {
202 String[] fileNames = new String[firstFileNextExec - sourceIndex];
203 for (int j = 0; j < fileNames.length; j++) {
204 fileNames[j] = sourceFiles[sourceIndex + j];
205 }
206 monitor.progress(fileNames);
207 }
208 //
209 // if the process returned a failure code and
210 // we aren't holding an exception from an earlier
211 // interation
212 if (retval != 0 && exc == null) {
213 //
214 // construct the exception
215 //
216 exc = new BuildException(this.getCommand()
217 + " failed with return code " + retval, task
218 .getLocation());
219 //
220 // and throw it now unless we are relentless
221 //
222 if (!relentless) {
223 throw exc;
224 }
225 }
226 sourceIndex = firstFileNextExec;
227 }
228 //
229 // if the compiler returned a failure value earlier
230 // then throw an exception
231 if (exc != null) {
232 throw exc;
233 }
234 }
235 protected CompilerConfiguration createConfiguration(final CCTask task,
236 final LinkType linkType,
237 final ProcessorDef[] baseDefs,
238 final CompilerDef specificDef,
239 final TargetDef targetPlatform) {
240 Vector args = new Vector();
241 CompilerDef[] defaultProviders = new CompilerDef[baseDefs.length + 1];
242 for (int i = 0; i < baseDefs.length; i++) {
243 defaultProviders[i + 1] = (CompilerDef) baseDefs[i];
244 }
245 defaultProviders[0] = specificDef;
246 Vector cmdArgs = new Vector();
247 //
248 // add command line arguments inherited from <cc> element
249 // any "extends" and finally the specific CompilerDef
250 CommandLineArgument[] commandArgs;
251 for (int i = defaultProviders.length - 1; i >= 0; i--) {
252 commandArgs = defaultProviders[i].getActiveProcessorArgs();
253 for (int j = 0; j < commandArgs.length; j++) {
254 if (commandArgs[j].getLocation() == 0) {
255 args.addElement(commandArgs[j].getValue());
256 } else {
257 cmdArgs.addElement(commandArgs[j]);
258 }
259 }
260 }
261 Vector params = new Vector();
262 //
263 // add command line arguments inherited from <cc> element
264 // any "extends" and finally the specific CompilerDef
265 ProcessorParam[] paramArray;
266 for (int i = defaultProviders.length - 1; i >= 0; i--) {
267 paramArray = defaultProviders[i].getActiveProcessorParams();
268 for (int j = 0; j < paramArray.length; j++) {
269 params.add(paramArray[j]);
270 }
271 }
272 paramArray = (ProcessorParam[]) (params
273 .toArray(new ProcessorParam[params.size()]));
274 boolean multithreaded = specificDef.getMultithreaded(defaultProviders,
275 1);
276 boolean debug = specificDef.getDebug(baseDefs, 0);
277 boolean exceptions = specificDef.getExceptions(defaultProviders, 1);
278 Boolean rtti = specificDef.getRtti(defaultProviders, 1);
279 Boolean defaultflag = specificDef.getDefaultflag(defaultProviders, 1);
280 OptimizationEnum optimization = specificDef.getOptimization(defaultProviders, 1);
281 this.addImpliedArgs(args, debug, multithreaded, exceptions, linkType, rtti, optimization, defaultflag);
282 //
283 // add all appropriate defines and undefines
284 //
285 buildDefineArguments(defaultProviders, args);
286 //
287 // Want to have distinct set of arguments with relative
288 // path names for includes that are used to build
289 // the configuration identifier
290 //
291 Vector relativeArgs = (Vector) args.clone();
292 //
293 // add all active include and sysincludes
294 //
295 StringBuffer includePathIdentifier = new StringBuffer();
296 File baseDir = specificDef.getProject().getBaseDir();
297 String baseDirPath;
298 try {
299 baseDirPath = baseDir.getCanonicalPath();
300 } catch (IOException ex) {
301 baseDirPath = baseDir.toString();
302 }
303 Vector includePath = new Vector();
304 Vector sysIncludePath = new Vector();
305 for (int i = defaultProviders.length - 1; i >= 0; i--) {
306 String[] incPath = defaultProviders[i].getActiveIncludePaths();
307 for (int j = 0; j < incPath.length; j++) {
308 includePath.addElement(incPath[j]);
309 }
310 incPath = defaultProviders[i].getActiveSysIncludePaths();
311 for (int j = 0; j < incPath.length; j++) {
312 sysIncludePath.addElement(incPath[j]);
313 }
314 }
315 File[] incPath = new File[includePath.size()];
316 for (int i = 0; i < includePath.size(); i++) {
317 incPath[i] = new File((String) includePath.elementAt(i));
318 }
319 File[] sysIncPath = new File[sysIncludePath.size()];
320 for (int i = 0; i < sysIncludePath.size(); i++) {
321 sysIncPath[i] = new File((String) sysIncludePath.elementAt(i));
322 }
323 addIncludes(baseDirPath, incPath, args, relativeArgs,
324 includePathIdentifier);
325 addIncludes(baseDirPath, sysIncPath, args, null, null);
326 StringBuffer buf = new StringBuffer(getIdentifier());
327 for (int i = 0; i < relativeArgs.size(); i++) {
328 buf.append(relativeArgs.elementAt(i));
329 buf.append(' ');
330 }
331 buf.setLength(buf.length() - 1);
332 String configId = buf.toString();
333 int warnings = specificDef.getWarnings(defaultProviders, 0);
334 addWarningSwitch(args, warnings);
335 Enumeration argEnum = cmdArgs.elements();
336 int endCount = 0;
337 while (argEnum.hasMoreElements()) {
338 CommandLineArgument arg = (CommandLineArgument) argEnum
339 .nextElement();
340 switch (arg.getLocation()) {
341 case 1 :
342 args.addElement(arg.getValue());
343 break;
344 case 2 :
345 endCount++;
346 break;
347 }
348 }
349 String[] endArgs = new String[endCount];
350 argEnum = cmdArgs.elements();
351 int index = 0;
352 while (argEnum.hasMoreElements()) {
353 CommandLineArgument arg = (CommandLineArgument) argEnum
354 .nextElement();
355 if (arg.getLocation() == 2) {
356 endArgs[index++] = arg.getValue();
357 }
358 }
359 String[] argArray = new String[args.size()];
360 args.copyInto(argArray);
361 boolean rebuild = specificDef.getRebuild(baseDefs, 0);
362 File[] envIncludePath = getEnvironmentIncludePath();
363 return new CommandLineCompilerConfiguration(this, configId, incPath,
364 sysIncPath, envIncludePath, includePathIdentifier.toString(),
365 argArray, paramArray, rebuild, endArgs);
366 }
367 protected int getArgumentCountPerInputFile() {
368 return 1;
369 }
370 protected final String getCommand() {
371 return command;
372 }
373 abstract protected void getDefineSwitch(StringBuffer buffer, String define,
374 String value);
375 protected abstract File[] getEnvironmentIncludePath();
376 public String getIdentifier() {
377 if (identifier == null) {
378 if (identifierArg == null) {
379 identifier = getIdentifier(new String[]{command}, command);
380 } else {
381 identifier = getIdentifier(
382 new String[]{command, identifierArg}, command);
383 }
384 }
385 return identifier;
386 }
387 abstract protected String getIncludeDirSwitch(String source);
388 protected String getInputFileArgument(File outputDir, String filename,
389 int index) {
390 //
391 // if there is an embedded space,
392 // must enclose in quotes
393 if (filename.indexOf(' ') >= 0) {
394 StringBuffer buf = new StringBuffer("\"");
395 buf.append(filename);
396 buf.append("\"");
397 return buf.toString();
398 }
399 return filename;
400 }
401 protected final boolean getLibtool() {
402 return libtool;
403 }
404 /**
405 * Obtains the same compiler, but with libtool set
406 *
407 * Default behavior is to ignore libtool
408 */
409 public final CommandLineCompiler getLibtoolCompiler() {
410 if (libtoolCompiler != null) {
411 return libtoolCompiler;
412 }
413 return this;
414 }
415 abstract public int getMaximumCommandLength();
416 protected int getMaximumInputFilesPerCommand() {
417 return Integer.MAX_VALUE;
418 }
419 protected int getTotalArgumentLengthForInputFile(File outputDir,
420 String inputFile) {
421 return inputFile.length() + 1;
422 }
423 abstract protected void getUndefineSwitch(StringBuffer buffer, String define);
424 /**
425 * This method is exposed so test classes can overload and test the
426 * arguments without actually spawning the compiler
427 */
428 protected int runCommand(CCTask task, File workingDir, String[] cmdline)
429 throws BuildException {
430 return CUtil.runCommand(task, workingDir, cmdline, newEnvironment, env);
431 }
432 protected final void setCommand(String command) {
433 this.command = command;
434 }
435 }