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.CaptureStreamHandler;
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.gcc.AbstractLdLinker;
35  import com.github.maven_nar.cpptasks.types.LibrarySet;
36  
37  /**
38   * Adapter for the g++ variant of the GCC linker
39   *
40   * @author Stephen M. Webb <stephen.webb@bregmasoft.com>
41   */
42  public class GppLinker extends AbstractLdLinker {
43    protected static final String[] discardFiles = new String[0];
44    protected static final String[] objFiles = new String[] {
45        ".o", ".a", ".lib", ".dll", ".so", ".sl"
46    };
47    private static final GppLinker dllLinker = new GppLinker("gcc", objFiles, discardFiles, "lib", ".so", false,
48        new GppLinker("gcc", objFiles, discardFiles, "lib", ".so", true, null));
49    private final static String libPrefix = "libraries: =";
50    protected static final String[] libtoolObjFiles = new String[] {
51        ".fo", ".a", ".lib", ".dll", ".so", ".sl"
52    };
53    private static String[] linkerOptions = new String[] {
54        "-bundle", "-dylib", "-dynamic", "-dynamiclib", "-nostartfiles", "-nostdlib", "-prebind", "-s", "-static",
55        "-shared", "-symbolic", "-Xlinker"
56    };
57    private static final GppLinker instance = new GppLinker("gcc", objFiles, discardFiles, "", "", false, null);
58    private static final GppLinker machDllLinker = new GppLinker("gcc", objFiles, discardFiles, "lib", ".dylib", false,
59        null);
60    private static final GppLinker machPluginLinker = new GppLinker("gcc", objFiles, discardFiles, "lib", ".bundle",
61        false, null);
62  
63    public static GppLinker getInstance() {
64      return instance;
65    }
66  
67    private File[] libDirs;
68    private String runtimeLibrary;
69  
70    protected GppLinker(final String command, final String[] extensions, final String[] ignoredExtensions,
71        final String outputPrefix, final String outputSuffix, final boolean isLibtool, final GppLinker libtoolLinker) {
72      super(command, "-dumpversion", extensions, ignoredExtensions, outputPrefix, outputSuffix, isLibtool, libtoolLinker);
73    }
74  
75    @Override
76    protected void addImpliedArgs(final CCTask task, final boolean debug, final LinkType linkType,
77        final Vector<String> args) {
78      super.addImpliedArgs(task, debug, linkType, args);
79      if (getIdentifier().contains("mingw")) {
80        if (linkType.isSubsystemConsole()) {
81          args.addElement("-mconsole");
82        }
83        if (linkType.isSubsystemGUI()) {
84          args.addElement("-mwindows");
85        }
86      }
87      if (linkType.isStaticRuntime()) {
88        final String[] cmdin = new String[] {
89            "g++", "-print-file-name=libstdc++.a"
90        };
91        final String[] cmdout = CaptureStreamHandler.run(cmdin);
92        if (cmdout.length > 0) {
93          this.runtimeLibrary = cmdout[0];
94        } else {
95          this.runtimeLibrary = null;
96        }
97      } else {
98        this.runtimeLibrary = "-lstdc++";
99      }
100   }
101 
102   @Override
103   public String[] addLibrarySets(final CCTask task, final LibrarySet[] libsets, final Vector<String> preargs,
104       final Vector<String> midargs, final Vector<String> endargs) {
105     final String[] rs = super.addLibrarySets(task, libsets, preargs, midargs, endargs);
106     if (this.runtimeLibrary != null) {
107       endargs.addElement(this.runtimeLibrary);
108     }
109     return rs;
110   }
111 
112   @Override
113   protected Object clone() throws CloneNotSupportedException {
114     final GppLinker clone = (GppLinker) super.clone();
115     return clone;
116   }
117 
118   /**
119    * Allows drived linker to decorate linker option. Override by GppLinker to
120    * prepend a "-Wl," to pass option to through gcc to linker.
121    * 
122    * @param buf
123    *          buffer that may be used and abused in the decoration process,
124    *          must not be null.
125    * @param arg
126    *          linker argument
127    */
128   @Override
129   public String decorateLinkerOption(final StringBuffer buf, final String arg) {
130     String decoratedArg = arg;
131     if (arg.length() > 1 && arg.charAt(0) == '-') {
132       switch (arg.charAt(1)) {
133       //
134       // passed automatically by GCC
135       //
136         case 'g':
137         case 'f':
138         case 'F':
139           /* Darwin */
140         case 'm':
141         case 'O':
142         case 'W':
143         case 'l':
144         case 'L':
145         case 'u':
146           break;
147         default:
148           boolean known = false;
149           for (final String linkerOption : linkerOptions) {
150             if (linkerOption.equals(arg)) {
151               known = true;
152               break;
153             }
154           }
155           if (!known) {
156             buf.setLength(0);
157             buf.append("-Wl,");
158             buf.append(arg);
159             decoratedArg = buf.toString();
160           }
161           break;
162       }
163     }
164     return decoratedArg;
165   }
166 
167   /**
168    * Returns library path.
169    * 
170    */
171   @Override
172   public File[] getLibraryPath() {
173     if (this.libDirs == null) {
174       final Vector<String> dirs = new Vector<>();
175       // Ask GCC where it will look for its libraries.
176       final String[] args = new String[] {
177           "g++", "-print-search-dirs"
178       };
179       final String[] cmdout = CaptureStreamHandler.run(args);
180       for (int i = 0; i < cmdout.length; ++i) {
181         final int prefixIndex = cmdout[i].indexOf(libPrefix);
182         if (prefixIndex >= 0) {
183           // Special case DOS-type GCCs like MinGW or Cygwin
184           int s = prefixIndex + libPrefix.length();
185           int t = cmdout[i].indexOf(';', s);
186           while (t > 0) {
187             dirs.addElement(cmdout[i].substring(s, t));
188             s = t + 1;
189             t = cmdout[i].indexOf(';', s);
190           }
191           dirs.addElement(cmdout[i].substring(s));
192           ++i;
193           for (; i < cmdout.length; ++i) {
194             dirs.addElement(cmdout[i]);
195           }
196         }
197       }
198       // Eliminate all but actual directories.
199       final String[] libpath = new String[dirs.size()];
200       dirs.copyInto(libpath);
201       final int count = CUtil.checkDirectoryArray(libpath);
202       // Build return array.
203       this.libDirs = new File[count];
204       int index = 0;
205       for (final String element : libpath) {
206         if (element != null) {
207           this.libDirs[index++] = new File(element);
208         }
209       }
210     }
211     return this.libDirs;
212   }
213 
214   @Override
215   public Linker getLinker(final LinkType type) {
216     if (type.isStaticLibrary()) {
217       return GccLibrarian.getInstance();
218     }
219     if (type.isPluginModule()) {
220       if (GccProcessor.getMachine().contains("darwin")) {
221         return machPluginLinker;
222       } else {
223         return dllLinker;
224       }
225     }
226     if (type.isSharedLibrary()) {
227       if (GccProcessor.getMachine().contains("darwin")) {
228         return machDllLinker;
229       } else {
230         return dllLinker;
231       }
232     }
233     return instance;
234   }
235 
236   @Override
237   public void link(final CCTask task, final File outputFile, final String[] sourceFiles,
238       final CommandLineLinkerConfiguration config) throws BuildException {
239     try {
240       final GppLinker clone = (GppLinker) this.clone();
241       final LinkerParam param = config.getParam("target");
242       if (param != null) {
243         clone.setCommand(param.getValue() + "-" + this.getCommand());
244       }
245       clone.superlink(task, outputFile, sourceFiles, config);
246     } catch (final CloneNotSupportedException e) {
247       superlink(task, outputFile, sourceFiles, config);
248     }
249   }
250 
251   private void superlink(final CCTask task, final File outputFile, final String[] sourceFiles,
252       final CommandLineLinkerConfiguration config) throws BuildException {
253     super.link(task, outputFile, sourceFiles, config);
254   }
255 }