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