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.gcc;
21  
22  import java.io.File;
23  import java.util.Vector;
24  
25  import com.github.maven_nar.cpptasks.CCTask;
26  import com.github.maven_nar.cpptasks.CUtil;
27  import com.github.maven_nar.cpptasks.VersionInfo;
28  import com.github.maven_nar.cpptasks.compiler.CommandLineLinker;
29  import com.github.maven_nar.cpptasks.compiler.CommandLineLinkerConfiguration;
30  import com.github.maven_nar.cpptasks.compiler.LinkType;
31  import com.github.maven_nar.cpptasks.types.LibrarySet;
32  import com.github.maven_nar.cpptasks.types.LibraryTypeEnum;
33  
34  /**
35   * Abstract adapter for ld-like linkers
36   *
37   * @author Curt Arnold
38   */
39  public abstract class AbstractLdLinker extends CommandLineLinker {
40    private final String outputPrefix;
41  
42    protected AbstractLdLinker(final String command, final String identifierArg, final String[] extensions,
43        final String[] ignoredExtensions, final String outputPrefix, final String outputSuffix, final boolean isLibtool,
44        final AbstractLdLinker libtoolLinker) {
45      super(command, identifierArg, extensions, ignoredExtensions, outputSuffix, isLibtool, libtoolLinker);
46      this.outputPrefix = outputPrefix;
47    }
48  
49    @Override
50    protected void addBase(final CCTask task, final long base, final Vector<String> args) {
51      if (base >= 0) {
52        args.addElement("--image-base");
53        args.addElement(Long.toHexString(base));
54      }
55    }
56  
57    @Override
58    protected void addEntry(final CCTask task, final String entry, final Vector<String> args) {
59      if (entry != null) {
60        args.addElement("-e");
61        args.addElement(entry);
62      }
63    }
64  
65    @Override
66    protected void addImpliedArgs(final CCTask task, final boolean debug, final LinkType linkType,
67        final Vector<String> args) {
68      if (debug) {
69        args.addElement("-g");
70      }
71      if (isDarwin()) {
72        if (linkType.isPluginModule()) {
73          args.addElement("-bundle");
74          // BEGINFREEHEP
75        } else if (linkType.isJNIModule()) {
76          args.addElement("-dynamic");
77          args.addElement("-bundle");
78          // ENDFREEHEP
79        } else {
80          if (linkType.isSharedLibrary()) {
81            // FREEHEP no longer needed for 10.4+
82            // args.addElement("-prebind");
83            args.addElement("-dynamiclib");
84          }
85        }
86      } else {
87        if (linkType.isStaticRuntime()) {
88          args.addElement("-static");
89        }
90        if (linkType.isPluginModule()) {
91          args.addElement("-shared");
92        } else {
93          if (linkType.isSharedLibrary()) {
94            args.addElement("-shared");
95          }
96        }
97      }
98    }
99  
100   @Override
101   protected void addIncremental(final CCTask task, final boolean incremental, final Vector<String> args) {
102     if (incremental) {
103       args.addElement("-i");
104     }
105   }
106 
107   @Override
108   protected void addLibraryPath(final Vector<String> preargs, final String path) {
109     preargs.addElement("-L" + path);
110   }
111 
112   protected int addLibraryPatterns(final String[] libnames, final StringBuffer buf, final String prefix,
113       final String extension, final String[] patterns, final int offset) {
114     for (int i = 0; i < libnames.length; i++) {
115       buf.setLength(0);
116       buf.append(prefix);
117       buf.append(libnames[i]);
118       buf.append(extension);
119       patterns[offset + i] = buf.toString();
120     }
121     return offset + libnames.length;
122   }
123 
124   @Override
125   protected String[] addLibrarySets(final CCTask task, final LibrarySet[] libsets, final Vector<String> preargs,
126       final Vector<String> midargs, final Vector<String> endargs) {
127     final Vector<String> libnames = new Vector<>();
128     super.addLibrarySets(task, libsets, preargs, midargs, endargs);
129     LibraryTypeEnum previousLibraryType = null;
130     for (final LibrarySet libset : libsets) {
131       final LibrarySet set = libset;
132       final File libdir = set.getDir(null);
133       final String[] libs = set.getLibs();
134       if (libdir != null) {
135         String relPath = libdir.getAbsolutePath();
136         // File outputFile = task.getOutfile();
137         final File currentDir = new File(".");
138         if (currentDir.getParentFile() != null) {
139           relPath = CUtil.getRelativePath(currentDir.getParentFile().getAbsolutePath(), libdir);
140         }
141         if (set.getType() != null && "framework".equals(set.getType().getValue()) && isDarwin()) {
142           endargs.addElement("-F" + relPath);
143         } else {
144           endargs.addElement("-L" + relPath);
145         }
146       }
147       //
148       // if there has been a change of library type
149       //
150       if (set.getType() != previousLibraryType) {
151         if (set.getType() != null && "static".equals(set.getType().getValue())) {
152           // BEGINFREEHEP not on MacOS X
153           if (!isDarwin()) {
154             endargs.addElement(getStaticLibFlag());
155             previousLibraryType = set.getType();
156           }
157           // ENDFREEHEP
158         } else {
159           // FREEHEP not on MacOS X, recheck this!
160           if (set.getType() == null || !"framework".equals(set.getType().getValue()) && !isDarwin()) {
161             endargs.addElement(getDynamicLibFlag());
162             previousLibraryType = set.getType();
163           }
164         }
165       }
166       final StringBuffer buf = new StringBuffer("-l");
167       if (set.getType() != null && "framework".equals(set.getType().getValue()) && isDarwin()) {
168         buf.setLength(0);
169         // FREEHEP, added as endarg w/o trailing space to avoid quoting!
170         endargs.addElement("-framework");
171       }
172       final int initialLength = buf.length();
173       for (final String lib : libs) {
174         //
175         // reset the buffer to just "-l"
176         //
177         buf.setLength(initialLength);
178         //
179         // add the library name
180         buf.append(lib);
181         libnames.addElement(lib);
182         //
183         // add the argument to the list
184         endargs.addElement(buf.toString());
185       }
186     }
187 
188     // BEGINFREEHEP if last was -Bstatic reset it to -Bdynamic so that libc and
189     // libm can be found as shareables
190     if (previousLibraryType != null && previousLibraryType.getValue().equals("static") && !isDarwin()) {
191       endargs.addElement(getDynamicLibFlag());
192     }
193     // ENDFREEHEP
194 
195     final String rc[] = new String[libnames.size()];
196     for (int i = 0; i < libnames.size(); i++) {
197       rc[i] = libnames.elementAt(i);
198     }
199     return rc;
200   }
201 
202   @Override
203   protected void addMap(final CCTask task, final boolean map, final Vector<String> args) {
204     if (map) {
205       args.addElement("-M");
206     }
207   }
208 
209   @Override
210   protected void addStack(final CCTask task, final int stack, final Vector<String> args) {
211     if (stack > 0) {
212       args.addElement("--stack");
213       args.addElement(Integer.toString(stack));
214     }
215   }
216 
217   @Override
218   public String getCommandFileSwitch(final String commandFile) {
219     throw new IllegalStateException("ld does not support command files");
220   }
221 
222   protected String getDynamicLibFlag() {
223     return "-Bdynamic";
224   }
225 
226   /**
227    * Returns library path.
228    *
229    */
230   protected File[] getEnvironmentIncludePath() {
231     return CUtil.getPathFromEnvironment("LIB", ":");
232   }
233 
234   @Override
235   public String getLibraryKey(final File libfile) {
236     final String libname = libfile.getName();
237     final int lastDot = libname.lastIndexOf('.');
238     if (lastDot >= 0) {
239       return libname.substring(0, lastDot);
240     }
241     return libname;
242   }
243 
244   /**
245    * Returns library path.
246    *
247    */
248   @Override
249   public File[] getLibraryPath() {
250     return new File[0];
251   }
252 
253   @Override
254   public String[] getLibraryPatterns(final String[] libnames, final LibraryTypeEnum libType) {
255     final StringBuffer buf = new StringBuffer();
256     int patternCount = libnames.length;
257     if (libType == null) {
258       patternCount *= 2;
259     }
260     final String[] patterns = new String[patternCount];
261     int offset = 0;
262     if (libType == null || "static".equals(libType.getValue())) {
263       offset = addLibraryPatterns(libnames, buf, "lib", ".a", patterns, 0);
264     }
265     if (libType != null && "framework".equals(libType.getValue()) && isDarwin()) {
266       for (final String libname : libnames) {
267         buf.setLength(0);
268         buf.append(libname);
269         buf.append(".framework/");
270         buf.append(libname);
271         patterns[offset++] = buf.toString();
272       }
273     } else {
274       if (libType == null || !"static".equals(libType.getValue())) {
275         if (isHPUX()) {
276           offset = addLibraryPatterns(libnames, buf, "lib", ".sl", patterns, offset);
277         } else {
278           offset = addLibraryPatterns(libnames, buf, "lib", ".so", patterns, offset);
279         }
280       }
281     }
282     return patterns;
283   }
284 
285   @Override
286   public int getMaximumCommandLength() {
287     // FREEHEP
288     return isWindows() ? 20000 : Integer.MAX_VALUE;
289   }
290 
291   @Override
292   public String[] getOutputFileNames(final String baseName, final VersionInfo versionInfo) {
293     final String[] baseNames = super.getOutputFileNames(baseName, versionInfo);
294     if (this.outputPrefix.length() > 0) {
295       for (int i = 0; i < baseNames.length; i++) {
296         baseNames[i] = this.outputPrefix + baseNames[i];
297       }
298     }
299     return baseNames;
300   }
301 
302   @Override
303   public String[] getOutputFileSwitch(final String outputFile) {
304     return GccProcessor.getOutputFileSwitch("-o", outputFile);
305   }
306 
307   protected String getStaticLibFlag() {
308     return "-Bstatic";
309   }
310 
311   @Override
312   public boolean isCaseSensitive() {
313     return true;
314   }
315 
316   protected boolean isHPUX() {
317     final String osname = System.getProperty("os.name").toLowerCase();
318     if (osname.contains("hp") && osname.contains("ux")) {
319       return true;
320     }
321     return false;
322   }
323 
324   /**
325    * Prepares argument list for exec command. Will return null if command
326    * line would exceed allowable command line buffer.
327    *
328    * @param outputFile
329    *          linker output file
330    * @param sourceFiles
331    *          linker input files (.obj, .o, .res)
332    * @param config
333    *          linker configuration
334    * @return arguments for runTask
335    */
336   @Override
337   public String[] prepareArguments(final CCTask task, final String outputDir, final String outputFile,
338       final String[] sourceFiles, final CommandLineLinkerConfiguration config) {
339     //
340     // need to suppress sources that correspond to
341     // library set entries since they are already
342     // in the argument list
343     final String[] libnames = config.getLibraryNames();
344     if (libnames == null || libnames.length == 0) {
345       return super.prepareArguments(task, outputDir, outputFile, sourceFiles, config);
346     }
347     //
348     //
349     // null out any sources that correspond to library names
350     //
351     final String[] localSources = sourceFiles.clone();
352     int extra = 0;
353     for (final String libname : libnames) {
354       for (int j = 0; j < localSources.length; j++) {
355         if (localSources[j] != null && localSources[j].indexOf(libname) > 0 && localSources[j].indexOf("lib") > 0) {
356           final String filename = new File(localSources[j]).getName();
357           if (filename.startsWith("lib") && filename.substring(3).startsWith(libname)) {
358             final String extension = filename.substring(libname.length() + 3);
359             if (extension.equals(".a") || extension.equals(".so") || extension.equals(".sl")) {
360               localSources[j] = null;
361               extra++;
362             }
363           }
364         }
365       }
366     }
367     if (extra == 0) {
368       return super.prepareArguments(task, outputDir, outputFile, sourceFiles, config);
369     }
370     final String[] finalSources = new String[localSources.length - extra];
371     int index = 0;
372     for (final String localSource : localSources) {
373       if (localSource != null) {
374         finalSources[index++] = localSource;
375       }
376     }
377     return super.prepareArguments(task, outputDir, outputFile, finalSources, config);
378   }
379 }