/*
* #%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.LinkType;
import com.github.maven_nar.cpptasks.compiler.Linker;
/**
* Adapter for the GCC linker
*
* @author Adam Murdoch
*/
public class GccLinker extends AbstractLdLinker {
private static final String[] discardFiles = new String[0];
private static final String[] objFiles = new String[] {
".o", ".a", ".lib", ".dll", ".so", ".sl"
};
private static final String[] libtoolObjFiles = new String[] {
".fo", ".a", ".lib", ".dll", ".so", ".sl"
};
private static String[] linkerOptions = new String[] {
"-bundle",
// FREEHEP
"-dynamic", "-arch", "-dynamiclib", "-nostartfiles", "-nostdlib", "-prebind", "-s", "-static", "-shared",
"-symbolic", "-Xlinker", "--export-all-symbols", "-static-libgcc", "-p", "-pg", "-pthread"
};
// FREEHEP refactored dllLinker to soLinker
private static final GccLinker soLinker = new GccLinker("gcc", objFiles, discardFiles, "lib", ".so", false,
new GccLinker("gcc", objFiles, discardFiles, "lib", ".so", true, null));
private static final GccLinker instance = new GccLinker("gcc", objFiles, discardFiles, "", "", false, null);
private static final GccLinker clangInstance = new GccLinker("clang", objFiles, discardFiles, "", "", false, null);
private static final GccLinker machBundleLinker = new GccLinker("gcc", objFiles, discardFiles, "lib", ".bundle",
false, null);
private static final GccLinker machDllLinker = new GccLinker("gcc", objFiles, discardFiles, "lib", ".dylib", false,
null);
private static final GccLinker machJNILinker = new GccLinker("gcc", objFiles, discardFiles, "lib", ".jnilib", false,
null);
// FREEHEP added dllLinker for windows
private static final GccLinker dllLinker = new GccLinker("gcc", objFiles, discardFiles, "", ".dll", false, null);
//Support running on AIX
private static final GccLinker aLinker = new GccLinker("gcc", objFiles, discardFiles, "lib", ".a", false, null);
public static GccLinker getCLangInstance() {
return clangInstance;
}
public static GccLinker getInstance() {
return instance;
}
private File[] libDirs;
protected GccLinker(final String command, final String[] extensions, final String[] ignoredExtensions,
final String outputPrefix, final String outputSuffix, final boolean isLibtool, final GccLinker 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");
}
}
}
/**
* Allows drived linker to decorate linker option. Override by GccLinker 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 'v':
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) {
//
// construct gcc lib path from machine and version
//
final StringBuffer buf = new StringBuffer("/lib/gcc-lib/");
buf.append(GccProcessor.getMachine());
buf.append('/');
buf.append(GccProcessor.getVersion());
//
// build default path from gcc and system /lib and /lib/w32api
//
final String[] impliedLibPath = new String[] {
buf.toString(), "/lib/w32api", "/lib"
};
//
// read gcc specs file for other library paths
//
final String[] specs = GccProcessor.getSpecs();
final String[][] libpaths = GccProcessor.parseSpecs(specs, "*link:", new String[] {
"%q"
});
String[] libpath;
if (libpaths[0].length > 0) {
libpath = new String[libpaths[0].length + 3];
int i = 0;
for (; i < libpaths[0].length; i++) {
libpath[i] = libpaths[0][i];
}
libpath[i++] = buf.toString();
libpath[i++] = "/lib/w32api";
libpath[i++] = "/lib";
} else {
//
// if a failure to find any matches then
// use some default values for lib path entries
libpath = new String[] {
"/usr/local/lib/mingw", "/usr/local/lib", "/usr/lib/w32api", "/usr/lib/mingw", "/usr/lib", buf.toString(),
"/lib/w32api", "/lib"
};
}
for (int i = 0; i < libpath.length; i++) {
if (libpath[i].contains("mingw")) {
libpath[i] = null;
}
}
//
// if cygwin then
// we have to prepend location of gcc32
// and .. to start of absolute filenames to
// have something that will exist in the
// windows filesystem
if (GccProcessor.isCygwin()) {
GccProcessor.convertCygwinFilenames(libpath);
}
//
// check that remaining entries are actual directories
//
final int count = CUtil.checkDirectoryArray(libpath);
//
// populate return array with remaining entries
//
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() ? machBundleLinker : isWindows() ? dllLinker : soLinker;
}
if (type.isSharedLibrary()) {
return isDarwin() ? machDllLinker : isWindows() ? dllLinker : isAIX() ? aLinker : soLinker;
}
// ENDFREEHEP
return instance;
}
}