View Javadoc

1   /*
2    * #%L
3    * Native ARchive plugin for Maven
4    * %%
5    * Copyright (C) 2002 - 2014 NAR Maven Plugin developers.
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   * 
11   * http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package com.github.maven_nar.cpptasks.borland;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.Enumeration;
25  import java.util.Vector;
26  
27  import com.github.maven_nar.cpptasks.CCTask;
28  import com.github.maven_nar.cpptasks.TargetMatcher;
29  import com.github.maven_nar.cpptasks.VersionInfo;
30  import com.github.maven_nar.cpptasks.compiler.CommandLineLinker;
31  import com.github.maven_nar.cpptasks.compiler.CommandLineLinkerConfiguration;
32  import com.github.maven_nar.cpptasks.compiler.LinkType;
33  import com.github.maven_nar.cpptasks.compiler.Linker;
34  import com.github.maven_nar.cpptasks.platforms.WindowsPlatform;
35  import com.github.maven_nar.cpptasks.types.LibraryTypeEnum;
36  
37  /**
38   * Adapter for the Borland(r) ilink32 linker
39   *
40   * @author Curt Arnold
41   */
42  public final class BorlandLinker extends CommandLineLinker {
43    private static final BorlandLinker dllLinker = new BorlandLinker(".dll");
44    private static final BorlandLinker instance = new BorlandLinker(".exe");
45  
46    public static BorlandLinker getInstance() {
47      return instance;
48    }
49  
50    private BorlandLinker(final String outputSuffix) {
51      super("ilink32", "-r", new String[] {
52          ".obj", ".lib", ".res"
53      }, new String[] {
54          ".map", ".pdb", ".lnk"
55      }, outputSuffix, false, null);
56    }
57  
58    protected void addBase(final long base, final Vector<String> args) {
59      if (base >= 0) {
60        final String baseAddr = Long.toHexString(base);
61        args.addElement("-b:" + baseAddr);
62      }
63    }
64  
65    protected void addEntry(final String entry, final Vector<String> args) {
66    }
67  
68    protected void addFixed(final Boolean fixed, final Vector<String> args) {
69    }
70  
71    protected void addImpliedArgs(final boolean debug, final LinkType linkType, final Vector<String> args) {
72      if (linkType.isExecutable()) {
73        if (linkType.isSubsystemConsole()) {
74          args.addElement("/ap");
75        } else {
76          if (linkType.isSubsystemGUI()) {
77            args.addElement("/Tpe");
78          }
79        }
80      }
81      if (linkType.isSharedLibrary()) {
82        args.addElement("/Tpd");
83        args.addElement("/Gi");
84      }
85      if (debug) {
86        args.addElement("-v");
87      }
88    }
89  
90    protected void addIncremental(final boolean incremental, final Vector<String> args) {
91    }
92  
93    protected void addMap(final boolean map, final Vector<String> args) {
94      if (!map) {
95        args.addElement("-x");
96      }
97    }
98  
99    protected void addStack(final int stack, final Vector<String> args) {
100     if (stack >= 0) {
101       final String stackStr = Integer.toHexString(stack);
102       args.addElement("-S:" + stackStr);
103     }
104   }
105 
106   /**
107    * Adds source or object files to the bidded fileset to
108    * support version information.
109    *
110    * @param versionInfo
111    *          version information
112    * @param linkType
113    *          link type
114    * @param isDebug
115    *          true if debug build
116    * @param outputFile
117    *          name of generated executable
118    * @param objDir
119    *          directory for generated files
120    * @param matcher
121    *          bidded fileset
122    */
123   @Override
124   public void addVersionFiles(final VersionInfo versionInfo, final LinkType linkType, final File outputFile,
125       final boolean isDebug, final File objDir, final TargetMatcher matcher) throws IOException {
126     WindowsPlatform.addVersionFiles(versionInfo, linkType, outputFile, isDebug, objDir, matcher);
127   }
128 
129   @Override
130   public String getCommandFileSwitch(final String commandFile) {
131     return "@" + commandFile;
132   }
133 
134   @Override
135   public String getIdentifier() {
136     return "Borland Linker";
137   }
138 
139   @Override
140   public File[] getLibraryPath() {
141     return BorlandProcessor.getEnvironmentPath("ilink32", 'L', new String[] {
142       "..\\lib"
143     });
144   }
145 
146   @Override
147   public String[] getLibraryPatterns(final String[] libnames, final LibraryTypeEnum libType) {
148     return BorlandProcessor.getLibraryPatterns(libnames, libType);
149   }
150 
151   @Override
152   public Linker getLinker(final LinkType type) {
153     if (type.isStaticLibrary()) {
154       return BorlandLibrarian.getInstance();
155     }
156     if (type.isSharedLibrary()) {
157       return dllLinker;
158     }
159     return instance;
160   }
161 
162   @Override
163   public int getMaximumCommandLength() {
164     return 1024;
165   }
166 
167   @Override
168   public String[] getOutputFileSwitch(final String outFile) {
169     return BorlandProcessor.getOutputFileSwitch(outFile);
170   }
171 
172   @Override
173   protected String getStartupObject(final LinkType linkType) {
174     if (linkType.isSharedLibrary()) {
175       return "c0d32.obj";
176     }
177     if (linkType.isSubsystemGUI()) {
178       return "c0w32.obj";
179     }
180     if (linkType.isSubsystemConsole()) {
181       return "c0x32.obj";
182     }
183     return null;
184   }
185 
186   @Override
187   public boolean isCaseSensitive() {
188     return BorlandProcessor.isCaseSensitive();
189   }
190 
191   /**
192    * Prepares argument list for exec command.
193    *
194    * @param outputDir
195    *          linker output directory
196    * @param outputName
197    *          linker output name
198    * @param sourceFiles
199    *          linker input files (.obj, .o, .res)
200    * @param config
201    *          linker configuration
202    * @return arguments for runTask
203    */
204   @Override
205   protected String[] prepareArguments(final CCTask task, final String outputDir, final String outputName,
206       final String[] sourceFiles, final CommandLineLinkerConfiguration config) {
207     final String[] preargs = config.getPreArguments();
208     final String[] endargs = config.getEndArguments();
209     final Vector<String> execArgs = new Vector<>(preargs.length + endargs.length + 10 + sourceFiles.length);
210     execArgs.addElement(this.getCommand());
211     for (final String prearg : preargs) {
212       execArgs.addElement(prearg);
213     }
214     for (final String endarg : endargs) {
215       execArgs.addElement(endarg);
216     }
217     //
218     // see if the input files have any known startup obj files
219     //
220     String startup = null;
221     for (final String sourceFile : sourceFiles) {
222       final String filename = new File(sourceFile).getName().toLowerCase();
223       if (startup != null && filename.substring(0, 2).equals("c0") && filename.substring(3, 5).equals("32")
224           && filename.substring(filename.length() - 4).equals(".obj")) {
225         startup = sourceFile;
226       }
227     }
228     //
229     // c0w32.obj, c0x32.obj or c0d32.obj depending on
230     // link type
231     if (startup == null) {
232       startup = config.getStartupObject();
233     }
234     execArgs.addElement(startup);
235     final Vector<String> resFiles = new Vector<>();
236     final Vector<String> libFiles = new Vector<>();
237     String defFile = null;
238     final StringBuffer buf = new StringBuffer();
239     for (final String sourceFile : sourceFiles) {
240       final String last4 = sourceFile.substring(sourceFile.length() - 4).toLowerCase();
241       if (last4.equals(".def")) {
242         defFile = quoteFilename(buf, sourceFile);
243       } else {
244         if (last4.equals(".res")) {
245           resFiles.addElement(quoteFilename(buf, sourceFile));
246         } else {
247           if (last4.equals(".lib")) {
248             libFiles.addElement(quoteFilename(buf, sourceFile));
249           } else {
250             execArgs.addElement(quoteFilename(buf, sourceFile));
251           }
252         }
253       }
254     }
255     //
256     // output file name
257     //
258     final String outputFileName = new File(outputDir, outputName).toString();
259     execArgs.addElement("," + quoteFilename(buf, outputFileName));
260     if (config.getMap()) {
261       final int lastPeriod = outputFileName.lastIndexOf('.');
262       String mapName;
263       if (lastPeriod < outputFileName.length() - 4) {
264         mapName = outputFileName + ".map";
265       } else {
266         mapName = outputFileName.substring(0, lastPeriod) + ".map";
267       }
268       execArgs.addElement("," + quoteFilename(buf, mapName) + ",");
269     } else {
270       execArgs.addElement(",,");
271     }
272     //
273     // add all the libraries
274     //
275     final Enumeration<String> libEnum = libFiles.elements();
276     boolean hasImport32 = false;
277     final boolean hasCw32 = false;
278     while (libEnum.hasMoreElements()) {
279       final String libName = libEnum.nextElement();
280       if (libName.equalsIgnoreCase("import32.lib")) {
281         hasImport32 = true;
282       }
283       if (libName.equalsIgnoreCase("cw32.lib")) {
284         hasImport32 = true;
285       }
286       execArgs.addElement(quoteFilename(buf, libName));
287     }
288     if (!hasCw32) {
289       execArgs.addElement(quoteFilename(buf, "cw32.lib"));
290     }
291     if (!hasImport32) {
292       execArgs.addElement(quoteFilename(buf, "import32.lib"));
293     }
294     if (defFile == null) {
295       execArgs.addElement(",,");
296     } else {
297       execArgs.addElement("," + quoteFilename(buf, defFile) + ",");
298     }
299     final Enumeration<String> resEnum = resFiles.elements();
300     while (resEnum.hasMoreElements()) {
301       final String resName = resEnum.nextElement();
302       execArgs.addElement(quoteFilename(buf, resName));
303     }
304     final String[] execArguments = new String[execArgs.size()];
305     execArgs.copyInto(execArguments);
306     return execArguments;
307   }
308 
309   /**
310    * Prepares argument list to execute the linker using a response file.
311    *
312    * @param outputFile
313    *          linker output file
314    * @param args
315    *          output of prepareArguments
316    * @return arguments for runTask
317    */
318   @Override
319   protected String[] prepareResponseFile(final File outputFile, final String[] args) throws IOException {
320     final String cmdargs[] = BorlandProcessor.prepareResponseFile(outputFile, args, " + \n");
321     cmdargs[cmdargs.length - 1] = getCommandFileSwitch(cmdargs[cmdargs.length - 1]);
322     return cmdargs;
323   }
324 
325 }