blob: 38faf427e73cedc230c4389997959e766c50041a [file] [log] [blame]
/*
*
* 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;
}
}