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;
21  
22  import java.io.File;
23  import java.util.ArrayList;
24  import java.util.Enumeration;
25  import java.util.LinkedHashSet;
26  import java.util.List;
27  import java.util.Set;
28  import java.util.Vector;
29  
30  import org.apache.tools.ant.BuildException;
31  import org.apache.tools.ant.Project;
32  import org.apache.tools.ant.types.FlexInteger;
33  
34  import com.github.maven_nar.cpptasks.compiler.CommandLineLinker;
35  import com.github.maven_nar.cpptasks.compiler.LinkType;
36  import com.github.maven_nar.cpptasks.compiler.Linker;
37  import com.github.maven_nar.cpptasks.compiler.Processor;
38  import com.github.maven_nar.cpptasks.gcc.GccLinker;
39  import com.github.maven_nar.cpptasks.types.FlexLong;
40  import com.github.maven_nar.cpptasks.types.LibrarySet;
41  import com.github.maven_nar.cpptasks.types.LinkerArgument;
42  import com.github.maven_nar.cpptasks.types.SystemLibrarySet;
43  
44  /**
45   * A linker definition. linker elements may be placed either as children of a
46   * cc element or the project element. A linker element with an id attribute may
47   * be referenced by linker elements with refid or extends attributes.
48   *
49   * @author Adam Murdoch
50   * @author Curt Arnold
51   */
52  public class LinkerDef extends ProcessorDef {
53    private long base;
54    private String entry;
55    private Boolean fixed;
56    private Boolean incremental;
57    private final Vector librarySets = new Vector();
58    private Boolean map;
59    private int stack;
60    private final Vector sysLibrarySets = new Vector();
61    private String toolPath;
62    private String linkerPrefix;
63    private Boolean skipDepLink;
64  
65    private final Set<File> libraryDirectories = new LinkedHashSet<>();
66  
67    /**
68     * Default constructor
69     * 
70     * @see java.lang.Object#Object()
71     */
72    public LinkerDef() {
73      this.base = -1;
74      this.stack = -1;
75    }
76  
77    private void addActiveLibrarySet(final Project project, final Vector libsets, final Vector srcSets) {
78      final Enumeration srcenum = srcSets.elements();
79      while (srcenum.hasMoreElements()) {
80        final LibrarySet set = (LibrarySet) srcenum.nextElement();
81        if (set.isActive(project)) {
82          libsets.addElement(set);
83        }
84      }
85    }
86  
87    private void addActiveSystemLibrarySets(final Project project, final Vector libsets) {
88      addActiveLibrarySet(project, libsets, this.sysLibrarySets);
89    }
90  
91    private void addActiveUserLibrarySets(final Project project, final Vector libsets) {
92      addActiveLibrarySet(project, libsets, this.librarySets);
93    }
94  
95    /**
96     * Adds a linker command-line arg.
97     */
98    public void addConfiguredLinkerArg(final LinkerArgument arg) {
99      addConfiguredProcessorArg(arg);
100   }
101 
102   /**
103    * Adds a compiler command-line arg.
104    */
105   public void addConfiguredLinkerParam(final LinkerParam param) {
106     if (isReference()) {
107       throw noChildrenAllowed();
108     }
109     addConfiguredProcessorParam(param);
110   }
111 
112   public boolean addLibraryDirectory(final File directory) {
113     if (directory == null || !directory.exists()) {
114       return false;
115     } else {
116       return this.libraryDirectories.add(directory);
117     }
118   }
119 
120   public boolean addLibraryDirectory(final File parent, final String path) {
121     if (parent == null) {
122       return false;
123     } else {
124       final File directory = new File(parent, path);
125       return addLibraryDirectory(directory);
126     }
127   }
128 
129   public void addLibraryDirectory(final String path) {
130     final File directory = new File(path);
131     addLibraryDirectory(directory);
132   }
133 
134   /**
135    * Adds a system library set.
136    */
137   public void addLibset(final LibrarySet libset) {
138     if (isReference()) {
139       throw super.noChildrenAllowed();
140     }
141     if (libset == null) {
142       throw new NullPointerException("libset");
143     }
144     this.librarySets.addElement(libset);
145   }
146 
147   /**
148    * Adds a system library set.
149    */
150   public void addSyslibset(final SystemLibrarySet libset) {
151     if (isReference()) {
152       throw super.noChildrenAllowed();
153     }
154     if (libset == null) {
155       throw new NullPointerException("libset");
156     }
157     this.sysLibrarySets.addElement(libset);
158   }
159 
160   public void execute() throws org.apache.tools.ant.BuildException {
161     throw new org.apache.tools.ant.BuildException("Not an actual task, but looks like one for documentation purposes");
162   }
163 
164   /**
165    * Returns an array of active library sets for this linker definition.
166    */
167   public LibrarySet[] getActiveLibrarySets(final LinkerDef[] defaultProviders, final int index) {
168     if (isReference()) {
169       return ((LinkerDef) getCheckedRef(LinkerDef.class, "LinkerDef"))
170           .getActiveUserLibrarySets(defaultProviders, index);
171     }
172     final Project p = getProject();
173     final Vector libsets = new Vector();
174     for (int i = index; i < defaultProviders.length; i++) {
175       defaultProviders[i].addActiveUserLibrarySets(p, libsets);
176     }
177     addActiveUserLibrarySets(p, libsets);
178     for (int i = index; i < defaultProviders.length; i++) {
179       defaultProviders[i].addActiveSystemLibrarySets(p, libsets);
180     }
181     addActiveSystemLibrarySets(p, libsets);
182     final LibrarySet[] sets = new LibrarySet[libsets.size()];
183     libsets.copyInto(sets);
184     return sets;
185   }
186 
187   /**
188    * Returns an array of active library sets for this linker definition.
189    */
190   public LibrarySet[] getActiveSystemLibrarySets(final LinkerDef[] defaultProviders, final int index) {
191     if (isReference()) {
192       return ((LinkerDef) getCheckedRef(LinkerDef.class, "LinkerDef"))
193           .getActiveUserLibrarySets(defaultProviders, index);
194     }
195     final Project p = getProject();
196     final Vector libsets = new Vector();
197     for (int i = index; i < defaultProviders.length; i++) {
198       defaultProviders[i].addActiveSystemLibrarySets(p, libsets);
199     }
200     addActiveSystemLibrarySets(p, libsets);
201     final LibrarySet[] sets = new LibrarySet[libsets.size()];
202     libsets.copyInto(sets);
203     return sets;
204   }
205 
206   /**
207    * Returns an array of active library sets for this linker definition.
208    */
209   public LibrarySet[] getActiveUserLibrarySets(final LinkerDef[] defaultProviders, final int index) {
210     if (isReference()) {
211       return ((LinkerDef) getCheckedRef(LinkerDef.class, "LinkerDef"))
212           .getActiveUserLibrarySets(defaultProviders, index);
213     }
214     final Project p = getProject();
215     final Vector libsets = new Vector();
216     for (int i = index; i < defaultProviders.length; i++) {
217       defaultProviders[i].addActiveUserLibrarySets(p, libsets);
218     }
219     addActiveUserLibrarySets(p, libsets);
220     final LibrarySet[] sets = new LibrarySet[libsets.size()];
221     libsets.copyInto(sets);
222     return sets;
223   }
224 
225   public long getBase(final LinkerDef[] defaultProviders, final int index) {
226     if (isReference()) {
227       return ((LinkerDef) getCheckedRef(LinkerDef.class, "LinkerDef")).getBase(defaultProviders, index);
228     }
229     if (this.base <= 0) {
230       if (defaultProviders != null && index < defaultProviders.length) {
231         return defaultProviders[index].getBase(defaultProviders, index + 1);
232       }
233     }
234     return this.base;
235   }
236 
237   public String getEntry(final LinkerDef[] defaultProviders, final int index) {
238     if (isReference()) {
239       return ((LinkerDef) getCheckedRef(LinkerDef.class, "LinkerDef")).getEntry(defaultProviders, index);
240     }
241     if (this.entry != null) {
242       return this.entry;
243     }
244     if (defaultProviders != null && index < defaultProviders.length) {
245       return defaultProviders[index].getEntry(defaultProviders, index + 1);
246     }
247     return null;
248   }
249 
250   public Boolean getFixed(final LinkerDef[] defaultProviders, final int index) {
251     if (isReference()) {
252       return ((LinkerDef) getCheckedRef(LinkerDef.class, "LinkerDef")).getFixed(defaultProviders, index);
253     }
254     if (this.fixed == null) {
255       if (defaultProviders != null && index < defaultProviders.length) {
256         return defaultProviders[index].getFixed(defaultProviders, index + 1);
257       }
258     }
259     return this.fixed;
260   }
261 
262   public boolean getIncremental(final LinkerDef[] defaultProviders, final int index) {
263     if (isReference()) {
264       return ((LinkerDef) getCheckedRef(LinkerDef.class, "LinkerDef")).getIncremental(defaultProviders, index);
265     }
266     if (this.incremental != null) {
267       return this.incremental.booleanValue();
268     }
269     if (defaultProviders != null && index < defaultProviders.length) {
270       return defaultProviders[index].getIncremental(defaultProviders, index + 1);
271     }
272     return false;
273   }
274 
275   public List<File> getLibraryDirectories() {
276     return new ArrayList<>(this.libraryDirectories);
277   }
278 
279   public boolean getMap(final LinkerDef[] defaultProviders, final int index) {
280     if (isReference()) {
281       return ((LinkerDef) getCheckedRef(LinkerDef.class, "LinkerDef")).getMap(defaultProviders, index);
282     }
283     if (this.map != null) {
284       return this.map.booleanValue();
285     }
286     if (defaultProviders != null && index < defaultProviders.length) {
287       return defaultProviders[index].getMap(defaultProviders, index + 1);
288     }
289     return false;
290   }
291 
292   @Override
293   public Processor getProcessor() {
294     Linker linker = (Linker) super.getProcessor();
295     if (linker == null) {
296       linker = GccLinker.getInstance();
297     }
298     if (getLibtool() && linker instanceof CommandLineLinker) {
299       final CommandLineLinker cmdLineLinker = (CommandLineLinker) linker;
300       linker = cmdLineLinker.getLibtoolLinker();
301     }
302     return linker;
303   }
304 
305   @Override
306   public Processor getProcessor(final LinkType linkType) {
307     final Processor proc = getProcessor();
308     return proc.getLinker(linkType);
309   }
310 
311   public int getStack(final LinkerDef[] defaultProviders, final int index) {
312     if (isReference()) {
313       return ((LinkerDef) getCheckedRef(LinkerDef.class, "LinkerDef")).getStack(defaultProviders, index);
314     }
315     if (this.stack < 0) {
316       if (defaultProviders != null && index < defaultProviders.length) {
317         return defaultProviders[index].getStack(defaultProviders, index + 1);
318       }
319     }
320     return this.stack;
321   }
322 
323   public String getToolPath() {
324     return this.toolPath;
325   }
326 
327   public String getLinkerPrefix() {
328     return this.linkerPrefix;
329   }
330   
331  public boolean isSkipDepLink() {
332     return this.skipDepLink.booleanValue();
333   }
334   
335   /**
336    * Sets the base address. May be specified in either decimal or hex.
337    * 
338    * @param base
339    *          base address
340    * 
341    */
342   public void setBase(final FlexLong base) {
343     if (isReference()) {
344       throw tooManyAttributes();
345     }
346     this.base = base.longValue();
347   }
348 
349   /**
350    * Sets the starting address.
351    * 
352    * @param entry
353    *          function name
354    */
355   public void setEntry(final String entry) {
356     if (isReference()) {
357       throw tooManyAttributes();
358     }
359     this.entry = entry;
360   }
361 
362   /**
363    * If true, marks the file to be loaded only at its preferred address.
364    */
365   public void setFixed(final boolean fixed) {
366     if (isReference()) {
367       throw tooManyAttributes();
368     }
369     this.fixed = booleanValueOf(fixed);
370   }
371 
372   /**
373    * If true, allows incremental linking.
374    * 
375    */
376   public void setIncremental(final boolean incremental) {
377     if (isReference()) {
378       throw tooManyAttributes();
379     }
380     this.incremental = booleanValueOf(incremental);
381   }
382 
383   /**
384    * If set to true, a map file will be produced.
385    */
386   public void setMap(final boolean map) {
387     if (isReference()) {
388       throw tooManyAttributes();
389     }
390     this.map = booleanValueOf(map);
391   }
392 
393   /**
394    * Sets linker type.
395    * 
396    * 
397    * <table width="100%" border="1">
398    * <thead>Supported linkers </thead>
399    * <tr>
400    * <td>gcc</td>
401    * <td>Gcc Linker</td>
402    * </tr>
403    * <tr>
404    * <td>g++</td>
405    * <td>G++ Linker</td>
406    * </tr>
407    * <tr>
408    * <td>ld</td>
409    * <td>Ld Linker</td>
410    * </tr>
411    * <tr>
412    * <td>ar</td>
413    * <td>Gcc Librarian</td>
414    * </tr>
415    * <tr>
416    * <td>msvc</td>
417    * <td>Microsoft Linker</td>
418    * </tr>
419    * <tr>
420    * <td>bcc</td>
421    * <td>Borland Linker</td>
422    * </tr>
423    * <tr>
424    * <td>df</td>
425    * <td>Compaq Visual Fortran Linker</td>
426    * </tr>
427    * <tr>
428    * <td>icl</td>
429    * <td>Intel Linker for Windows (IA-32)</td>
430    * </tr>
431    * <tr>
432    * <td>ecl</td>
433    * <td>Intel Linker for Windows (IA-64)</td>
434    * </tr>
435    * <tr>
436    * <td>icc</td>
437    * <td>Intel Linker for Linux (IA-32)</td>
438    * </tr>
439    * <tr>
440    * <td>ecc</td>
441    * <td>Intel Linker for Linux (IA-64)</td>
442    * </tr>
443    * <tr>
444    * <td>CC</td>
445    * <td>Sun ONE Linker</td>
446    * </tr>
447    * <tr>
448    * <td>aCC</td>
449    * <td>HP aC++ Linker</td>
450    * </tr>
451    * <tr>
452    * <td>os390</td>
453    * <td>OS390 Linker</td>
454    * </tr>
455    * <tr>
456    * <td>os390batch</td>
457    * <td>OS390 Linker</td>
458    * </tr>
459    * <tr>
460    * <td>os400</td>
461    * <td>IccLinker</td>
462    * </tr>
463    * <tr>
464    * <td>sunc89</td>
465    * <td>C89 Linker</td>
466    * </tr>
467    * <tr>
468    * <td>xlC</td>
469    * <td>VisualAge Linker</td>
470    * </tr>
471    * <tr>
472    * <td>wcl</td>
473    * <td>OpenWatcom C/C++ linker</td>
474    * </tr>
475    * <tr>
476    * <td>wfl</td>
477    * <td>OpenWatcom FORTRAN linker</td>
478    * </tr>
479    * </table>
480    * 
481    */
482   public void setName(final LinkerEnum name) throws BuildException {
483     if (isReference()) {
484       throw tooManyAttributes();
485     }
486     final Linker linker = name.getLinker();
487     super.setProcessor(linker);
488   }
489 
490   @Override
491   protected void setProcessor(final Processor proc) throws BuildException {
492     Linker linker = null;
493     if (proc instanceof Linker) {
494       linker = (Linker) proc;
495     } else {
496       final LinkType linkType = new LinkType();
497       linker = proc.getLinker(linkType);
498     }
499     super.setProcessor(linker);
500   }
501 
502   /**
503    * Sets stack size in bytes.
504    */
505   public void setStack(final FlexInteger stack) {
506     if (isReference()) {
507       throw tooManyAttributes();
508     }
509     this.stack = stack.intValue();
510   }
511 
512   public void setToolPath(final String path) {
513     this.toolPath = path;
514   }
515 
516   public void setLinkerPrefix(final String prefix) {
517     this.linkerPrefix = prefix;
518   }
519   
520   public void setSkipDepLink(final boolean skipDepLink) {
521     this.skipDepLink = booleanValueOf(skipDepLink);
522   }
523 
524   public void visitSystemLibraries(final Linker linker, final FileVisitor libraryVisitor) {
525     final Project p = getProject();
526     if (p == null) {
527       throw new java.lang.IllegalStateException("project must be set");
528     }
529     if (isReference()) {
530       final LinkerDef master = (LinkerDef) getCheckedRef(LinkerDef.class, "Linker");
531       master.visitSystemLibraries(linker, libraryVisitor);
532     } else {
533       //
534       // if this linker extends another,
535       // visit its libraries first
536       //
537       final LinkerDef extendsDef = (LinkerDef) getExtends();
538       if (extendsDef != null) {
539         extendsDef.visitSystemLibraries(linker, libraryVisitor);
540       }
541       if (this.sysLibrarySets.size() > 0) {
542         final File[] libpath = linker.getLibraryPath();
543         for (int i = 0; i < this.sysLibrarySets.size(); i++) {
544           final LibrarySet set = (LibrarySet) this.sysLibrarySets.elementAt(i);
545           if (set.isActive(p)) {
546             set.visitLibraries(p, linker, libpath, libraryVisitor);
547           }
548         }
549       }
550     }
551   }
552 
553   public void visitUserLibraries(final Linker linker, final FileVisitor libraryVisitor) {
554     final Project p = getProject();
555     if (p == null) {
556       throw new java.lang.IllegalStateException("project must be set");
557     }
558     if (isReference()) {
559       final LinkerDef master = (LinkerDef) getCheckedRef(LinkerDef.class, "Linker");
560       master.visitUserLibraries(linker, libraryVisitor);
561     } else {
562       //
563       // if this linker extends another,
564       // visit its libraries first
565       //
566       final LinkerDef extendsDef = (LinkerDef) getExtends();
567       if (extendsDef != null) {
568         extendsDef.visitUserLibraries(linker, libraryVisitor);
569       }
570       //
571       // visit the user libraries
572       //
573       if (this.librarySets.size() > 0) {
574         final File[] libpath = linker.getLibraryPath();
575         for (int i = 0; i < this.librarySets.size(); i++) {
576           final LibrarySet set = (LibrarySet) this.librarySets.elementAt(i);
577           if (set.isActive(p)) {
578             set.visitLibraries(p, linker, libpath, libraryVisitor);
579           }
580         }
581       }
582     }
583   }
584 }