]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/Source/Cpptasks/net/sf/antcontrib/cpptasks/compiler/CommandLineLinker.java
Changed spelling to manifest
[mirror_edk2.git] / Tools / Source / Cpptasks / net / sf / antcontrib / cpptasks / compiler / CommandLineLinker.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
19 import java.io.File;
20 import java.io.FileWriter;
21 import java.io.IOException;
22 import java.util.Enumeration;
23 import java.util.Vector;
24
25 import net.sf.antcontrib.cpptasks.CCTask;
26 import net.sf.antcontrib.cpptasks.CUtil;
27 import net.sf.antcontrib.cpptasks.LinkerDef;
28 import net.sf.antcontrib.cpptasks.ProcessorDef;
29 import net.sf.antcontrib.cpptasks.ProcessorParam;
30 import net.sf.antcontrib.cpptasks.types.CommandLineArgument;
31 import net.sf.antcontrib.cpptasks.types.LibrarySet;
32 import net.sf.antcontrib.cpptasks.TargetDef;
33
34 import org.apache.tools.ant.BuildException;
35 import org.apache.tools.ant.types.Environment;
36
37
38 /**
39 * An abstract Linker implementation that performs the link via an external
40 * command.
41 *
42 * @author Adam Murdoch
43 */
44 public abstract class CommandLineLinker extends AbstractLinker
45 {
46 private String command;
47 private Environment env = null;
48 private String identifier;
49 private String identifierArg;
50 private boolean isLibtool;
51 private String[] librarySets;
52 private CommandLineLinker libtoolLinker;
53 private boolean newEnvironment = false;
54 private String outputSuffix;
55
56
57 /** Creates a comand line linker invocation */
58 public CommandLineLinker(String command,
59 String identifierArg,
60 String[] extensions,
61 String[] ignoredExtensions, String outputSuffix,
62 boolean isLibtool, CommandLineLinker libtoolLinker)
63 {
64 super(extensions, ignoredExtensions);
65 this.command = command;
66 this.identifierArg = identifierArg;
67 this.outputSuffix = outputSuffix;
68 this.isLibtool = isLibtool;
69 this.libtoolLinker = libtoolLinker;
70 }
71 protected abstract void addBase(long base, Vector args);
72
73 protected abstract void addFixed(Boolean fixed, Vector args);
74
75 abstract protected void addImpliedArgs(boolean debug,
76 LinkType linkType, Vector args, Boolean defaultflag);
77 protected abstract void addIncremental(boolean incremental, Vector args);
78
79 //
80 // Windows processors handle these through file list
81 //
82 protected String[] addLibrarySets(CCTask task, LibrarySet[] libsets, Vector preargs,
83 Vector midargs, Vector endargs) {
84 return null;
85 }
86 protected abstract void addMap(boolean map, Vector args);
87 protected abstract void addStack(int stack, Vector args);
88 protected abstract void addEntry(String entry, Vector args);
89
90 protected LinkerConfiguration createConfiguration(
91 CCTask task,
92 LinkType linkType,
93 ProcessorDef[] baseDefs, LinkerDef specificDef, TargetDef targetPlatform) {
94
95 Vector preargs = new Vector();
96 Vector midargs = new Vector();
97 Vector endargs = new Vector();
98 Vector[] args = new Vector[] { preargs, midargs, endargs };
99
100 LinkerDef[] defaultProviders = new LinkerDef[baseDefs.length+1];
101 defaultProviders[0] = specificDef;
102 for(int i = 0; i < baseDefs.length; i++) {
103 defaultProviders[i+1] = (LinkerDef) baseDefs[i];
104 }
105 //
106 // add command line arguments inherited from <cc> element
107 // any "extends" and finally the specific CompilerDef
108 CommandLineArgument[] commandArgs;
109 for(int i = defaultProviders.length-1; i >= 0; i--) {
110 commandArgs = defaultProviders[i].getActiveProcessorArgs();
111 for(int j = 0; j < commandArgs.length; j++) {
112 args[commandArgs[j].getLocation()].
113 addElement(commandArgs[j].getValue());
114 }
115 }
116
117 Vector params = new Vector();
118 //
119 // add command line arguments inherited from <cc> element
120 // any "extends" and finally the specific CompilerDef
121 ProcessorParam[] paramArray;
122 for (int i = defaultProviders.length - 1; i >= 0; i--) {
123 paramArray = defaultProviders[i].getActiveProcessorParams();
124 for (int j = 0; j < paramArray.length; j++) {
125 params.add(paramArray[j]);
126 }
127 }
128
129 paramArray = (ProcessorParam[])(params.toArray(new ProcessorParam[params.size()]));
130
131 boolean debug = specificDef.getDebug(baseDefs,0);
132
133
134 String startupObject = getStartupObject(linkType);
135 Boolean defaultflag = specificDef.getDefaultflag(defaultProviders, 1);
136 addImpliedArgs(debug, linkType, preargs, defaultflag);
137 addIncremental(specificDef.getIncremental(defaultProviders,1), preargs);
138 addFixed(specificDef.getFixed(defaultProviders,1), preargs);
139 addMap(specificDef.getMap(defaultProviders,1), preargs);
140 addBase(specificDef.getBase(defaultProviders,1), preargs);
141 addStack(specificDef.getStack(defaultProviders,1), preargs);
142 addEntry(specificDef.getEntry(defaultProviders, 1), preargs);
143
144 String[] libnames = null;
145 LibrarySet[] libsets = specificDef.getActiveLibrarySets(defaultProviders,1);
146 if (libsets.length > 0) {
147 libnames = addLibrarySets(task, libsets, preargs, midargs, endargs);
148 }
149
150 StringBuffer buf = new StringBuffer(getIdentifier());
151 for (int i = 0; i < 3; i++) {
152 Enumeration argenum = args[i].elements();
153 while (argenum.hasMoreElements()) {
154 buf.append(' ');
155 buf.append(argenum.nextElement().toString());
156 }
157 }
158 String configId = buf.toString();
159
160 String[][] options = new String[][] {
161 new String[args[0].size() + args[1].size()],
162 new String[args[2].size()] };
163 args[0].copyInto(options[0]);
164 int offset = args[0].size();
165 for (int i = 0; i < args[1].size(); i++) {
166 options[0][i+offset] = (String) args[1].elementAt(i);
167 }
168 args[2].copyInto(options[1]);
169
170
171 boolean rebuild = specificDef.getRebuild(baseDefs,0);
172 boolean map = specificDef.getMap(defaultProviders,1);
173
174 //task.log("libnames:"+libnames.length, Project.MSG_VERBOSE);
175 return new CommandLineLinkerConfiguration(this,configId,options,
176 paramArray,
177 rebuild,map,libnames, startupObject);
178 }
179
180 /**
181 * Allows drived linker to decorate linker option.
182 * Override by GccLinker to prepend a "-Wl," to
183 * pass option to through gcc to linker.
184 *
185 * @param buf buffer that may be used and abused in the decoration process,
186 * must not be null.
187 * @param arg linker argument
188 */
189 protected String decorateLinkerOption(StringBuffer buf, String arg) {
190 return arg;
191 }
192
193 protected final String getCommand() {
194 return command;
195 }
196 protected abstract String getCommandFileSwitch(String commandFile);
197
198
199 public String getIdentifier() {
200 if(identifier == null) {
201 if (identifierArg == null) {
202 identifier = getIdentifier(new String[] { command }, command);
203 } else {
204 identifier = getIdentifier(new String[] { command, identifierArg },
205 command);
206 }
207 }
208 return identifier;
209 }
210 public final CommandLineLinker getLibtoolLinker() {
211 if (libtoolLinker != null) {
212 return libtoolLinker;
213 }
214 return this;
215 }
216 protected abstract int getMaximumCommandLength();
217
218 public String getOutputFileName(String baseName) {
219 return baseName + outputSuffix;
220 }
221
222 protected String[] getOutputFileSwitch(CCTask task, String outputFile) {
223 return getOutputFileSwitch(outputFile);
224 }
225 protected abstract String[] getOutputFileSwitch(String outputFile);
226 protected String getStartupObject(LinkType linkType) {
227 return null;
228 }
229
230 /**
231 * Performs a link using a command line linker
232 *
233 */
234 public void link(CCTask task,
235 File outputFile,
236 String[] sourceFiles,
237 CommandLineLinkerConfiguration config)
238 throws BuildException
239 {
240 File parentDir = new File(outputFile.getParent());
241 String parentPath;
242 try {
243 parentPath = parentDir.getCanonicalPath();
244 } catch(IOException ex) {
245 parentPath = parentDir.getAbsolutePath();
246 }
247 String[] execArgs = prepareArguments(task, parentPath,outputFile.getName(),
248 sourceFiles, config);
249 int commandLength = 0;
250 for(int i = 0; i < execArgs.length; i++) {
251 commandLength += execArgs[i].length() + 1;
252 }
253
254 //
255 // if command length exceeds maximum
256 // (1024 for Windows) then create a temporary
257 // file containing everything but the command name
258 if(commandLength >= this.getMaximumCommandLength()) {
259 try {
260 execArgs = prepareResponseFile(outputFile,execArgs);
261 }
262 catch(IOException ex) {
263 throw new BuildException(ex);
264 }
265 }
266
267 int retval = runCommand(task,parentDir,execArgs);
268 //
269 // if the process returned a failure code then
270 // throw an BuildException
271 //
272 if(retval != 0) {
273 //
274 // construct the exception
275 //
276 throw new BuildException(this.getCommand() + " failed with return code " + retval, task.getLocation());
277 }
278
279 }
280
281
282 /**
283 * Prepares argument list for exec command. Will return null
284 * if command line would exceed allowable command line buffer.
285 *
286 * @param outputFile linker output file
287 * @param sourceFiles linker input files (.obj, .o, .res)
288 * @param args linker arguments
289 * @return arguments for runTask
290 */
291 protected String[] prepareArguments(
292 CCTask task,
293 String outputDir,
294 String outputFile,
295 String[] sourceFiles,
296 CommandLineLinkerConfiguration config) {
297
298 String[] preargs = config.getPreArguments();
299 String[] endargs = config.getEndArguments();
300 String outputSwitch[] = getOutputFileSwitch(task, outputFile);
301 int allArgsCount = preargs.length + 1 + outputSwitch.length +
302 sourceFiles.length + endargs.length;
303 if (isLibtool) {
304 allArgsCount++;
305 }
306 String[] allArgs = new String[allArgsCount];
307 int index = 0;
308 if (isLibtool) {
309 allArgs[index++] = "libtool";
310 }
311 allArgs[index++] = this.getCommand();
312 StringBuffer buf = new StringBuffer();
313 for (int i = 0; i < preargs.length; i++) {
314 allArgs[index++] = decorateLinkerOption(buf, preargs[i]);
315 }
316 for (int i = 0; i < outputSwitch.length; i++) {
317 allArgs[index++] = outputSwitch[i];
318 }
319 for (int i = 0; i < sourceFiles.length; i++) {
320 allArgs[index++] = prepareFilename(buf,outputDir,sourceFiles[i]);
321 }
322 for (int i = 0; i < endargs.length; i++) {
323 allArgs[index++] = decorateLinkerOption(buf, endargs[i]);
324 }
325 return allArgs;
326 }
327
328 /**
329 * Processes filename into argument form
330 *
331 */
332 protected String prepareFilename(StringBuffer buf,
333 String outputDir, String sourceFile) {
334 String relativePath = CUtil.getRelativePath(outputDir,
335 new File(sourceFile));
336 return quoteFilename(buf,relativePath);
337 }
338
339 /**
340 * Prepares argument list to execute the linker using a
341 * response file.
342 *
343 * @param outputFile linker output file
344 * @param args output of prepareArguments
345 * @return arguments for runTask
346 */
347 protected String[] prepareResponseFile(File outputFile,String[] args) throws IOException
348 {
349 String baseName = outputFile.getName();
350 File commandFile = new File(outputFile.getParent(),baseName + ".rsp");
351 FileWriter writer = new FileWriter(commandFile);
352 int execArgCount = 1;
353 if (isLibtool) {
354 execArgCount++;
355 }
356 String[] execArgs = new String[execArgCount+1];
357 for (int i = 0; i < execArgCount; i++) {
358 execArgs[i] = args[i];
359 }
360 execArgs[execArgCount] = getCommandFileSwitch(commandFile.toString());
361 for(int i = execArgCount; i < args.length; i++) {
362 //
363 // if embedded space and not quoted then
364 // quote argument
365 if (args[i].indexOf(" ") >= 0 && args[i].charAt(0) != '\"') {
366 writer.write('\"');
367 writer.write(args[i]);
368 writer.write("\"\n");
369 } else {
370 writer.write(args[i]);
371 writer.write('\n');
372 }
373 }
374 writer.close();
375 return execArgs;
376 }
377
378
379 protected String quoteFilename(StringBuffer buf,String filename) {
380 if(filename.indexOf(' ') >= 0) {
381 buf.setLength(0);
382 buf.append('\"');
383 buf.append(filename);
384 buf.append('\"');
385 return buf.toString();
386 }
387 return filename;
388 }
389
390 /**
391 * This method is exposed so test classes can overload
392 * and test the arguments without actually spawning the
393 * compiler
394 */
395 protected int runCommand(CCTask task, File workingDir,String[] cmdline)
396 throws BuildException {
397 return CUtil.runCommand(task,workingDir,cmdline, newEnvironment, env);
398 }
399
400 protected final void setCommand(String command) {
401 this.command = command;
402 }
403
404 }