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.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import net.sf.antcontrib.cpptasks.CUtil; import net.sf.antcontrib.cpptasks.CompilerDef; import net.sf.antcontrib.cpptasks.CompilerEnum; import net.sf.antcontrib.cpptasks.OptimizationEnum; import net.sf.antcontrib.cpptasks.types.CompilerArgument; import net.sf.antcontrib.cpptasks.types.ConditionalFileSet; import net.sf.antcontrib.cpptasks.types.DefineArgument; import net.sf.antcontrib.cpptasks.types.DefineSet; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.logging.Log; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.StringUtils; /** * Abstract Compiler class * * @author Mark Donszelmann */ public abstract class Compiler { /** * The name of the compiler. Some choices are: "msvc", "g++", "gcc", "CC", "cc", "icc", "icpc", ... Default is * Architecture-OS-Linker specific: FIXME: table missing * * @parameter expression="" */ private String name; /** * Source directory for native files * * @parameter expression="${basedir}/src/main" * @required */ private File sourceDirectory; /** * Source directory for native test files * * @parameter expression="${basedir}/src/test" * @required */ private File testSourceDirectory; /** * Include patterns for sources * * @parameter expression="" * @required */ private Set includes = new HashSet(); /** * Exclude patterns for sources * * @parameter expression="" * @required */ private Set excludes = new HashSet(); /** * Compile with debug information. * * @parameter expression="" default-value="false" * @required */ private boolean debug = false; /** * Enables generation of exception handling code. * * @parameter expression="" default-value="true" * @required */ private boolean exceptions = true; /** * Enables run-time type information. * * @parameter expression="" default-value="true" * @required */ private boolean rtti = true; /** * Sets optimization. Possible choices are: "none", "size", "minimal", "speed", "full", "aggressive", "extreme", * "unsafe". * * @parameter expression="" default-value="none" * @required */ private String optimize = "none"; /** * Enables or disables generation of multi-threaded code. Default value: false, except on Windows. * * @parameter expression="" default-value="false" * @required */ private boolean multiThreaded = false; /** * Defines * * @parameter expression="" */ private List defines; /** * Defines for the compiler as a comma separated list of name[=value] pairs, where the value is optional. Will work * in combination with <defines>. * * @parameter expression="" */ private String defineSet; /** * Clears default defines * * @parameter expression="" default-value="false" * @required */ private boolean clearDefaultDefines; /** * Undefines * * @parameter expression="" */ private List undefines; /** * Undefines for the compiler as a comma separated list of name[=value] pairs where the value is optional. Will work * in combination with <undefines>. * * @parameter expression="" */ private String undefineSet; /** * Clears default undefines * * @parameter expression="" default-value="false" * @required */ private boolean clearDefaultUndefines; /** * Include Paths. Defaults to "${sourceDirectory}/include" * * @parameter expression="" */ private List includePaths; /** * Test Include Paths. Defaults to "${testSourceDirectory}/include" * * @parameter expression="" */ private List testIncludePaths; /** * System Include Paths, which are added at the end of all include paths * * @parameter expression="" */ private List systemIncludePaths; /** * Additional options for the C++ compiler Defaults to Architecture-OS-Linker specific values. FIXME table missing * * @parameter expression="" */ private List options; /** * Options for the compiler as a whitespace separated list. Will work in combination with <options>. * * @parameter expression="" */ private String optionSet; /** * Clears default options * * @parameter expression="" default-value="false" * @required */ private boolean clearDefaultOptions; /** * Comma separated list of filenames to compile in order * * @parameter expression="" */ private String compileOrder; private AbstractCompileMojo mojo; public static final String MAIN = "main"; public static final String TEST = "test"; protected Compiler() { } public String getName() throws MojoFailureException, MojoExecutionException { // adjust default values if ( name == null ) { name = NarProperties.getInstance(mojo.getMavenProject()).getProperty( getPrefix() + "compiler" ); } return name; } public final void setAbstractCompileMojo( AbstractCompileMojo mojo ) { this.mojo = mojo; } public final List/* <File> */getSourceDirectories() { return getSourceDirectories( "dummy" ); } private List/* <File> */getSourceDirectories( String type ) { List sourceDirectories = new ArrayList(); File baseDir = mojo.getMavenProject().getBasedir(); if ( type.equals( TEST ) ) { if ( testSourceDirectory == null ) { testSourceDirectory = new File( baseDir, "/src/test" ); } if ( testSourceDirectory.exists() ) { sourceDirectories.add( testSourceDirectory ); } for ( Iterator i = mojo.getMavenProject().getTestCompileSourceRoots().iterator(); i.hasNext(); ) { File extraTestSourceDirectory = new File( (String) i.next() ); if ( extraTestSourceDirectory.exists() ) { sourceDirectories.add( extraTestSourceDirectory ); } } } else { if ( sourceDirectory == null ) { sourceDirectory = new File( baseDir, "src/main" ); } if ( sourceDirectory.exists() ) { sourceDirectories.add( sourceDirectory ); } for ( Iterator i = mojo.getMavenProject().getCompileSourceRoots().iterator(); i.hasNext(); ) { File extraSourceDirectory = new File( (String) i.next() ); if ( extraSourceDirectory.exists() ) { sourceDirectories.add( extraSourceDirectory ); } } } if ( mojo.getLog().isDebugEnabled() ) { for ( Iterator i = sourceDirectories.iterator(); i.hasNext(); ) { mojo.getLog().debug( "Added to sourceDirectory: " + ( (File) i.next() ).getPath() ); } } return sourceDirectories; } protected final List/* <String> */getIncludePaths( String type ) { return createIncludePaths( type, type.equals( TEST ) ? testIncludePaths : includePaths ); } private List/* <String> */createIncludePaths( String type, List paths ) { List includeList = paths; if ( includeList == null || ( paths.size() == 0 ) ) { includeList = new ArrayList(); for ( Iterator i = getSourceDirectories( type ).iterator(); i.hasNext(); ) { //VR 20100318 only add include directories that exist - we now fail the build fast if an include directory does not exist File includePath = new File( (File) i.next(), "include" ); if(includePath.isDirectory()) { includeList.add( includePath.getPath() ); } } } return includeList; } public final Set getIncludes() throws MojoFailureException, MojoExecutionException { return getIncludes( "main" ); } protected final Set getIncludes( String type ) throws MojoFailureException, MojoExecutionException { Set result = new HashSet(); if ( !type.equals( TEST ) && !includes.isEmpty() ) { result.addAll( includes ); } else { String defaultIncludes = NarProperties.getInstance(mojo.getMavenProject()).getProperty( getPrefix() + "includes" ); if ( defaultIncludes != null ) { String[] include = defaultIncludes.split( " " ); for ( int i = 0; i < include.length; i++ ) { result.add( include[i].trim() ); } } } return result; } protected final Set getExcludes() throws MojoFailureException, MojoExecutionException { Set result = new HashSet(); // add all excludes if ( excludes.isEmpty() ) { String defaultExcludes = NarProperties.getInstance(mojo.getMavenProject()).getProperty( getPrefix() + "excludes" ); if ( defaultExcludes != null ) { String[] exclude = defaultExcludes.split( " " ); for ( int i = 0; i < exclude.length; i++ ) { result.add( exclude[i].trim() ); } } } else { result.addAll( excludes ); } return result; } protected final String getPrefix() throws MojoFailureException, MojoExecutionException { return mojo.getAOL().getKey() + "." + getLanguage() + "."; } public final CompilerDef getCompiler( String type, String output ) throws MojoFailureException, MojoExecutionException { String name = getName(); if (name == null) return null; CompilerDef compiler = new CompilerDef(); compiler.setProject( mojo.getAntProject() ); CompilerEnum compilerName = new CompilerEnum(); compilerName.setValue( name ); compiler.setName( compilerName ); // debug, exceptions, rtti, multiThreaded compiler.setDebug( debug ); compiler.setExceptions( exceptions ); compiler.setRtti( rtti ); compiler.setMultithreaded( mojo.getOS().equals( "Windows" ) ? true : multiThreaded ); // optimize OptimizationEnum optimization = new OptimizationEnum(); optimization.setValue( optimize ); compiler.setOptimize( optimization ); // add options if ( options != null ) { for ( Iterator i = options.iterator(); i.hasNext(); ) { CompilerArgument arg = new CompilerArgument(); arg.setValue( (String) i.next() ); compiler.addConfiguredCompilerArg( arg ); } } if ( optionSet != null ) { String[] opts = optionSet.split( "\\s" ); for ( int i = 0; i < opts.length; i++ ) { CompilerArgument arg = new CompilerArgument(); arg.setValue( opts[i] ); compiler.addConfiguredCompilerArg( arg ); } } if ( !clearDefaultOptions ) { String optionsProperty = NarProperties.getInstance(mojo.getMavenProject()).getProperty( getPrefix() + "options" ); if ( optionsProperty != null ) { String[] option = optionsProperty.split( " " ); for ( int i = 0; i < option.length; i++ ) { CompilerArgument arg = new CompilerArgument(); arg.setValue( option[i] ); compiler.addConfiguredCompilerArg( arg ); } } } // add defines if ( defines != null ) { DefineSet ds = new DefineSet(); for ( Iterator i = defines.iterator(); i.hasNext(); ) { DefineArgument define = new DefineArgument(); String[] pair = ( (String) i.next() ).split( "=", 2 ); define.setName( pair[0] ); define.setValue( pair.length > 1 ? pair[1] : null ); ds.addDefine( define ); } compiler.addConfiguredDefineset( ds ); } if ( defineSet != null ) { String[] defList = defineSet.split( "," ); DefineSet defSet = new DefineSet(); for ( int i = 0; i < defList.length; i++ ) { String[] pair = defList[i].trim().split( "=", 2 ); DefineArgument def = new DefineArgument(); def.setName( pair[0] ); def.setValue( pair.length > 1 ? pair[1] : null ); defSet.addDefine( def ); } compiler.addConfiguredDefineset( defSet ); } if ( !clearDefaultDefines ) { DefineSet ds = new DefineSet(); String defaultDefines = NarProperties.getInstance(mojo.getMavenProject()).getProperty( getPrefix() + "defines" ); if ( defaultDefines != null ) { ds.setDefine( new CUtil.StringArrayBuilder( defaultDefines ) ); } compiler.addConfiguredDefineset( ds ); } // add undefines if ( undefines != null ) { DefineSet us = new DefineSet(); for ( Iterator i = undefines.iterator(); i.hasNext(); ) { DefineArgument undefine = new DefineArgument(); String[] pair = ( (String) i.next() ).split( "=", 2 ); undefine.setName( pair[0] ); undefine.setValue( pair.length > 1 ? pair[1] : null ); us.addUndefine( undefine ); } compiler.addConfiguredDefineset( us ); } if ( undefineSet != null ) { String[] undefList = undefineSet.split( "," ); DefineSet undefSet = new DefineSet(); for ( int i = 0; i < undefList.length; i++ ) { String[] pair = undefList[i].trim().split( "=", 2 ); DefineArgument undef = new DefineArgument(); undef.setName( pair[0] ); undef.setValue( pair.length > 1 ? pair[1] : null ); undefSet.addUndefine( undef ); } compiler.addConfiguredDefineset( undefSet ); } if ( !clearDefaultUndefines ) { DefineSet us = new DefineSet(); String defaultUndefines = NarProperties.getInstance(mojo.getMavenProject()).getProperty( getPrefix() + "undefines" ); if ( defaultUndefines != null ) { us.setUndefine( new CUtil.StringArrayBuilder( defaultUndefines ) ); } compiler.addConfiguredDefineset( us ); } // add include path for ( Iterator i = getIncludePaths( type ).iterator(); i.hasNext(); ) { String path = (String) i.next(); // Darren Sargent, 30Jan2008 - fail build if invalid include path(s) specified. if ( ! new File(path).exists() ) { throw new MojoFailureException("NAR: Include path not found: " + path); } compiler.createIncludePath().setPath( path ); } // add system include path (at the end) if ( systemIncludePaths != null ) { for ( Iterator i = systemIncludePaths.iterator(); i.hasNext(); ) { String path = (String) i.next(); compiler.createSysIncludePath().setPath( path ); } } // Add default fileset (if exists) List srcDirs = getSourceDirectories( type ); Set includeSet = getIncludes(); Set excludeSet = getExcludes(); // now add all but the current test to the excludes for ( Iterator i = mojo.getTests().iterator(); i.hasNext(); ) { Test test = (Test) i.next(); if ( !test.getName().equals( output ) ) { excludeSet.add( "**/" + test.getName() + ".*" ); } } for ( Iterator i = srcDirs.iterator(); i.hasNext(); ) { File srcDir = (File) i.next(); mojo.getLog().debug( "Checking for existence of " + getLanguage() + " source directory: " + srcDir ); if ( srcDir.exists() ) { if ( compileOrder != null ) { compiler.setOrder( Arrays.asList( StringUtils.split( compileOrder, ", " ) ) ); } ConditionalFileSet fileSet = new ConditionalFileSet(); fileSet.setProject( mojo.getAntProject() ); fileSet.setIncludes( StringUtils.join( includeSet.iterator(), "," ) ); fileSet.setExcludes( StringUtils.join( excludeSet.iterator(), "," ) ); fileSet.setDir( srcDir ); compiler.addFileset( fileSet ); } } return compiler; } protected abstract String getLanguage(); public final void copyIncludeFiles( MavenProject mavenProject, File targetDirectory, final Log log ) throws IOException { for ( Iterator i = getIncludePaths( "dummy" ).iterator(); i.hasNext(); ) { File path = new File( (String) i.next() ); if ( path.exists() ) { NarUtil.copyDirectoryStructure( path, targetDirectory, null, NarUtil.DEFAULT_EXCLUDES, log ); } } } }