/* * #%L * Native ARchive plugin for Maven * %% * Copyright (C) 2002 - 2014 NAR Maven Plugin developers. * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ package com.github.maven_nar.cpptasks.gcc; import java.io.File; import java.util.Vector; import com.github.maven_nar.cpptasks.CCTask; import com.github.maven_nar.cpptasks.CUtil; import com.github.maven_nar.cpptasks.compiler.CaptureStreamHandler; import com.github.maven_nar.cpptasks.compiler.LinkType; import com.github.maven_nar.cpptasks.compiler.Linker; import com.github.maven_nar.cpptasks.types.LibrarySet; /** * Adapter for the g++ variant of the GCC linker * * @author Stephen M. Webb <stephen.webb@bregmasoft.com> */ public class GppLinker extends AbstractLdLinker { public static final String GPP_COMMAND = "g++"; protected static final String[] discardFiles = new String[0]; protected static final String[] objFiles = new String[] { ".o", ".a", ".lib", ".dll", ".so", ".sl" }; private final static String libPrefix = "libraries: ="; protected static final String[] libtoolObjFiles = new String[] { ".fo", ".a", ".lib", ".dll", ".so", ".sl" }; private static String[] linkerOptions = new String[] { "-bundle", "-dylib", "-dynamic", "-dynamiclib", "-nostartfiles", "-nostdlib", "-prebind", "-s", "-static", "-shared", "-symbolic", "-Xlinker", "-static-libgcc", "-shared-libgcc", "-p", "-pg", "-pthread" }; // FREEHEP refactored dllLinker into soLinker private static final GppLinker soLinker = new GppLinker(GPP_COMMAND, objFiles, discardFiles, "lib", ".so", false, new GppLinker(GPP_COMMAND, objFiles, discardFiles, "lib", ".so", true, null)); private static final GppLinker instance = new GppLinker(GPP_COMMAND, objFiles, discardFiles, "", "", false, null); private static final GppLinker clangInstance = new GppLinker("clang", objFiles, discardFiles, "", "", false, null); private static final GppLinker machDllLinker = new GppLinker(GPP_COMMAND, objFiles, discardFiles, "lib", ".dylib", false, null); private static final GppLinker machPluginLinker = new GppLinker(GPP_COMMAND, objFiles, discardFiles, "lib", ".bundle", false, null); /*On AIX shared libaries use .a for extension */ private static final GppLinker aLinker = new GppLinker(GPP_COMMAND,objFiles, discardFiles, "lib", ".a", false, null); // FREEHEP private static final GppLinker machJNILinker = new GppLinker(GPP_COMMAND, objFiles, discardFiles, "lib", ".jnilib", false, null); // FREEHEP added dllLinker for windows private static final GppLinker dllLinker = new GppLinker(GPP_COMMAND, objFiles, discardFiles, "", ".dll", false, null); public static GppLinker getCLangInstance() { return clangInstance; } public static GppLinker getInstance() { return instance; } private File[] libDirs; private String runtimeLibrary; // FREEEHEP private String gccLibrary, gfortranLibrary, gfortranMainLibrary; protected GppLinker(final String command, final String[] extensions, final String[] ignoredExtensions, final String outputPrefix, final String outputSuffix, final boolean isLibtool, final GppLinker libtoolLinker) { super(command, "-dumpversion", extensions, ignoredExtensions, outputPrefix, outputSuffix, isLibtool, libtoolLinker); } @Override protected void addImpliedArgs(final CCTask task, final boolean debug, final LinkType linkType, final Vector<String> args) { super.addImpliedArgs(task, debug, linkType, args); if (getIdentifier().contains("mingw")) { if (linkType.isSubsystemConsole()) { args.addElement("-mconsole"); } if (linkType.isSubsystemGUI()) { args.addElement("-mwindows"); } } // BEGINFREEHEP link or not with libstdc++ // for MacOS X see: // http://developer.apple.com/documentation/DeveloperTools/Conceptual/CppRuntimeEnv/Articles/LibCPPDeployment.html this.gfortranLibrary = null; if (linkType.linkFortran()) { if (linkType.isStaticRuntime()) { final String[] cmdin = new String[] { "gfortran", "-print-file-name=libgfortran.a" }; final String[] cmdout = CaptureStreamHandler.run(cmdin); if (cmdout.length > 0 && cmdout[0].indexOf('/') >= 0) { this.gfortranLibrary = cmdout[0]; } } else { this.gfortranLibrary = "-lgfortran"; } } this.gfortranMainLibrary = null; if (linkType.linkFortran()) { if (linkType.isExecutable() && linkType.linkFortranMain() && !isDarwin()) { if (linkType.isStaticRuntime()) { final String[] cmdin = new String[] { "gfortran", "-print-file-name=libgfortranbegin.a" }; final String[] cmdout = CaptureStreamHandler.run(cmdin); if (cmdout.length > 0 && cmdout[0].indexOf('/') >= 0) { this.gfortranMainLibrary = cmdout[0]; } } else { this.gfortranMainLibrary = "-lgfortranbegin"; } } } this.runtimeLibrary = null; if (linkType.linkCPP()) { if (linkType.isStaticRuntime()) { if (isDarwin()) { if (isClang()) { task.log("Warning: clang cannot statically link to C++"); } else { this.runtimeLibrary = "-lstdc++-static"; } } else { final String[] cmdin = new String[] { "g++", "-print-file-name=libstdc++.a" }; final String[] cmdout = CaptureStreamHandler.run(cmdin); if (cmdout.length > 0 && cmdout[0].indexOf('/') >= 0) { this.runtimeLibrary = cmdout[0]; } } } else { this.runtimeLibrary = "-lstdc++"; } } this.gccLibrary = null; if (linkType.isStaticRuntime()) { if (isClang()) { task.log("Warning: clang cannot statically link libgcc"); } else { this.gccLibrary = "-static-libgcc"; } } else { if (linkType.linkCPP()) { // NOTE: added -fexceptions here for MacOS X this.gccLibrary = "-fexceptions"; } else { if (isClang()) { task.log("Warning: clang cannot dynamically link libgcc"); } else { this.gccLibrary = "-shared-libgcc"; } } } // ENDFREEHEP } @Override protected String[] addLibrarySets(final CCTask task, final LibrarySet[] libsets, final Vector<String> preargs, final Vector<String> midargs, final Vector<String> endargs) { final String[] rs = super.addLibrarySets(task, libsets, preargs, midargs, endargs); // BEGINFREEHEP if (this.gfortranLibrary != null) { endargs.addElement(this.gfortranLibrary); } if (this.gfortranMainLibrary != null) { endargs.addElement(this.gfortranMainLibrary); } if (this.gccLibrary != null) { endargs.addElement(this.gccLibrary); } // ENDFREEHEP if (this.runtimeLibrary != null) { endargs.addElement(this.runtimeLibrary); } return rs; } /** * Allows drived linker to decorate linker option. Override by GppLinker to * prepend a "-Wl," to pass option to through gcc to linker. * * @param buf * buffer that may be used and abused in the decoration process, * must not be null. * @param arg * linker argument */ @Override public String decorateLinkerOption(final StringBuffer buf, final String arg) { String decoratedArg = arg; if (arg.length() > 1 && arg.charAt(0) == '-') { switch (arg.charAt(1)) { // // passed automatically by GCC // case 'g': case 'f': case 'F': /* Darwin */ case 'm': case 'O': case 'W': case 'l': case 'L': case 'u': case 'B': break; default: boolean known = false; for (final String linkerOption : linkerOptions) { if (linkerOption.equals(arg)) { known = true; break; } } if (!known) { buf.setLength(0); buf.append("-Wl,"); buf.append(arg); decoratedArg = buf.toString(); } break; } } return decoratedArg; } /** * Returns library path. * */ @Override public File[] getLibraryPath() { if (this.libDirs == null) { final Vector<String> dirs = new Vector<>(); // Ask GCC where it will look for its libraries. final String[] args = new String[] { "g++", "-print-search-dirs" }; final String[] cmdout = CaptureStreamHandler.run(args); for (int i = 0; i < cmdout.length; ++i) { final int prefixIndex = cmdout[i].indexOf(libPrefix); if (prefixIndex >= 0) { // Special case DOS-type GCCs like MinGW or Cygwin int s = prefixIndex + libPrefix.length(); int t = cmdout[i].indexOf(';', s); while (t > 0) { dirs.addElement(cmdout[i].substring(s, t)); s = t + 1; t = cmdout[i].indexOf(';', s); } dirs.addElement(cmdout[i].substring(s)); ++i; for (; i < cmdout.length; ++i) { dirs.addElement(cmdout[i]); } } } // Eliminate all but actual directories. final String[] libpath = new String[dirs.size()]; dirs.copyInto(libpath); final int count = CUtil.checkDirectoryArray(libpath); // Build return array. this.libDirs = new File[count]; int index = 0; for (final String element : libpath) { if (element != null) { this.libDirs[index++] = new File(element); } } } return this.libDirs; } @Override public Linker getLinker(final LinkType type) { if (type.isStaticLibrary()) { return GccLibrarian.getInstance(); } // BEGINFREEHEP if (type.isJNIModule()) { return isDarwin() ? machJNILinker : isWindows() ? dllLinker : soLinker; } if (type.isPluginModule()) { return isDarwin() ? machPluginLinker : isWindows() ? dllLinker : soLinker; } if (type.isSharedLibrary()) { return isDarwin() ? machDllLinker : isWindows() ? dllLinker :isAIX() ? aLinker : soLinker; } // ENDFREEHEP return instance; } /** * Checks whether the compiler is actually clang masquerading as gcc * (e.g., the situation on OS X 10.9 Mavericks). */ private boolean isClang() { final String command = getCommand(); if (command == null) { return false; } if (command.startsWith("clang")) { return true; } if (!GPP_COMMAND.equals(command)) { return false; } final String[] cmd = { command, "--version" }; final String[] cmdout = CaptureStreamHandler.execute(cmd).getStdout(); return cmdout != null && cmdout.length > 0 && cmdout[0].contains("(clang-"); } }