// Copyright FreeHEP, 2005-2007.
package org.freehep.maven.nar;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
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.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.StringUtils;
/**
* Abstract Compiler class
*
* @author <a href="Mark.Donszelmann@slac.stanford.edu">Mark Donszelmann</a>
* @version $Id: Compiler.java 13350 2007-09-20 18:42:29Z duns $
*/
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;
/**
* 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;
/**
* 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;
private AbstractCompileMojo mojo;
protected Compiler() {
}
public void setAbstractCompileMojo(AbstractCompileMojo mojo) {
this.mojo = mojo;
}
public File getSourceDirectory() {
return getSourceDirectory("dummy");
}
protected File getSourceDirectory(String type) {
if (sourceDirectory == null) {
sourceDirectory = new File(mojo.getMavenProject().getBasedir(),
"src/" + (type.equals("test") ? "test" : "main"));
}
return sourceDirectory;
}
protected List/* <String> */getIncludePaths(String type) {
if (includePaths == null || (includePaths.size() == 0)) {
includePaths = new ArrayList();
includePaths.add(new File(getSourceDirectory(type), "include")
.getPath());
}
return includePaths;
}
public Set getIncludes() throws MojoFailureException {
return getIncludes("main");
}
protected Set getIncludes(String type) throws MojoFailureException {
Set result = new HashSet();
if (!type.equals("test") && !includes.isEmpty()) {
result.addAll(includes);
} else {
String defaultIncludes = NarUtil.getDefaults().getProperty(
getPrefix() + "includes");
if (defaultIncludes == null) {
throw new MojoFailureException(
"NAR: Please specify <Includes> as part of <Cpp>, <C> or <Fortran> for "
+ getPrefix());
}
String[] include = defaultIncludes.split(" ");
for (int i = 0; i < include.length; i++) {
result.add(include[i].trim());
}
}
return result;
}
protected Set getExcludes() throws MojoFailureException {
Set result = new HashSet();
// add all excludes
if (excludes.isEmpty()) {
String defaultExcludes = NarUtil.getDefaults().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 String getPrefix() throws MojoFailureException {
return mojo.getAOL().getKey() + "." + getName() + ".";
}
public CompilerDef getCompiler(String type, String output)
throws MojoFailureException {
// adjust default values
if (name == null)
name = NarUtil.getDefaults().getProperty(getPrefix() + "compiler");
if (name == null) {
throw new MojoFailureException(
"NAR: Please specify <Name> as part of <Cpp>, <C> or <Fortran> for "
+ getPrefix());
}
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 = NarUtil.getDefaults().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 defineSet = 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);
defineSet.addDefine(define);
}
compiler.addConfiguredDefineset(defineSet);
}
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 defineSet = new DefineSet();
String defaultDefines = NarUtil.getDefaults().getProperty(
getPrefix() + "defines");
if (defaultDefines != null) {
defineSet
.setDefine(new CUtil.StringArrayBuilder(defaultDefines));
}
compiler.addConfiguredDefineset(defineSet);
}
// add undefines
if (undefines != null) {
DefineSet undefineSet = 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);
undefineSet.addUndefine(undefine);
}
compiler.addConfiguredDefineset(undefineSet);
}
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 undefineSet = new DefineSet();
String defaultUndefines = NarUtil.getDefaults().getProperty(
getPrefix() + "undefines");
if (defaultUndefines != null) {
undefineSet.setUndefine(new CUtil.StringArrayBuilder(
defaultUndefines));
}
compiler.addConfiguredDefineset(undefineSet);
}
// add include path
for (Iterator i = getIncludePaths(type).iterator(); i.hasNext();) {
String path = (String) i.next();
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)
File srcDir = getSourceDirectory(type);
Set includes = getIncludes();
Set excludes = 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)) {
excludes.add("**/" + test.getName() + ".*");
}
}
mojo.getLog().debug(
"Checking for existence of " + getName() + " sourceDirectory: "
+ srcDir);
if (srcDir.exists()) {
ConditionalFileSet fileSet = new ConditionalFileSet();
fileSet.setProject(mojo.getAntProject());
fileSet.setIncludes(StringUtils.join(includes.iterator(), ","));
fileSet.setExcludes(StringUtils.join(excludes.iterator(), ","));
fileSet.setDir(srcDir);
compiler.addFileset(fileSet);
}
// add other sources
if (!type.equals("test")) {
for (Iterator i = mojo.getMavenProject().getCompileSourceRoots()
.iterator(); i.hasNext();) {
File dir = new File((String) i.next());
mojo.getLog().debug(
"Checking for existence of " + getName()
+ " sourceCompileRoot: " + dir);
if (dir.exists()) {
ConditionalFileSet otherFileSet = new ConditionalFileSet();
otherFileSet.setProject(mojo.getAntProject());
otherFileSet.setIncludes(StringUtils.join(includes
.iterator(), ","));
otherFileSet.setExcludes(StringUtils.join(excludes
.iterator(), ","));
otherFileSet.setDir(dir);
compiler.addFileset(otherFileSet);
}
}
}
return compiler;
}
protected abstract String getName();
public void copyIncludeFiles(MavenProject mavenProject, File targetDirectory)
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);
}
}
}
}