package org.apache.maven.plugin.nar; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ import java.io.File; import java.io.IOException; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.sf.antcontrib.cpptasks.CUtil; import net.sf.antcontrib.cpptasks.LinkerDef; import net.sf.antcontrib.cpptasks.LinkerEnum; import net.sf.antcontrib.cpptasks.types.LibrarySet; import net.sf.antcontrib.cpptasks.types.LibraryTypeEnum; import net.sf.antcontrib.cpptasks.types.LinkerArgument; import net.sf.antcontrib.cpptasks.types.SystemLibrarySet; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.tools.ant.Project; import org.codehaus.plexus.util.FileUtils; /** * 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 expression="" */ private String name; /** * Enables or disables incremental linking. * * @parameter expression="" default-value="false" * @required */ private boolean incremental = false; /** * Enables or disables the production of a map file. * * @parameter expression="" default-value="false" * @required */ private boolean map = false; /** * Options for the linker Defaults to Architecture-OS-Linker specific values. FIXME table missing * * @parameter expression="" */ private List options; /** * Options for the linker as a whitespace separated list. Defaults to Architecture-OS-Linker specific values. Will * work in combination with <options>. * * @parameter expression="" */ private String optionSet; /** * Clears default options * * @parameter expression="" default-value="false" * @required */ private boolean clearDefaultOptions; /** * Adds libraries to the linker. * * @parameter expression="" */ private List/* <Lib> */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 expression="" */ private String libSet; /** * Adds system libraries to the linker. * * @parameter expression="" */ private List/* <SysLib> */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 expression="" */ private String sysLibSet; /** * <p> * 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. * </p> * <p> * Example: <narDependencyLibOrder>someGroup:myProduct, other.group:productB<narDependencyLibOrder> * </p> * * @parameter expression="" */ private String narDependencyLibOrder; public Linker() { // default constructor for use as TAG } /** * For use with specific named linker. * * @param name */ public Linker( String name ) { this.name = name; } public final String getName() { return name; } public final String getName( NarProperties properties, String prefix ) throws MojoFailureException, MojoExecutionException { if ( ( name == null ) && ( properties != null ) && ( prefix != null ) ) { name = properties.getProperty( prefix + "linker" ); } if ( name == null ) { throw new MojoExecutionException( "NAR: One of two things may be wrong here:\n\n" + "1. <Name> tag is missing inside the <Linker> tag of your NAR configuration\n\n" + "2. no linker is defined in the aol.properties file for '" + prefix + "linker'\n" ); } return name; } public final String getVersion() throws MojoFailureException, MojoExecutionException { if ( name == null ) { throw new MojoFailureException( "Cannot deduce linker version if name is null" ); } String version = null; TextStream out = new StringTextStream(); TextStream err = new StringTextStream(); TextStream dbg = new StringTextStream(); if ( name.equals( "g++" ) || name.equals( "gcc" ) ) { NarUtil.runCommand( "gcc", new String[] { "--version" }, null, null, out, err, dbg ); Pattern p = Pattern.compile( "\\d+\\.\\d+\\.\\d+" ); Matcher m = p.matcher( out.toString() ); if ( m.find() ) { version = m.group( 0 ); } } else if ( name.equals( "msvc" ) ) { NarUtil.runCommand( "link", new String[] { "/version" }, null, null, out, err, dbg ); Pattern p = Pattern.compile( "\\d+\\.\\d+\\.\\d+" ); Matcher m = p.matcher( out.toString() ); if ( m.find() ) { version = m.group( 0 ); } } else if ( name.equals( "icc" ) || name.equals( "icpc" ) ) { NarUtil.runCommand( "icc", new String[] { "--version" }, null, null, out, err, dbg ); Pattern p = Pattern.compile( "\\d+\\.\\d+" ); Matcher m = p.matcher( out.toString() ); if ( m.find() ) { version = m.group( 0 ); } } else if ( name.equals( "icl" ) ) { NarUtil.runCommand( "icl", new String[] { "/QV" }, null, null, out, err, dbg ); Pattern p = Pattern.compile( "\\d+\\.\\d+" ); Matcher m = p.matcher( err.toString() ); if ( m.find() ) { version = m.group( 0 ); } } else if ( name.equals( "CC" ) ) { NarUtil.runCommand( "CC", new String[] { "-V" }, null, null, out, err, dbg ); Pattern p = Pattern.compile( "\\d+\\.d+" ); Matcher m = p.matcher( err.toString() ); if ( m.find() ) { version = m.group( 0 ); } } else { throw new MojoFailureException( "Cannot find version number for linker '" + name + "'" ); } if (version == null) { throw new MojoFailureException( "Cannot deduce version number from: " + out.toString() ); } return version; } public final LinkerDef getLinker( AbstractCompileMojo mojo, Project antProject, String os, String prefix, String type ) throws MojoFailureException, MojoExecutionException { if ( name == null ) { throw new MojoFailureException( "NAR: Please specify a <Name> as part of <Linker>" ); } LinkerDef linker = new LinkerDef(); linker.setProject( antProject ); LinkerEnum linkerEnum = new LinkerEnum(); linkerEnum.setValue( name ); linker.setName( linkerEnum ); // incremental, map linker.setIncremental( incremental ); linker.setMap( map ); // Add definitions (Window only) if ( os.equals( OS.WINDOWS ) && ( type.equals( Library.SHARED ) || type.equals( Library.JNI ) ) ) { Set defs = new HashSet(); try { List cSrcDirs = mojo.getC().getSourceDirectories(); for ( Iterator i = cSrcDirs.iterator(); i.hasNext(); ) { File dir = (File) i.next(); if ( dir.exists() ) { defs.addAll( FileUtils.getFiles( dir, "**/*.def", null ) ); } } } catch ( IOException e ) { } try { List cppSrcDirs = mojo.getCpp().getSourceDirectories(); for ( Iterator i = cppSrcDirs.iterator(); i.hasNext(); ) { File dir = (File) i.next(); if ( dir.exists() ) { defs.addAll( FileUtils.getFiles( dir, "**/*.def", null ) ); } } } catch ( IOException e ) { } try { List fortranSrcDirs = mojo.getFortran().getSourceDirectories(); for ( Iterator i = fortranSrcDirs.iterator(); i.hasNext(); ) { File dir = (File) i.next(); if ( dir.exists() ) { defs.addAll( FileUtils.getFiles( dir, "**/*.def", null ) ); } } } catch ( IOException e ) { } for ( Iterator i = defs.iterator(); i.hasNext(); ) { LinkerArgument arg = new LinkerArgument(); arg.setValue( "/def:" + i.next() ); 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().startsWith( "6." ) ) { LinkerArgument arg = new LinkerArgument(); arg.setValue( "/MANIFEST" ); linker.addConfiguredLinkerArg( arg ); } // Add options to linker if ( options != null ) { for ( Iterator i = options.iterator(); i.hasNext(); ) { LinkerArgument arg = new LinkerArgument(); arg.setValue( (String) i.next() ); linker.addConfiguredLinkerArg( arg ); } } if ( optionSet != null ) { String[] opts = optionSet.split( "\\s" ); for ( int i = 0; i < opts.length; i++ ) { LinkerArgument arg = new LinkerArgument(); arg.setValue( opts[i] ); linker.addConfiguredLinkerArg( arg ); } } if ( !clearDefaultOptions ) { String option = NarProperties.getInstance(mojo.getMavenProject()).getProperty( prefix + "options" ); if ( option != null ) { String[] opt = option.split( " " ); for ( int i = 0; i < opt.length; i++ ) { LinkerArgument arg = new LinkerArgument(); arg.setValue( opt[i] ); linker.addConfiguredLinkerArg( arg ); } } } // record the preference for nar dependency library link order if ( narDependencyLibOrder != null ) { List libOrder = new LinkedList(); String[] lib = narDependencyLibOrder.split( "," ); for ( int i = 0; i < lib.length; i++ ) { libOrder.add( lib[i].trim() ); } mojo.setDependencyLibOrder( libOrder ); } // Add Libraries to linker if ( ( libs != null ) || ( libSet != null ) ) { if ( libs != null ) { for ( Iterator i = libs.iterator(); i.hasNext(); ) { Lib lib = (Lib) i.next(); lib.addLibSet( mojo, linker, antProject ); } } if ( libSet != null ) { addLibraries( libSet, linker, antProject, false ); } } else { String libsList = NarProperties.getInstance(mojo.getMavenProject()).getProperty( prefix + "libs" ); addLibraries( libsList, linker, antProject, false ); } // Add System Libraries to linker if ( ( sysLibs != null ) || ( sysLibSet != null ) ) { if ( sysLibs != null ) { for ( Iterator i = sysLibs.iterator(); i.hasNext(); ) { SysLib sysLib = (SysLib) i.next(); linker.addSyslibset( sysLib.getSysLibSet( antProject ) ); } } if ( sysLibSet != null ) { addLibraries( sysLibSet, linker, antProject, true ); } } else { String sysLibsList = NarProperties.getInstance(mojo.getMavenProject()).getProperty( prefix + "sysLibs" ); addLibraries( sysLibsList, linker, antProject, true ); } return linker; } private void addLibraries( String libraryList, LinkerDef linker, Project antProject, boolean isSystem ) { if ( libraryList == null ) { return; } String[] lib = libraryList.split( "," ); for ( int i = 0; i < lib.length; i++ ) { String[] libInfo = lib[i].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 ) { 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 ); } } } }