All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.maven_nar.Linker Maven / Gradle / Ivy

Go to download

This plugin compiles native code and publishes native artifacts in the form of nar files.

There is a newer version: 3.10.1
Show newest version
/*
 * #%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;

import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Arrays;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.tools.ant.Project;
import org.codehaus.plexus.util.FileUtils;

import com.github.maven_nar.cpptasks.CCTask;
import com.github.maven_nar.cpptasks.CUtil;
import com.github.maven_nar.cpptasks.LinkerDef;
import com.github.maven_nar.cpptasks.LinkerEnum;
import com.github.maven_nar.cpptasks.types.LibrarySet;
import com.github.maven_nar.cpptasks.types.LibraryTypeEnum;
import com.github.maven_nar.cpptasks.types.LinkerArgument;
import com.github.maven_nar.cpptasks.types.SystemLibrarySet;

/**
 * Linker tag
 * 
 * @author Mark Donszelmann
 */
public class Linker {

  /**
   * The Linker Some choices are: "msvc", "g++", "CC", "icpc", ... Default is
   * Architecture-OS-Linker specific: FIXME:
   * table missing
   */
  @Parameter
  private String name;

  /**
   * The prefix for the linker.
   */
  @Parameter
  private String prefix;

  /**
   * Path location of the linker tool
   */
  @Parameter
  private String toolPath;

  /**
   * Enables or disables incremental linking.
   */
  @Parameter(required = true)
  private boolean incremental = false;

  /**
   * Enables or disables the production of a map file.
   */
  @Parameter(required = true)
  private boolean map = false;

  @Parameter(required = true)
  private boolean skipDepLink = false;
  
  /**
   * Options for the linker Defaults to Architecture-OS-Linker specific values.
   * FIXME table missing
   */
  @Parameter
  private List options;

  /**
   * Additional options for the linker when running in the nar-testCompile
   * phase.
   * 
   */
  @Parameter
  private List testOptions;

  /**
   * Options for the linker as a whitespace separated list. Defaults to
   * Architecture-OS-Linker specific values. Will
   * work in combination with <options>.
   */
  @Parameter
  private String optionSet;

  /**
   * Clears default options
   */
  @Parameter(required = true)
  private boolean clearDefaultOptions;

  /**
   * Adds libraries to the linker.
   */
  @Parameter
  private List/*  */ libs;

  /**
   * Adds libraries to the linker. Will work in combination with <libs>.
   * The format is comma separated,
   * colon-delimited values (name:type:dir), like
   * "myLib:shared:/home/me/libs/, otherLib:static:/some/path".
   */
  @Parameter
  private String libSet;

  /**
   * Adds system libraries to the linker.
   */
  @Parameter
  private List/*  */ sysLibs;

  /**
   * Adds system libraries to the linker. Will work in combination with
   * <sysLibs>. The format is comma
   * separated, colon-delimited values (name:type), like
   * "dl:shared, pthread:shared".
   */
  @Parameter
  private String sysLibSet;

