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.compiler.LinkType;
28  import com.github.maven_nar.cpptasks.compiler.Linker;
29  
30  /**
31   * Adapter for the GCC linker
32   *
33   * @author Adam Murdoch
34   */
35  public class GccLinker extends AbstractLdLinker {
36    private static final String[] discardFiles = new String[0];
37    private static final String[] objFiles = new String[] {
38        ".o", ".a", ".lib", ".dll", ".so", ".sl"
39    };
40    private static final String[] libtoolObjFiles = new String[] {
41        ".fo", ".a", ".lib", ".dll", ".so", ".sl"
42    };
43    private static String[] linkerOptions = new String[] {
44        "-bundle",
45        // FREEHEP
46        "-dynamic", "-arch", "-dynamiclib", "-nostartfiles", "-nostdlib", "-prebind", "-s", "-static", "-shared",
47        "-symbolic", "-Xlinker", "--export-all-symbols", "-static-libgcc", "-p", "-pg", "-pthread"
48    };
49    // FREEHEP refactored dllLinker to soLinker
50    private static final GccLinker soLinker = new GccLinker("gcc", objFiles, discardFiles, "lib", ".so", false,
51        new GccLinker("gcc", objFiles, discardFiles, "lib", ".so", true, null));
52    private static final GccLinker instance = new GccLinker("gcc", objFiles, discardFiles, "", "", false, null);
53    private static final GccLinker clangInstance = new GccLinker("clang", objFiles, discardFiles, "", "", false, null);
54    private static final GccLinker machBundleLinker = new GccLinker("gcc", objFiles, discardFiles, "lib", ".bundle",
55        false, null);
56    private static final GccLinker machDllLinker = new GccLinker("gcc", objFiles, discardFiles, "lib", ".dylib", false,
57        null);
58    private static final GccLinker machJNILinker = new GccLinker("gcc", objFiles, discardFiles, "lib", ".jnilib", false,
59        null);
60    // FREEHEP added dllLinker for windows
61    private static final GccLinker dllLinker = new GccLinker("gcc", objFiles, discardFiles, "", ".dll", false, null);
62  
63    public static GccLinker getCLangInstance() {
64      return clangInstance;
65    }
66  
67    public static GccLinker getInstance() {
68      return instance;
69    }
70  
71    private File[] libDirs;
72  
73    protected GccLinker(final String command, final String[] extensions, final String[] ignoredExtensions,
74        final String outputPrefix, final String outputSuffix, final boolean isLibtool, final GccLinker libtoolLinker) {
75      super(command, "-dumpversion", extensions, ignoredExtensions, outputPrefix, outputSuffix, isLibtool, libtoolLinker);
76    }
77  
78    @Override
79    protected void addImpliedArgs(final CCTask task, final boolean debug, final LinkType linkType,
80        final Vector<String> args) {
81      super.addImpliedArgs(task, debug, linkType, args);
82      if (getIdentifier().contains("mingw")) {
83        if (linkType.isSubsystemConsole()) {
84          args.addElement("-mconsole");
85        }
86        if (linkType.isSubsystemGUI()) {
87          args.addElement("-mwindows");
88        }
89      }
90    }
91  
92    /**
93     * Allows drived linker to decorate linker option. Override by GccLinker to
94     * prepend a "-Wl," to pass option to through gcc to linker.
95     * 
96     * @param buf
97     *          buffer that may be used and abused in the decoration process,
98     *          must not be null.
99     * @param arg
100    *          linker argument
101    */
102   @Override
103   public String decorateLinkerOption(final StringBuffer buf, final String arg) {
104     String decoratedArg = arg;
105     if (arg.length() > 1 && arg.charAt(0) == '-') {
106       switch (arg.charAt(1)) {
107       //
108       // passed automatically by GCC
109       //
110         case 'g':
111         case 'f':
112         case 'F':
113           /* Darwin */
114         case 'm':
115         case 'O':
116         case 'W':
117         case 'l':
118         case 'L':
119         case 'u':
120         case 'v':
121           break;
122         default:
123           boolean known = false;
124           for (final String linkerOption : linkerOptions) {
125             if (linkerOption.equals(arg)) {
126               known = true;
127               break;
128             }
129           }
130           if (!known) {
131             buf.setLength(0);
132             buf.append("-Wl,");
133             buf.append(arg);
134             decoratedArg = buf.toString();
135           }
136           break;
137       }
138     }
139     return decoratedArg;
140   }
141 
142   /**
143    * Returns library path.
144    * 
145    */
146   @Override
147   public File[] getLibraryPath() {
148     if (this.libDirs == null) {
149       //
150       // construct gcc lib path from machine and version
151       //
152       final StringBuffer buf = new StringBuffer("/lib/gcc-lib/");
153       buf.append(GccProcessor.getMachine());
154       buf.append('/');
155       buf.append(GccProcessor.getVersion());
156       //
157       // build default path from gcc and system /lib and /lib/w32api
158       //
159       final String[] impliedLibPath = new String[] {
160           buf.toString(), "/lib/w32api", "/lib"
161       };
162       //
163       // read gcc specs file for other library paths
164       //
165       final String[] specs = GccProcessor.getSpecs();
166       final String[][] libpaths = GccProcessor.parseSpecs(specs, "*link:", new String[] {
167         "%q"
168       });
169       String[] libpath;
170       if (libpaths[0].length > 0) {
171         libpath = new String[libpaths[0].length + 3];
172         int i = 0;
173         for (; i < libpaths[0].length; i++) {
174           libpath[i] = libpaths[0][i];
175         }
176         libpath[i++] = buf.toString();
177         libpath[i++] = "/lib/w32api";
178         libpath[i++] = "/lib";
179       } else {
180         //
181         // if a failure to find any matches then
182         // use some default values for lib path entries
183         libpath = new String[] {
184             "/usr/local/lib/mingw", "/usr/local/lib", "/usr/lib/w32api", "/usr/lib/mingw", "/usr/lib", buf.toString(),
185             "/lib/w32api", "/lib"
186         };
187       }
188       for (int i = 0; i < libpath.length; i++) {
189         if (libpath[i].contains("mingw")) {
190           libpath[i] = null;
191         }
192       }
193       //
194       // if cygwin then
195       // we have to prepend location of gcc32
196       // and .. to start of absolute filenames to
197       // have something that will exist in the
198       // windows filesystem
199       if (GccProcessor.isCygwin()) {
200         GccProcessor.convertCygwinFilenames(libpath);
201       }
202       //
203       // check that remaining entries are actual directories
204       //
205       final int count = CUtil.checkDirectoryArray(libpath);
206       //
207       // populate return array with remaining entries
208       //
209       this.libDirs = new File[count];
210       int index = 0;
211       for (final String element : libpath) {
212         if (element != null) {
213           this.libDirs[index++] = new File(element);
214         }
215       }
216     }
217     return this.libDirs;
218   }
219 
220   @Override
221   public Linker getLinker(final LinkType type) {
222     if (type.isStaticLibrary()) {
223       return GccLibrarian.getInstance();
224     }
225     // BEGINFREEHEP
226     if (type.isJNIModule()) {
227       return isDarwin() ? machJNILinker : isWindows() ? dllLinker : soLinker;
228     }
229     if (type.isPluginModule()) {
230       return isDarwin() ? machBundleLinker : isWindows() ? dllLinker : soLinker;
231     }
232     if (type.isSharedLibrary()) {
233       return isDarwin() ? machDllLinker : isWindows() ? dllLinker : soLinker;
234     }
235     // ENDFREEHEP
236     return instance;
237   }
238 }