/* | |
* | |
* Copyright 2002-2004 The Ant-Contrib project | |
* | |
* 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. | |
*/ | |
package net.sf.antcontrib.cpptasks; | |
import java.io.BufferedReader; | |
import java.io.File; | |
import java.io.FileReader; | |
import java.io.IOException; | |
import java.lang.reflect.Method; | |
import java.util.Vector; | |
import net.sf.antcontrib.cpptasks.compiler.LinkType; | |
import net.sf.antcontrib.cpptasks.compiler.Processor; | |
import net.sf.antcontrib.cpptasks.compiler.ProcessorConfiguration; | |
import net.sf.antcontrib.cpptasks.types.CommandLineArgument; | |
import net.sf.antcontrib.cpptasks.types.ConditionalFileSet; | |
import org.apache.tools.ant.BuildException; | |
import org.apache.tools.ant.DirectoryScanner; | |
import org.apache.tools.ant.Project; | |
import org.apache.tools.ant.types.DataType; | |
import org.apache.tools.ant.types.Environment; | |
import org.apache.tools.ant.types.Reference; | |
/** | |
* An abstract compiler/linker definition. | |
* | |
* @author Curt Arnold | |
*/ | |
public abstract class ProcessorDef extends DataType { | |
/** | |
* Returns the equivalent Boolean object for the specified value | |
* | |
* Equivalent to Boolean.valueOf in JDK 1.4 | |
* | |
* @param val | |
* boolean value | |
* @return Boolean.TRUE or Boolean.FALSE | |
*/ | |
protected static Boolean booleanValueOf(boolean val) { | |
if (val) { | |
return Boolean.TRUE; | |
} | |
return Boolean.FALSE; | |
} | |
/** | |
* if true, targets will be built for debugging | |
*/ | |
private Boolean debug; | |
private Environment env = null; | |
/** | |
* Reference for "extends" processor definition | |
*/ | |
private Reference extendsRef = null; | |
/** | |
* Name of property that must be present or definition will be ignored. May | |
* be null. | |
*/ | |
private String ifProp; | |
/** | |
* if true, processor definition inherits values from containing <cc> | |
* element | |
*/ | |
private boolean inherit; | |
private Boolean libtool = null; | |
protected boolean newEnvironment = false; | |
/** | |
* Processor. | |
*/ | |
private Processor processor; | |
/** | |
* Collection of <compilerarg>or <linkerarg>contained by definition | |
*/ | |
private final Vector processorArgs = new Vector(); | |
/** | |
* Collection of <compilerparam>or <linkerparam>contained by definition | |
*/ | |
private final Vector processorParams = new Vector(); | |
/** | |
* if true, all targets will be unconditionally rebuilt | |
*/ | |
private Boolean rebuild; | |
/** | |
* Collection of <fileset>contained by definition | |
*/ | |
private final Vector srcSets = new Vector(); | |
/** | |
* Name of property that if present will cause definition to be ignored. | |
* May be null. | |
*/ | |
private String unlessProp; | |
/** | |
* Constructor | |
* | |
*/ | |
protected ProcessorDef() throws NullPointerException { | |
inherit = true; | |
} | |
/** | |
* Adds a <compilerarg>or <linkerarg> | |
* | |
* @param arg | |
* command line argument, must not be null | |
* @throws NullPointerException | |
* if arg is null | |
* @throws BuildException | |
* if this definition is a reference | |
*/ | |
protected void addConfiguredProcessorArg(CommandLineArgument arg) | |
throws NullPointerException, BuildException { | |
if (arg == null) { | |
throw new NullPointerException("arg"); | |
} | |
if (isReference()) { | |
throw noChildrenAllowed(); | |
} | |
if(arg.getFile() == null ) { | |
processorArgs.addElement(arg); | |
} | |
else { | |
loadFile(arg.getFile()); | |
} | |
} | |
/** | |
* Add a <compilerarg>or <linkerarg> if specify the file attribute | |
* | |
* @param arg | |
* command line argument, must not be null | |
* @throws BuildException | |
* if the specify file not exist | |
*/ | |
protected void loadFile(File file) | |
throws BuildException { | |
FileReader fileReader; | |
BufferedReader in; | |
String str; | |
if (! file.exists()){ | |
throw new BuildException("The file " + file + " is not existed"); | |
} | |
try { | |
fileReader = new FileReader(file); | |
in = new BufferedReader(fileReader); | |
while ( (str = in.readLine()) != null ){ | |
if(str.trim() == ""){ | |
continue ; | |
} | |
str = getProject().replaceProperties(str); | |
CommandLineArgument newarg = new CommandLineArgument(); | |
newarg.setValue(str.trim()); | |
processorArgs.addElement(newarg); | |
} | |
} | |
catch(Exception e){ | |
throw new BuildException(e.getMessage()); | |
} | |
} | |
/** | |
* Adds a <compilerarg>or <linkerarg> | |
* | |
* @param arg | |
* command line argument, must not be null | |
* @throws NullPointerException | |
* if arg is null | |
* @throws BuildException | |
* if this definition is a reference | |
*/ | |
protected void addConfiguredProcessorParam(ProcessorParam param) | |
throws NullPointerException, BuildException { | |
if (param == null) { | |
throw new NullPointerException("param"); | |
} | |
if (isReference()) { | |
throw noChildrenAllowed(); | |
} | |
processorParams.addElement(param); | |
} | |
/** | |
* Add an environment variable to the launched process. | |
*/ | |
public void addEnv(Environment.Variable var) { | |
if (env == null) { | |
env = new Environment(); | |
} | |
env.addVariable(var); | |
} | |
/** | |
* Adds a source file set. | |
* | |
* Files in these set will be processed by this configuration and will not | |
* participate in the auction. | |
* | |
* @param srcSet | |
* Fileset identifying files that should be processed by this | |
* processor | |
* @throws BuildException | |
* if processor definition is a reference | |
*/ | |
public void addFileset(ConditionalFileSet srcSet) throws BuildException { | |
if (isReference()) { | |
throw noChildrenAllowed(); | |
} | |
srcSet.setProject(getProject()); | |
srcSets.addElement(srcSet); | |
} | |
/** | |
* Creates a configuration | |
* | |
* @param baseDef | |
* reference to def from containing <cc>element, may be null | |
* @return configuration | |
* | |
*/ | |
public ProcessorConfiguration createConfiguration(CCTask task, | |
LinkType linkType, ProcessorDef baseDef, TargetDef targetPlatform) { | |
if (isReference()) { | |
return ((ProcessorDef) getCheckedRef(ProcessorDef.class, | |
"ProcessorDef")).createConfiguration(task, linkType, | |
baseDef, targetPlatform); | |
} | |
ProcessorDef[] defaultProviders = getDefaultProviders(baseDef); | |
Processor proc = getProcessor(); | |
return proc.createConfiguration(task, linkType, defaultProviders, this, targetPlatform); | |
} | |
/** | |
* Prepares list of processor arguments ( <compilerarg>, <linkerarg>) that | |
* are active for the current project settings. | |
* | |
* @return active compiler arguments | |
*/ | |
public CommandLineArgument[] getActiveProcessorArgs() { | |
Project p = getProject(); | |
if (p == null) { | |
throw new java.lang.IllegalStateException("project must be set"); | |
} | |
if (isReference()) { | |
return ((ProcessorDef) getCheckedRef(ProcessorDef.class, | |
"ProcessorDef")).getActiveProcessorArgs(); | |
} | |
Vector activeArgs = new Vector(processorArgs.size()); | |
for (int i = 0; i < processorArgs.size(); i++) { | |
CommandLineArgument arg = (CommandLineArgument) processorArgs | |
.elementAt(i); | |
if (arg.isActive(p)) { | |
activeArgs.addElement(arg); | |
} | |
} | |
CommandLineArgument[] array = new CommandLineArgument[activeArgs.size()]; | |
activeArgs.copyInto(array); | |
return array; | |
} | |
/** | |
* Prepares list of processor arguments ( <compilerarg>, <linkerarg>) that | |
* are active for the current project settings. | |
* | |
* @return active compiler arguments | |
*/ | |
public ProcessorParam[] getActiveProcessorParams() { | |
Project p = getProject(); | |
if (p == null) { | |
throw new java.lang.IllegalStateException("project must be set"); | |
} | |
if (isReference()) { | |
return ((ProcessorDef) getCheckedRef(ProcessorDef.class, | |
"ProcessorDef")).getActiveProcessorParams(); | |
} | |
Vector activeParams = new Vector(processorParams.size()); | |
for (int i = 0; i < processorParams.size(); i++) { | |
ProcessorParam param = (ProcessorParam) processorParams | |
.elementAt(i); | |
if (param.isActive(p)) { | |
activeParams.addElement(param); | |
} | |
} | |
ProcessorParam[] array = new ProcessorParam[activeParams.size()]; | |
activeParams.copyInto(array); | |
return array; | |
} | |
/** | |
* Gets boolean indicating debug build | |
* | |
* @param defaultProviders | |
* array of ProcessorDef's in descending priority | |
* @param index | |
* index to first element in array that should be considered | |
* @return if true, built targets for debugging | |
*/ | |
public boolean getDebug(ProcessorDef[] defaultProviders, int index) { | |
if (isReference()) { | |
return ((ProcessorDef) getCheckedRef(ProcessorDef.class, | |
"ProcessorDef")).getDebug(defaultProviders, index); | |
} | |
if (debug != null) { | |
return debug.booleanValue(); | |
} else { | |
if (defaultProviders != null && index < defaultProviders.length) { | |
return defaultProviders[index].getDebug(defaultProviders, | |
index + 1); | |
} | |
} | |
return false; | |
} | |
/** | |
* Creates an chain of objects which provide default values in descending | |
* order of significance. | |
* | |
* @param baseDef | |
* corresponding ProcessorDef from CCTask, will be last element | |
* in array unless inherit = false | |
* @return default provider array | |
* | |
*/ | |
protected final ProcessorDef[] getDefaultProviders(ProcessorDef baseDef) { | |
ProcessorDef extendsDef = getExtends(); | |
Vector chain = new Vector(); | |
while (extendsDef != null && !chain.contains(extendsDef)) { | |
chain.addElement(extendsDef); | |
extendsDef = extendsDef.getExtends(); | |
} | |
if (baseDef != null && getInherit()) { | |
chain.addElement(baseDef); | |
} | |
ProcessorDef[] defaultProviders = new ProcessorDef[chain.size()]; | |
chain.copyInto(defaultProviders); | |
return defaultProviders; | |
} | |
/** | |
* Gets the ProcessorDef specified by the extends attribute | |
* | |
* @return Base ProcessorDef, null if extends is not specified | |
* @throws BuildException | |
* if reference is not same type object | |
*/ | |
public ProcessorDef getExtends() throws BuildException { | |
if (extendsRef != null) { | |
Object obj = extendsRef.getReferencedObject(getProject()); | |
if (!getClass().isInstance(obj)) { | |
throw new BuildException("Referenced object " | |
+ extendsRef.getRefId() + " not correct type, is " | |
+ obj.getClass().getName() + " should be " | |
+ getClass().getName()); | |
} | |
return (ProcessorDef) obj; | |
} | |
return null; | |
} | |
/** | |
* Gets the inherit attribute. If the inherit value is true, this processor | |
* definition will inherit default values from the containing <cc>element. | |
* | |
* @return if true then properties from the containing <cc>element are | |
* used. | |
*/ | |
public final boolean getInherit() { | |
return inherit; | |
} | |
public boolean getLibtool() { | |
if (libtool != null) { | |
return libtool.booleanValue(); | |
} | |
if (isReference()) { | |
return ((ProcessorDef) getCheckedRef(ProcessorDef.class, | |
"ProcessorDef")).getLibtool(); | |
} | |
ProcessorDef extendsDef = getExtends(); | |
if (extendsDef != null) { | |
return extendsDef.getLibtool(); | |
} | |
return false; | |
} | |
/** | |
* Obtains the appropriate processor (compiler, linker) | |
* | |
* @return processor | |
*/ | |
protected Processor getProcessor() { | |
if (isReference()) { | |
return ((ProcessorDef) getCheckedRef(ProcessorDef.class, | |
"ProcessorDef")).getProcessor(); | |
} | |
// | |
// if a processor has not been explicitly set | |
// then may be set by an extended definition | |
if (processor == null) { | |
ProcessorDef extendsDef = getExtends(); | |
if (extendsDef != null) { | |
return extendsDef.getProcessor(); | |
} | |
} | |
return processor; | |
} | |
/** | |
* Gets a boolean value indicating whether all targets must be rebuilt | |
* regardless of dependency analysis. | |
* | |
* @param defaultProviders | |
* array of ProcessorDef's in descending priority | |
* @param index | |
* index to first element in array that should be considered | |
* @return true if all targets should be rebuilt. | |
*/ | |
public boolean getRebuild(ProcessorDef[] defaultProviders, int index) { | |
if (isReference()) { | |
return ((ProcessorDef) getCheckedRef(ProcessorDef.class, | |
"ProcessorDef")).getRebuild(defaultProviders, index); | |
} | |
if (rebuild != null) { | |
return rebuild.booleanValue(); | |
} else { | |
if (defaultProviders != null && index < defaultProviders.length) { | |
return defaultProviders[index].getRebuild(defaultProviders, | |
index + 1); | |
} | |
} | |
return false; | |
} | |
/** | |
* Returns true if the processor definition contains embedded file set | |
* definitions | |
* | |
* @return true if processor definition contains embedded filesets | |
*/ | |
public boolean hasFileSets() { | |
if (isReference()) { | |
return ((ProcessorDef) getCheckedRef(ProcessorDef.class, | |
"ProcessorDef")).hasFileSets(); | |
} | |
return srcSets.size() > 0; | |
} | |
/** | |
* Determine if this def should be used. | |
* | |
* Definition will be active if the "if" variable (if specified) is set and | |
* the "unless" variable (if specified) is not set and that all reference | |
* or extended definitions are active | |
* | |
* @return true if processor is active | |
* @throws IllegalStateException | |
* if not properly initialized | |
* @throws BuildException | |
* if "if" or "unless" variable contains suspicious values | |
* "false" or "no" which indicates possible confusion | |
*/ | |
public boolean isActive() throws BuildException, IllegalStateException { | |
Project project = getProject(); | |
if (!CUtil.isActive(project, ifProp, unlessProp)) { | |
return false; | |
} | |
if (isReference()) { | |
if (!((ProcessorDef) getCheckedRef(ProcessorDef.class, | |
"ProcessorDef")).isActive()) { | |
return false; | |
} | |
} | |
// | |
// walk through any extended definitions | |
// | |
ProcessorDef[] defaultProviders = getDefaultProviders(null); | |
for (int i = 0; i < defaultProviders.length; i++) { | |
if (!defaultProviders[i].isActive()) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/** | |
* Sets the class name for the adapter. Use the "name" attribute when the | |
* tool is supported. | |
* | |
* @param className | |
* full class name | |
* | |
*/ | |
public void setClassname(String className) throws BuildException { | |
Object proc = null; | |
try { | |
Class implClass = ProcessorDef.class.getClassLoader().loadClass( | |
className); | |
try { | |
Method getInstance = implClass.getMethod("getInstance", | |
new Class[0]); | |
proc = getInstance.invoke(null, new Object[0]); | |
} catch (Exception ex) { | |
proc = implClass.newInstance(); | |
} | |
} catch (Exception ex) { | |
throw new BuildException(ex); | |
} | |
setProcessor((Processor) proc); | |
} | |
/** | |
* If set true, all targets will be built for debugging. | |
* | |
* @param debug | |
* true if targets should be built for debugging | |
* @throws BuildException | |
* if processor definition is a reference | |
*/ | |
public void setDebug(boolean debug) throws BuildException { | |
if (isReference()) { | |
throw tooManyAttributes(); | |
} | |
this.debug = booleanValueOf(debug); | |
} | |
/** | |
* Sets a description of the current data type. | |
*/ | |
public void setDescription(String desc) { | |
super.setDescription(desc); | |
} | |
/** | |
* Specifies that this element extends the element with id attribute with a | |
* matching value. The configuration will be constructed from the settings | |
* of this element, element referenced by extends, and the containing cc | |
* element. | |
* | |
* @param extendsRef | |
* Reference to the extended processor definition. | |
* @throws BuildException | |
* if this processor definition is a reference | |
*/ | |
public void setExtends(Reference extendsRef) throws BuildException { | |
if (isReference()) { | |
throw tooManyAttributes(); | |
} | |
this.extendsRef = extendsRef; | |
} | |
/** | |
* Sets an id that can be used to reference this element. | |
* | |
* @param id | |
* id | |
*/ | |
public void setId(String id) { | |
// | |
// this is actually accomplished by a different | |
// mechanism, but we can document it | |
// | |
} | |
/** | |
* Sets the property name for the 'if' condition. | |
* | |
* The configuration will be ignored unless the property is defined. | |
* | |
* The value of the property is insignificant, but values that would imply | |
* misinterpretation ("false", "no") will throw an exception when | |
* evaluated. | |
* | |
* @param propName | |
* name of property | |
*/ | |
public void setIf(String propName) { | |
ifProp = propName; | |
} | |
/** | |
* If inherit has the default value of true, defines, includes and other | |
* settings from the containing <cc>element will be inherited. | |
* | |
* @param inherit | |
* new value | |
* @throws BuildException | |
* if processor definition is a reference | |
*/ | |
public void setInherit(boolean inherit) throws BuildException { | |
if (isReference()) { | |
throw super.tooManyAttributes(); | |
} | |
this.inherit = inherit; | |
} | |
/** | |
* Set use of libtool. | |
* | |
* If set to true, the "libtool " will be prepended to the command line | |
* | |
* @param libtool | |
* If true, use libtool. | |
*/ | |
public void setLibtool(boolean libtool) { | |
if (isReference()) { | |
throw tooManyAttributes(); | |
} | |
this.libtool = booleanValueOf(libtool); | |
} | |
/** | |
* Do not propagate old environment when new environment variables are | |
* specified. | |
*/ | |
public void setNewenvironment(boolean newenv) { | |
newEnvironment = newenv; | |
} | |
/** | |
* Sets the processor | |
* | |
* @param processor | |
* processor, may not be null. | |
* @throws BuildException | |
* if ProcessorDef is a reference | |
* @throws NullPointerException | |
* if processor is null | |
*/ | |
protected void setProcessor(Processor processor) throws BuildException, | |
NullPointerException { | |
if (processor == null) { | |
throw new NullPointerException("processor"); | |
} | |
if (isReference()) { | |
throw super.tooManyAttributes(); | |
} | |
if (env == null && !newEnvironment) { | |
this.processor = processor; | |
} else { | |
this.processor = processor.changeEnvironment(newEnvironment, env); | |
} | |
} | |
/** | |
* If set true, all targets will be unconditionally rebuilt. | |
* | |
* @param rebuild | |
* if true, rebuild all targets. | |
* @throws BuildException | |
* if processor definition is a reference | |
*/ | |
public void setRebuild(boolean rebuild) throws BuildException { | |
if (isReference()) { | |
throw tooManyAttributes(); | |
} | |
this.rebuild = booleanValueOf(rebuild); | |
} | |
/** | |
* Specifies that this element should behave as if the content of the | |
* element with the matching id attribute was inserted at this location. If | |
* specified, no other attributes or child content should be specified, | |
* other than "if", "unless" and "description". | |
* | |
* @param ref | |
* Reference to other element | |
* | |
*/ | |
public void setRefid(org.apache.tools.ant.types.Reference ref) { | |
super.setRefid(ref); | |
} | |
/** | |
* Set the property name for the 'unless' condition. | |
* | |
* If named property is set, the configuration will be ignored. | |
* | |
* The value of the property is insignificant, but values that would imply | |
* misinterpretation ("false", "no") of the behavior will throw an | |
* exception when evaluated. | |
* | |
* @param propName | |
* name of property | |
*/ | |
public void setUnless(String propName) { | |
unlessProp = propName; | |
} | |
/** | |
* This method calls the FileVistor's visit function for every file in the | |
* processors definition | |
* | |
* @param visitor | |
* object whose visit method is called for every file | |
*/ | |
public void visitFiles(FileVisitor visitor) { | |
Project p = getProject(); | |
if (p == null) { | |
throw new java.lang.IllegalStateException( | |
"project must be set before this call"); | |
} | |
if (isReference()) { | |
((ProcessorDef) getCheckedRef(ProcessorDef.class, "ProcessorDef")) | |
.visitFiles(visitor); | |
} | |
// | |
// if this processor extends another, | |
// visit its files first | |
// | |
ProcessorDef extendsDef = getExtends(); | |
if (extendsDef != null) { | |
extendsDef.visitFiles(visitor); | |
} | |
for (int i = 0; i < srcSets.size(); i++) { | |
ConditionalFileSet srcSet = (ConditionalFileSet) srcSets | |
.elementAt(i); | |
if (srcSet.isActive()) { | |
// Find matching source files | |
DirectoryScanner scanner = srcSet.getDirectoryScanner(p); | |
// Check each source file - see if it needs compilation | |
String[] fileNames = scanner.getIncludedFiles(); | |
File parentDir = scanner.getBasedir(); | |
for (int j = 0; j < fileNames.length; j++) { | |
String currentFile = fileNames[j]; | |
visitor.visit(parentDir, currentFile); | |
} | |
} | |
} | |
} | |
public Vector getSrcSets() { | |
if (isReference()) { | |
return ((ProcessorDef) getCheckedRef(ProcessorDef.class, | |
"ProcessorDef")).getSrcSets(); | |
} | |
return srcSets; | |
} | |
} |