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