  /**
   * 

* Specifies the link ordering of libraries that come from nar dependencies. * The format is a comma separated list of dependency names, given as * groupId:artifactId. *

*

* Example: <narDependencyLibOrder>someGroup:myProduct, * other.group:productB<narDependencyLibOrder> *

*/ @Parameter private String narDependencyLibOrder; /** *

* Specifies to use Default link ordering of libraries that come from mvn dependency tree. * The Default link order (generated by nar) is a Level-order tree traversing list (also called BFS) of * dependency tree, given as a comma separated list of groupId:artifactId. *

*

* default Value is "false" *

*/ @Parameter(defaultValue = "false") private boolean narDefaultDependencyLibOrder = false; /** * Specifies that if using default dependency lib order then turn on/off logic that pushes * dependencies to appropriate place in linker line based on transitive dependencies. * @since 3.5.2 */ @Parameter(defaultValue = "false") protected boolean pushDepsToLowestOrder = false; /** * Specify that the linker should generate an intermediate manifest based on * the inputs. */ @Parameter(property = "nar.generateManifest", defaultValue = "true") private boolean generateManifest = true; private final Log log; public Linker() { // default constructor for use as TAG this(null); } public Linker(final Log log) { this.log = log; } /** * For use with specific named linker. * * @param name */ public Linker(final String name, final Log log) { this.name = name; this.log = log; } private void addLibraries(final String libraryList, final LinkerDef linker, final Project antProject, final boolean isSystem) { if (libraryList == null) { return; } final String[] lib = libraryList.split(","); for (final String element : lib) { final String[] libInfo = element.trim().split(":", 3); LibrarySet librarySet = new LibrarySet(); if (isSystem) { librarySet = new SystemLibrarySet(); } librarySet.setProject(antProject); librarySet.setLibs(new CUtil.StringArrayBuilder(libInfo[0])); if (libInfo.length > 1) { final LibraryTypeEnum libType = new LibraryTypeEnum(); libType.setValue(libInfo[1]); librarySet.setType(libType); if (!isSystem && libInfo.length > 2) { librarySet.setDir(new File(libInfo[2])); } } if (!isSystem) { linker.addLibset(librarySet); } else { linker.addSyslibset((SystemLibrarySet) librarySet); } } } /** * **/ public boolean isGenerateManifest() { return generateManifest; } public final LinkerDef getLinker(final AbstractCompileMojo mojo, final CCTask task, final String os, final String prefix, final String type, final List linkPaths) throws MojoFailureException, MojoExecutionException { Project antProject = task.getProject(); if (this.name == null) { throw new MojoFailureException("NAR: Please specify a as part of "); } final LinkerDef linker = new LinkerDef(); linker.setProject(antProject); final LinkerEnum linkerEnum = new LinkerEnum(); linkerEnum.setValue(this.name); linker.setName(linkerEnum); // tool path if (this.toolPath != null) { linker.setToolPath(this.toolPath); } else if (Msvc.isMSVC(name)) { linker.setToolPath(mojo.getMsvc().getToolPath()); } linker.setSkipDepLink(this.skipDepLink); // incremental, map linker.setLinkerPrefix(this.prefix); linker.setIncremental(this.incremental); linker.setMap(this.map); // Add definitions (Window only) if (os.equals(OS.WINDOWS) && getName(null, null).equals("msvc") && (type.equals(Library.SHARED) || type.equals(Library.JNI))) { final Set defs = new HashSet(); try { if (mojo.getC() != null) { final List cSrcDirs = mojo.getC().getSourceDirectories(); for (final Object cSrcDir : cSrcDirs) { final File dir = (File) cSrcDir; if (dir.exists()) { defs.addAll(FileUtils.getFiles(dir, "**/*.def", null)); } } } } catch (final IOException e) { } try { if (mojo.getCpp() != null) { final List cppSrcDirs = mojo.getCpp().getSourceDirectories(); for (final Object cppSrcDir : cppSrcDirs) { final File dir = (File) cppSrcDir; if (dir.exists()) { defs.addAll(FileUtils.getFiles(dir, "**/*.def", null)); } } } } catch (final IOException e) { } try { if (mojo.getFortran() != null) { final List fortranSrcDirs = mojo.getFortran().getSourceDirectories(); for (final Object fortranSrcDir : fortranSrcDirs) { final File dir = (File) fortranSrcDir; if (dir.exists()) { defs.addAll(FileUtils.getFiles(dir, "**/*.def", null)); } } } } catch (final IOException e) { } for (final Object def : defs) { final LinkerArgument arg = new LinkerArgument(); arg.setValue("/def:" + def); linker.addConfiguredLinkerArg(arg); } } // FIXME, this should be done in CPPTasks at some point, and may not be // necessary, but was for VS 2010 beta 2 if (os.equals(OS.WINDOWS) && getName(null, null).equals("msvc") && !getVersion(mojo).startsWith("6.") && (type.equals(Library.SHARED) || type.equals(Library.JNI) || type.equals(Library.EXECUTABLE))) { final LinkerArgument arg = new LinkerArgument(); if (isGenerateManifest()) arg.setValue("/MANIFEST"); else arg.setValue("/MANIFEST:NO"); linker.addConfiguredLinkerArg(arg); if (isGenerateManifest()) { final LinkerArgument arg2 = new LinkerArgument(); arg2.setValue("/MANIFESTFILE:" + task.getOutfile() + ".manifest"); linker.addConfiguredLinkerArg(arg2); } } // Add options to linker if (this.options != null) { for (final Object option : this.options) { final LinkerArgument arg = new LinkerArgument(); arg.setValue((String) option); linker.addConfiguredLinkerArg(arg); } } if (this.optionSet != null) { final String[] opts = this.optionSet.split("\\s"); for (final String opt : opts) { final LinkerArgument arg = new LinkerArgument(); arg.setValue(opt); linker.addConfiguredLinkerArg(arg); } } if (!this.clearDefaultOptions) { final String option = NarProperties.getInstance(mojo.getMavenProject()).getProperty(prefix + "options"); if (option != null) { final String[] opt = option.split(" "); for (final String element : opt) { final LinkerArgument arg = new LinkerArgument(); arg.setValue(element); linker.addConfiguredLinkerArg(arg); } } } //if No user preference of dependency library link order is specified then use the Default one nar generate. if ((this.narDependencyLibOrder == null) && (narDefaultDependencyLibOrder)) { if (os.equals(OS.AIX) && (getName(null, null).equals("xlC_r") || getName(null, null).equals("xlC") || getName(null, null).equals("xlc"))){ String dependencies = new StringBuilder(mojo.dependencyTreeOrderStr(pushDepsToLowestOrder, mojo.getDirectDepsOnly())).toString(); List dependency_list = Arrays.asList(dependencies.split("\\s*,\\s*")); Collections.reverse(dependency_list); StringBuilder libOrder = new StringBuilder(); boolean first = true; for (String dependency : dependency_list) { if (first) first = false; else libOrder.append(","); libOrder.append(dependency); } this.narDependencyLibOrder = libOrder.toString(); } else { this.narDependencyLibOrder = mojo.dependencyTreeOrderStr(pushDepsToLowestOrder, mojo.getDirectDepsOnly()); } } else if (pushDepsToLowestOrder && !narDefaultDependencyLibOrder) { mojo.getLog().warn("pushDepsToLowestOrder will have no effect since narDefaultDependencyLibOrder is disabled"); } else if (mojo.getDirectDepsOnly() && !narDefaultDependencyLibOrder) { mojo.getLog().warn("directDepsOnly will have no effect since narDefaultDependencyLibOrder is disabled"); } // Add transitive dependencies to the shared library search path if directDepsOnly is enabled, this is not a static library, and the OS is either Linux or AIX. if (linkPaths != null && linkPaths.size() > 0 && mojo.getDirectDepsOnly() && !type.equals(Library.STATIC) && (os.equals(OS.LINUX) || os.equals(OS.AIX))){ StringBuilder argStrBuilder = new StringBuilder(); if (os.equals(OS.LINUX)) { argStrBuilder.append("-Wl,-rpath-link,"); } else if (os.equals(OS.AIX)) { argStrBuilder.append("-L"); } for (String path : linkPaths){ argStrBuilder.append(path).append(':'); } String argStr = argStrBuilder.toString(); final LinkerArgument linkPathArg = new LinkerArgument (); // Trim trailing ':' character from argument linkPathArg.setValue(argStr.substring(0, argStr.length() - 1)); linker.addConfiguredLinkerArg(linkPathArg); } // record the preference for nar dependency library link order if (this.narDependencyLibOrder != null) { final List libOrder = new LinkedList(); final String[] lib = this.narDependencyLibOrder.split(","); for (final String element : lib) { libOrder.add(element.trim()); } mojo.setDependencyLibOrder(libOrder); } // Add Libraries to linker if (this.libs != null || this.libSet != null) { if (this.libs != null) { for (final Object lib1 : this.libs) { final Lib lib = (Lib) lib1; lib.addLibSet(mojo, linker, antProject); } } if (this.libSet != null) { addLibraries(this.libSet, linker, antProject, false); } } else { final String libsList = NarProperties.getInstance(mojo.getMavenProject()).getProperty(prefix + "libs"); addLibraries(libsList, linker, antProject, false); } // Add System Libraries to linker if (this.sysLibs != null || this.sysLibSet != null) { if (this.sysLibs != null) { for (final Object sysLib1 : this.sysLibs) { final SysLib sysLib = (SysLib) sysLib1; linker.addSyslibset(sysLib.getSysLibSet(antProject)); } } if (this.sysLibSet != null) { addLibraries(this.sysLibSet, linker, antProject, true); } } else { final String sysLibsList = NarProperties.getInstance(mojo.getMavenProject()).getProperty(prefix + "sysLibs"); addLibraries(sysLibsList, linker, antProject, true); } mojo.getMsvc().configureLinker(linker); return linker; } public final String getName() { return this.name; } public final String getName(final NarProperties properties, final String prefix) throws MojoFailureException, MojoExecutionException { if (this.name == null && properties != null && prefix != null) { this.name = properties.getProperty(prefix + "linker"); } if (this.name == null) { throw new MojoExecutionException("NAR: One of two things may be wrong here:\n\n" + "1. tag is missing inside the tag of your NAR configuration\n\n" + "2. no linker is defined in the aol.properties file for '" + prefix + "linker'\n"); } return this.name; } /** * @return The standard Linker configuration with 'testOptions' added to the * argument list. */ public final LinkerDef getTestLinker(final AbstractCompileMojo mojo, final CCTask task, final String os, final String prefix, final String type, final List linkPaths) throws MojoFailureException, MojoExecutionException { final LinkerDef linker = getLinker(mojo, task, os, prefix, type, linkPaths); if (this.testOptions != null) { for (final Object testOption : this.testOptions) { final LinkerArgument arg = new LinkerArgument(); arg.setValue((String) testOption); linker.addConfiguredLinkerArg(arg); } } return linker; } public final String getVersion() throws MojoFailureException, MojoExecutionException { return getVersion(new NarCompileMojo()); } public final String getVersion(final AbstractNarMojo mojo) throws MojoFailureException, MojoExecutionException { if (this.name == null) { throw new MojoFailureException("Cannot deduce linker version if name is null"); } String version = null; String linkerPrefix = ""; if (this.prefix != null && (!this.prefix.isEmpty())) { linkerPrefix = this.prefix; } final TextStream out = new StringTextStream(); final TextStream err = new StringTextStream(); final TextStream dbg = new StringTextStream(); if (this.name.equals("g++") || this.name.equals("gcc")) { NarUtil.runCommand(linkerPrefix+"gcc", new String[] { "--version" }, null, null, out, err, dbg, this.log); final Pattern p = Pattern.compile("\\d+\\.\\d+\\.\\d+"); final Matcher m = p.matcher(out.toString()); if (m.find()) { version = m.group(0); } } else if (this.name.equals("msvc")) { version = mojo.getMsvc().getVersion(); } else if (this.name.equals("icc") || this.name.equals("icpc")) { NarUtil.runCommand("icc", new String[] { "--version" }, null, null, out, err, dbg, this.log); final Pattern p = Pattern.compile("\\d+\\.\\d+"); final Matcher m = p.matcher(out.toString()); if (m.find()) { version = m.group(0); } } else if (this.name.equals("icl")) { NarUtil.runCommand("icl", new String[] { "/QV" }, null, null, out, err, dbg, this.log); final Pattern p = Pattern.compile("\\d+\\.\\d+"); final Matcher m = p.matcher(err.toString()); if (m.find()) { version = m.group(0); } } else if (this.name.equals("CC")) { NarUtil.runCommand("CC", new String[] { "-V" }, null, null, out, err, dbg, this.log); final Pattern p = Pattern.compile("\\d+\\.\\d+"); final Matcher m = p.matcher(err.toString()); if (m.find()) { version = m.group(0); } } else if (this.name.equals("xlC")) { NarUtil.runCommand("/usr/vacpp/bin/xlC", new String[] { "-qversion" }, null, null, out, err, dbg, this.log); final Pattern p = Pattern.compile("\\d+\\.\\d+"); final Matcher m = p.matcher(out.toString()); if (m.find()) { version = m.group(0); } } else if (this.name.equals("xlC_r")) { NarUtil.runCommand("xlC_r", new String[] { "-qversion" }, null, null, out, err, dbg, this.log); final Pattern p = Pattern.compile("\\d+\\.\\d+"); final Matcher m = p.matcher(out.toString()); if (m.find()) { version = m.group(0); } } else if (name.equals("clang") || name.equals("clang++")) { NarUtil.runCommand("clang", new String[] { "--version" }, null, null, out, err, dbg, log); final Pattern p = Pattern.compile("\\d+\\.\\d+\\.\\d+"); final Matcher m = p.matcher(out.toString()); if (m.find()) { version = m.group(0); } } else { if (!this.prefix.isEmpty()) { NarUtil.runCommand(linkerPrefix+this.name, new String[] { "--version" }, null, null, out, err, dbg, this.log); final Pattern p = Pattern.compile("\\d+\\.\\d+\\.\\d+"); final Matcher m = p.matcher(out.toString()); if (m.find()) { version = m.group(0); } } else { throw new MojoFailureException("Cannot find version number for linker '" + this.name + "'"); } } if (version == null) { if (!err.toString().isEmpty()) mojo.getLog().debug("linker returned error stream: " + err.toString()); throw new MojoFailureException("Cannot deduce version number from: " + out.toString()); } return version; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy