From cc0870758539a932dd3dc19653ce5189266f0967 Mon Sep 17 00:00:00 2001 From: Mark Donszelmann Date: Tue, 17 Jul 2007 21:18:28 +0000 Subject: Fixes for NARPLUGIN-123 --- src/net/sf/antcontrib/cpptasks/CCTask.java | 2873 +++++++++++--------- .../sf/antcontrib/cpptasks/TargetHistoryTable.java | 9 +- 2 files changed, 1519 insertions(+), 1363 deletions(-) (limited to 'src') diff --git a/src/net/sf/antcontrib/cpptasks/CCTask.java b/src/net/sf/antcontrib/cpptasks/CCTask.java index c2b665f..c90a929 100644 --- a/src/net/sf/antcontrib/cpptasks/CCTask.java +++ b/src/net/sf/antcontrib/cpptasks/CCTask.java @@ -15,13 +15,16 @@ * limitations under the License. */ package net.sf.antcontrib.cpptasks; + import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashSet; import java.util.Hashtable; import java.util.List; +import java.util.Set; import java.util.Vector; import net.sf.antcontrib.cpptasks.compiler.CompilerConfiguration; @@ -44,6 +47,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.Environment; + /** * Compile and link task. * @@ -70,18 +74,25 @@ import org.apache.tools.ant.types.Environment; *

* *

- * THIS SOFTWARE IS PROVIDED 'AS-IS', See http://www.apache.org/licenses/LICENSE-2.0 for - * additional disclaimers. + * THIS SOFTWARE IS PROVIDED 'AS-IS', See + * http://www.apache.org/licenses/LICENSE-2.0 for additional disclaimers. *

* * To use: *
    - *
  1. Place cpptasks.jar into Ant's classpath by placing in Ant's lib directory, - * adding to CLASSPATH environment variable or using the -lib command line option.
  2. + *
  3. Place cpptasks.jar into Ant's classpath by placing in Ant's lib + * directory, adding to CLASSPATH environment variable or using the -lib command + * line option.
  4. *
  5. Add type and task definitions in build file: - *
    • Ant 1.6 or later: add xmlns:cpptasks="antlib:org.sf.net.antcontrib.cpptasks" to <project> element.
    • - *
    • Ant 1.5 or later: Add <taskdef resource="cpptasks.tasks"/> and <typedef - * resource="cpptasks.types"/> to body of <project> element.
  6. + * + * *
  7. Add <cc/>, <compiler/> and <linker/> elements to * project.
  8. *
  9. Set path and environment variables to be able to run compiler from @@ -93,1386 +104,1528 @@ import org.apache.tools.ant.types.Environment; * @author Curt Arnold */ public class CCTask extends Task { - private static class SystemLibraryCollector implements FileVisitor { - private Hashtable libraries; - private Linker linker; - public SystemLibraryCollector(Linker linker, Hashtable libraries) { - this.linker = linker; - this.libraries = libraries; - } - public void visit(File basedir, String filename) { - if (linker.bid(filename) > 0) { - File libfile = new File(basedir, filename); - String key = linker.getLibraryKey(libfile); - libraries.put(key, libfile); - } - } - } - - private static class ProjectFileCollector implements FileVisitor { - private final List files; - /** - * Creates a new ProjectFileCollector. - * @param files vector for collected files. - */ - public ProjectFileCollector(List files) { - this.files = files; - } - /** - * Called for each file to be considered for collection. - * @param parentDir parent directory - * @param filename filename within directory - */ - public void visit(File parentDir, String filename) { - files.add(new File(parentDir, filename)); - } - } - - private static final ProcessorConfiguration[] EMPTY_CONFIG_ARRAY = new ProcessorConfiguration[0]; - /** - * Builds a Hashtable to targets needing to be rebuilt keyed by compiler - * configuration - */ - public static Hashtable getTargetsToBuildByConfiguration(Hashtable targets) { - Hashtable targetsByConfig = new Hashtable(); - Enumeration targetEnum = targets.elements(); - while (targetEnum.hasMoreElements()) { - TargetInfo target = (TargetInfo) targetEnum.nextElement(); - if (target.getRebuild()) { - Vector targetsForSameConfig = (Vector) targetsByConfig - .get(target.getConfiguration()); - if (targetsForSameConfig != null) { - targetsForSameConfig.addElement(target); - } else { - targetsForSameConfig = new Vector(); - targetsForSameConfig.addElement(target); - targetsByConfig.put(target.getConfiguration(), - targetsForSameConfig); - } - } - } - return targetsByConfig; - } - /** The compiler definitions. */ - private Vector _compilers = new Vector(); - /** The output file type. */ - // private LinkType _linkType = LinkType.EXECUTABLE; - /** The library sets. */ - private Vector _libsets = new Vector(); - /** The linker definitions. */ - private Vector _linkers = new Vector(); - /** The object directory. */ - private File _objDir; - /** The output file. */ - private File _outfile; - /** The linker definitions. */ - private final Vector targetPlatforms = new Vector(); - /** The distributer definitions. */ - private Vector distributers = new Vector(); - private final Vector versionInfos = new Vector(); - private final Vector projects = new Vector(); - private boolean projectsOnly = false; - - - /** - * If true, stop build on compile failure. - */ - protected boolean failOnError = true; - - /** - * Content that appears in and also in are maintained by a - * captive CompilerDef instance - */ - private final CompilerDef compilerDef = new CompilerDef(); - /** The OS390 dataset to build to object to */ - private String dataset; - /** - * - * Depth of dependency checking - * - * Values < 0 indicate full dependency checking Values >= 0 indicate - * partial dependency checking and for superficial compilation checks. Will - * throw BuildException before attempting link - */ - private int dependencyDepth = -1; - /** - * Content that appears in and also in are maintained by a - * captive CompilerDef instance - */ - private final LinkerDef linkerDef = new LinkerDef(); - /** - * contains the subsystem, output type and - * - */ - private final LinkType linkType = new LinkType(); - /** - * The property name which will be set with the physical filename of the - * file that is generated by the linker - */ - private String outputFileProperty; - /** - * if relentless = true, compilations should attempt to compile as many - * files as possible before throwing a BuildException - */ - private boolean relentless; - public CCTask() { - } - /** - * Adds a compiler definition or reference. - * - * @param compiler - * compiler - * @throws NullPointerException - * if compiler is null - */ - public void addConfiguredCompiler(CompilerDef compiler) { - if (compiler == null) { - throw new NullPointerException("compiler"); - } - compiler.setProject(getProject()); - _compilers.addElement(compiler); - } - /** - * Adds a compiler command-line arg. Argument will be inherited by all - * nested compiler elements that do not have inherit="false". - * - */ - public void addConfiguredCompilerArg(CompilerArgument arg) { - compilerDef.addConfiguredCompilerArg(arg); - } - /** - * Adds a defineset. Will be inherited by all compiler elements that do not - * have inherit="false". - * - * @param defs - * Define set - */ - public void addConfiguredDefineset(DefineSet defs) { - compilerDef.addConfiguredDefineset(defs); - } - /** - * Adds a linker definition. The first linker that is not disqualified by - * its "if" and "unless" attributes will perform the link. If no child - * linker element is active, the linker implied by the cc elements name or - * classname attribute will be used. - * - * @param linker - * linker - * @throws NullPointerException - * if linker is null - */ - public void addConfiguredLinker(LinkerDef linker) { - if (linker == null) { - throw new NullPointerException("linker"); - } - linker.setProject(getProject()); - _linkers.addElement(linker); - } - /** - * Adds a linker command-line arg. Argument will be inherited by all nested - * linker elements that do not have inherit="false". - */ - public void addConfiguredLinkerArg(LinkerArgument arg) { - linkerDef.addConfiguredLinkerArg(arg); - } - /** - * Add an environment variable to the launched process. - */ - public void addEnv(Environment.Variable var) { - compilerDef.addEnv(var); - linkerDef.addEnv(var); - } - /** - * Adds a source file set. - * - * Files in these filesets will be auctioned to the available compiler - * configurations, with the default compiler implied by the cc element - * bidding last. If no compiler is interested in the file, it will be - * passed to the linker. - * - * To have a file be processed by a particular compiler configuration, add - * a fileset to the corresponding compiler element. - */ - public void addFileset(ConditionalFileSet srcSet) { - compilerDef.addFileset(srcSet); - } - /** - * Adds a library set. - * - * Library sets will be inherited by all linker elements that do not have - * inherit="false". - * - * @param libset - * library set - * @throws NullPointerException - * if libset is null. - */ - public void addLibset(LibrarySet libset) { - if (libset == null) { - throw new NullPointerException("libset"); - } - linkerDef.addLibset(libset); - } - /** - * Adds a system library set. Timestamps and locations of system library - * sets are not used in dependency analysis. - * - * Essential libraries (such as C Runtime libraries) should not be - * specified since the task will attempt to identify the correct libraries - * based on the multithread, debug and runtime attributes. - * - * System library sets will be inherited by all linker elements that do not - * have inherit="false". - * - * @param libset - * library set - * @throws NullPointerException - * if libset is null. - */ - public void addSyslibset(SystemLibrarySet libset) { - if (libset == null) { - throw new NullPointerException("libset"); - } - linkerDef.addSyslibset(libset); - } - /** - * Specifies the generation of IDE project file. Experimental. - * @param projectDef project file generation specification - */ - public void addProject(final ProjectDef projectDef) { - if (projectDef == null) { - throw new NullPointerException("projectDef"); - } - projects.addElement(projectDef); - } - public void setProjectsOnly(final boolean value) { - projectsOnly = value; - } - /** - * Checks all targets that are not forced to be rebuilt or are missing - * object files to be checked for modified include files - * - * @returns total number of targets to be rebuilt - * - */ - protected int checkForChangedIncludeFiles(Hashtable targets) { - int potentialTargets = 0; - int definiteTargets = 0; - Enumeration targetEnum = targets.elements(); - while (targetEnum.hasMoreElements()) { - TargetInfo target = (TargetInfo) targetEnum.nextElement(); - if (!target.getRebuild()) { - potentialTargets++; - } else { - definiteTargets++; - } - } - // - // If there were remaining targets that - // might be out of date - // - if (potentialTargets > 0) { - log("Starting dependency analysis for " - + Integer.toString(potentialTargets) + " files."); - DependencyTable dependencyTable = new DependencyTable(_objDir); - try { - dependencyTable.load(); - } catch (Exception ex) { - log("Problem reading dependencies.xml: " + ex.toString()); - } - targetEnum = targets.elements(); - while (targetEnum.hasMoreElements()) { - TargetInfo target = (TargetInfo) targetEnum.nextElement(); - if (!target.getRebuild()) { - if (dependencyTable.needsRebuild(this, target, - dependencyDepth)) { - target.mustRebuild(); - } - } - } - dependencyTable.commit(this); - } - // - // count files being rebuilt now - // - int currentTargets = 0; - targetEnum = targets.elements(); - while (targetEnum.hasMoreElements()) { - TargetInfo target = (TargetInfo) targetEnum.nextElement(); - if (target.getRebuild()) { - currentTargets++; - } - } - if (potentialTargets > 0) { - log(Integer.toString(potentialTargets - currentTargets - + definiteTargets) - + " files are up to date."); - log(Integer.toString(currentTargets - definiteTargets) - + " files to be recompiled from dependency analysis."); - } - log(Integer.toString(currentTargets) + " total files to be compiled."); - return currentTargets; - } - protected LinkerConfiguration collectExplicitObjectFiles( - Vector objectFiles, Vector sysObjectFiles, VersionInfo versionInfo) { - // - // find the first eligible linker - // - // - ProcessorConfiguration linkerConfig = null; - LinkerDef selectedLinkerDef = null; - Linker selectedLinker = null; - Hashtable sysLibraries = new Hashtable(); - TargetDef targetPlatform = getTargetPlatform(); - FileVisitor objCollector = null; - FileVisitor sysLibraryCollector = null; - for (int i = 0; i < _linkers.size(); i++) { - LinkerDef currentLinkerDef = (LinkerDef) _linkers.elementAt(i); - if (currentLinkerDef.isActive()) { - selectedLinkerDef = currentLinkerDef; - selectedLinker = currentLinkerDef.getProcessor().getLinker( - linkType); - // - // skip the linker if it doesn't know how to - // produce the specified link type - if (selectedLinker != null) { - linkerConfig = currentLinkerDef.createConfiguration(this, - linkType, linkerDef, targetPlatform, versionInfo); - if (linkerConfig != null) { - // - // create collectors for object files - // and system libraries - objCollector = new ObjectFileCollector(selectedLinker, - objectFiles); - sysLibraryCollector = new SystemLibraryCollector( - selectedLinker, sysLibraries); - // - // if the has embedded 's - // (such as linker specific libraries) - // add them as object files. - // - if (currentLinkerDef.hasFileSets()) { - currentLinkerDef.visitFiles(objCollector); - } - // - // user libraries are just a specialized form - // of an object fileset - selectedLinkerDef.visitUserLibraries(selectedLinker, - objCollector); - } - break; - } - } - } - if (linkerConfig == null) { - linkerConfig = linkerDef.createConfiguration(this, linkType, null, targetPlatform, versionInfo); - selectedLinker = (Linker) linkerDef.getProcessor().getLinker( - linkType); - objCollector = new ObjectFileCollector(selectedLinker, objectFiles); - sysLibraryCollector = new SystemLibraryCollector(selectedLinker, - sysLibraries); - } - // - // unless there was a element that - // explicitly did not inherit files from - // containing element - if (selectedLinkerDef == null || selectedLinkerDef.getInherit()) { - linkerDef.visitUserLibraries(selectedLinker, objCollector); - linkerDef.visitSystemLibraries(selectedLinker, sysLibraryCollector); - } - // - // if there was a in a nested - // evaluate it last so it takes priority over - // identically named libs from element - // - if (selectedLinkerDef != null) { - // - // add any system libraries to the hashtable - // done in reverse order so the earliest - // on the classpath takes priority - selectedLinkerDef.visitSystemLibraries(selectedLinker, - sysLibraryCollector); - } - // - // copy over any system libraries to the - // object files vector - // - Enumeration sysLibEnum = sysLibraries.elements(); - while (sysLibEnum.hasMoreElements()) { - sysObjectFiles.addElement(sysLibEnum.nextElement()); - } - return (LinkerConfiguration) linkerConfig; - } - /** - * Adds an include path. - * - * Include paths will be inherited by nested compiler elements that do not - * have inherit="false". - */ - public IncludePath createIncludePath() { - return compilerDef.createIncludePath(); - } - /** - * Specifies precompilation prototype file and exclusions. Inherited by all - * compilers that do not have inherit="false". - * - */ - public PrecompileDef createPrecompile() throws BuildException { - return compilerDef.createPrecompile(); - } - /** - * Adds a system include path. Locations and timestamps of files located - * using the system include paths are not used in dependency analysis. - * - * - * Standard include locations should not be specified. The compiler - * adapters should recognized the settings from the appropriate environment - * variables or configuration files. - * - * System include paths will be inherited by nested compiler elements that - * do not have inherit="false". - */ - public SystemIncludePath createSysIncludePath() { - return compilerDef.createSysIncludePath(); - } - /** - * Executes the task. Compiles the given files. - * - * @throws BuildException - * if someting goes wrong with the build - */ - public void execute() throws BuildException { - // - // if link type allowed objdir to be defaulted - // provide it from outfile - if (_objDir == null) { - if(_outfile != null) { - _objDir = new File(_outfile.getParent()); - } else { - _objDir = new File("."); - } - } - - // - // if the object directory does not exist - // - if (!_objDir.exists()) { - throw new BuildException("Object directory does not exist"); - } - TargetHistoryTable objHistory = new TargetHistoryTable(this, _objDir); - - // - // get the first active version info - // - VersionInfo versionInfo = null; - Enumeration versionEnum = versionInfos.elements(); - while (versionEnum.hasMoreElements()) { - versionInfo = (VersionInfo) versionEnum.nextElement(); - versionInfo = versionInfo.merge(); - if (versionInfo.isActive()) { - break; - } else { - versionInfo = null; - } - } - - - // - // determine the eventual linker configuration - // (may be null) and collect any explicit - // object files or libraries - Vector objectFiles = new Vector(); - Vector sysObjectFiles = new Vector(); - LinkerConfiguration linkerConfig = collectExplicitObjectFiles( - objectFiles, sysObjectFiles, versionInfo); - - - // - // Assemble hashtable of all files - // that we know how to compile (keyed by output file name) - // - Hashtable targets = getTargets(linkerConfig, objectFiles, versionInfo, _outfile); - TargetInfo linkTarget = null; - // - // if output file is not specified, - // then skip link step - // - if (_outfile != null) { - linkTarget = getLinkTarget(linkerConfig, objectFiles, - sysObjectFiles, targets, versionInfo); - } - - if (projects.size() > 0) { - ArrayList files = new ArrayList(); - ProjectFileCollector matcher = new ProjectFileCollector(files); - for (int i = 0; i < _compilers.size(); i++) { - CompilerDef currentCompilerDef = (CompilerDef) _compilers - .elementAt(i); - if (currentCompilerDef.isActive()) { - if (currentCompilerDef.hasFileSets()) { - currentCompilerDef.visitFiles(matcher); - } - } - } - compilerDef.visitFiles(matcher); - - - Enumeration iter = projects.elements(); - while (iter.hasMoreElements()) { - ProjectDef projectDef = (ProjectDef) iter.nextElement(); - if (projectDef.isActive()) { - projectDef.execute(this, files, targets, linkTarget); - } - } - } - if (projectsOnly) return; - - - - // - // mark targets that don't have a history record or - // whose source last modification time is not - // the same as the history to be rebuilt - // - objHistory.markForRebuild(targets); - CCTaskProgressMonitor monitor = new CCTaskProgressMonitor(objHistory, versionInfo); - // - // check for changed include files - // - int rebuildCount = checkForChangedIncludeFiles(targets); - if (rebuildCount > 0) { - BuildException compileException = null; - // - // compile all targets with getRebuild() == true - // - Hashtable targetsByConfig = getTargetsToBuildByConfiguration(targets); - // - // build array containing Vectors with precompiled generation - // steps going first - // - Vector[] targetVectors = new Vector[targetsByConfig.size()]; - int index = 0; - Enumeration targetVectorEnum = targetsByConfig.elements(); - while (targetVectorEnum.hasMoreElements()) { - Vector targetsForConfig = (Vector) targetVectorEnum - .nextElement(); - // - // get the configuration from the first entry - // - CompilerConfiguration config = (CompilerConfiguration) ((TargetInfo) targetsForConfig - .elementAt(0)).getConfiguration(); - if (config.isPrecompileGeneration()) { - targetVectors[index++] = targetsForConfig; - } - } - targetVectorEnum = targetsByConfig.elements(); - while (targetVectorEnum.hasMoreElements()) { - Vector targetsForConfig = (Vector) targetVectorEnum - .nextElement(); - for (int i = 0; i < targetVectors.length; i++) { - if (targetVectors[i] == targetsForConfig) { - break; - } - if (targetVectors[i] == null) { - targetVectors[i] = targetsForConfig; - break; - } - } - } - -// BEGINFREEHEP - Progress progress = new Progress(getObjdir(), rebuildCount); - progress.start(); - - for (int i = 0; i < targetVectors.length; i++) { - // - // get the targets for this configuration - // - Vector targetsForConfig = targetVectors[i]; - // - // get the configuration from the first entry - // - CompilerConfiguration config = (CompilerConfiguration) ((TargetInfo) targetsForConfig - .elementAt(0)).getConfiguration(); - // - // prepare the list of source files - // - String[] sourceFiles = new String[targetsForConfig.size()]; - Enumeration targetsEnum = targetsForConfig.elements(); - index = 0; - while (targetsEnum.hasMoreElements()) { - TargetInfo targetInfo = ((TargetInfo) targetsEnum - .nextElement()); - sourceFiles[index++] = targetInfo.getSources()[0] - .toString(); - } - try { - config.compile(this, _objDir, sourceFiles, relentless, - monitor); - } catch (BuildException ex) { - if (compileException == null) { - compileException = ex; - } - if (!relentless) - break; - } - } - -// BEGINFREEHEP - progress.exit(); - try { - progress.join(); - } catch (InterruptedException e) { - } -// ENDFREEHEP - - // - // save the details of the object file compilation - // settings to disk for dependency analysis - // - try { - objHistory.commit(); - } catch (IOException ex) { - this.log("Error writing history.xml: " + ex.toString()); - } - // - // if we threw a compile exception and - // didn't throw it at the time because - // we were relentless then - // save the history and - // throw the exception - // - if (compileException != null) { - if (failOnError) { - throw compileException; - } else { - log(compileException.getMessage(), Project.MSG_ERR); - return; - } - } - } - // - // if the dependency tree was not fully - // evaluated, then throw an exception - // since we really didn't do what we - // should have done - // - // - if (dependencyDepth >= 0) { - throw new BuildException( - "All files at depth " - + Integer.toString(dependencyDepth) - + " from changes successfully compiled.\n" - + "Remove or change dependencyDepth to -1 to perform full compilation."); - } - // - // if no link target then - // commit the history for the object files - // and leave the task - if (linkTarget != null) { - // - // get the history for the link target (may be the same - // as the object history) - TargetHistoryTable linkHistory = getLinkHistory(objHistory); - // - // see if it needs to be rebuilt - // - linkHistory.markForRebuild(linkTarget); - // - // if it needs to be rebuilt, rebuild it - // - File output = linkTarget.getOutput(); - if (linkTarget.getRebuild()) { - LinkerConfiguration linkConfig = (LinkerConfiguration) linkTarget - .getConfiguration(); -// BEGINFREEHEP - log("Linking..."); - log("Starting link {"+linkConfig.getIdentifier()+"}"); -// ENDFREEHEP - if (failOnError) { - linkConfig.link(this, linkTarget); - } else { - try { - linkConfig.link(this, linkTarget); - } catch(BuildException ex) { - log(ex.getMessage(), Project.MSG_ERR); - return; - } - } - if (outputFileProperty != null) - getProject().setProperty(outputFileProperty, - output.getAbsolutePath()); - linkHistory.update(linkTarget); - try { - linkHistory.commit(); - } catch (IOException ex) { - log("Error writing link history.xml: " + ex.toString()); - } - } else { - if (outputFileProperty != null) - getProject().setProperty(outputFileProperty, - output.getAbsolutePath()); - } - } - } -// BEGINFREEHEP + private static class SystemLibraryCollector implements FileVisitor { + private Hashtable libraries; + private Linker linker; + + public SystemLibraryCollector(Linker linker, Hashtable libraries) { + this.linker = linker; + this.libraries = libraries; + } + + public void visit(File basedir, String filename) { + if (linker.bid(filename) > 0) { + File libfile = new File(basedir, filename); + String key = linker.getLibraryKey(libfile); + libraries.put(key, libfile); + } + } + } + + private static class ProjectFileCollector implements FileVisitor { + private final List files; + + /** + * Creates a new ProjectFileCollector. + * + * @param files + * vector for collected files. + */ + public ProjectFileCollector(List files) { + this.files = files; + } + + /** + * Called for each file to be considered for collection. + * + * @param parentDir + * parent directory + * @param filename + * filename within directory + */ + public void visit(File parentDir, String filename) { + files.add(new File(parentDir, filename)); + } + } + + private static final ProcessorConfiguration[] EMPTY_CONFIG_ARRAY = new ProcessorConfiguration[0]; + + /** + * Builds a Hashtable to targets needing to be rebuilt keyed by compiler + * configuration + */ + public static Hashtable getTargetsToBuildByConfiguration(Hashtable targets) { + Hashtable targetsByConfig = new Hashtable(); + Enumeration targetEnum = targets.elements(); + while (targetEnum.hasMoreElements()) { + TargetInfo target = (TargetInfo) targetEnum.nextElement(); + if (target.getRebuild()) { + Vector targetsForSameConfig = (Vector) targetsByConfig + .get(target.getConfiguration()); + if (targetsForSameConfig != null) { + targetsForSameConfig.addElement(target); + } else { + targetsForSameConfig = new Vector(); + targetsForSameConfig.addElement(target); + targetsByConfig.put(target.getConfiguration(), + targetsForSameConfig); + } + } + } + return targetsByConfig; + } + + /** The compiler definitions. */ + private Vector _compilers = new Vector(); + /** The output file type. */ + // private LinkType _linkType = LinkType.EXECUTABLE; + /** The library sets. */ + private Vector _libsets = new Vector(); + /** The linker definitions. */ + private Vector _linkers = new Vector(); + /** The object directory. */ + private File _objDir; + /** The output file. */ + private File _outfile; + /** The linker definitions. */ + private final Vector targetPlatforms = new Vector(); + /** The distributer definitions. */ + private Vector distributers = new Vector(); + private final Vector versionInfos = new Vector(); + private final Vector projects = new Vector(); + private boolean projectsOnly = false; + + /** + * If true, stop build on compile failure. + */ + protected boolean failOnError = true; + + /** + * Content that appears in and also in are maintained by a + * captive CompilerDef instance + */ + private final CompilerDef compilerDef = new CompilerDef(); + /** The OS390 dataset to build to object to */ + private String dataset; + /** + * + * Depth of dependency checking + * + * Values < 0 indicate full dependency checking Values >= 0 indicate partial + * dependency checking and for superficial compilation checks. Will throw + * BuildException before attempting link + */ + private int dependencyDepth = -1; + /** + * Content that appears in and also in are maintained by a + * captive CompilerDef instance + */ + private final LinkerDef linkerDef = new LinkerDef(); + /** + * contains the subsystem, output type and + * + */ + private final LinkType linkType = new LinkType(); + /** + * The property name which will be set with the physical filename of the + * file that is generated by the linker + */ + private String outputFileProperty; + /** + * if relentless = true, compilations should attempt to compile as many + * files as possible before throwing a BuildException + */ + private boolean relentless; + + public CCTask() { + } + + /** + * Adds a compiler definition or reference. + * + * @param compiler + * compiler + * @throws NullPointerException + * if compiler is null + */ + public void addConfiguredCompiler(CompilerDef compiler) { + if (compiler == null) { + throw new NullPointerException("compiler"); + } + compiler.setProject(getProject()); + _compilers.addElement(compiler); + } + + /** + * Adds a compiler command-line arg. Argument will be inherited by all + * nested compiler elements that do not have inherit="false". + * + */ + public void addConfiguredCompilerArg(CompilerArgument arg) { + compilerDef.addConfiguredCompilerArg(arg); + } + + /** + * Adds a defineset. Will be inherited by all compiler elements that do not + * have inherit="false". + * + * @param defs + * Define set + */ + public void addConfiguredDefineset(DefineSet defs) { + compilerDef.addConfiguredDefineset(defs); + } + + /** + * Adds a linker definition. The first linker that is not disqualified by + * its "if" and "unless" attributes will perform the link. If no child + * linker element is active, the linker implied by the cc elements name or + * classname attribute will be used. + * + * @param linker + * linker + * @throws NullPointerException + * if linker is null + */ + public void addConfiguredLinker(LinkerDef linker) { + if (linker == null) { + throw new NullPointerException("linker"); + } + linker.setProject(getProject()); + _linkers.addElement(linker); + } + + /** + * Adds a linker command-line arg. Argument will be inherited by all nested + * linker elements that do not have inherit="false". + */ + public void addConfiguredLinkerArg(LinkerArgument arg) { + linkerDef.addConfiguredLinkerArg(arg); + } + + /** + * Add an environment variable to the launched process. + */ + public void addEnv(Environment.Variable var) { + compilerDef.addEnv(var); + linkerDef.addEnv(var); + } + + /** + * Adds a source file set. + * + * Files in these filesets will be auctioned to the available compiler + * configurations, with the default compiler implied by the cc element + * bidding last. If no compiler is interested in the file, it will be passed + * to the linker. + * + * To have a file be processed by a particular compiler configuration, add a + * fileset to the corresponding compiler element. + */ + public void addFileset(ConditionalFileSet srcSet) { + compilerDef.addFileset(srcSet); + } + + /** + * Adds a library set. + * + * Library sets will be inherited by all linker elements that do not have + * inherit="false". + * + * @param libset + * library set + * @throws NullPointerException + * if libset is null. + */ + public void addLibset(LibrarySet libset) { + if (libset == null) { + throw new NullPointerException("libset"); + } + linkerDef.addLibset(libset); + } + + /** + * Adds a system library set. Timestamps and locations of system library + * sets are not used in dependency analysis. + * + * Essential libraries (such as C Runtime libraries) should not be specified + * since the task will attempt to identify the correct libraries based on + * the multithread, debug and runtime attributes. + * + * System library sets will be inherited by all linker elements that do not + * have inherit="false". + * + * @param libset + * library set + * @throws NullPointerException + * if libset is null. + */ + public void addSyslibset(SystemLibrarySet libset) { + if (libset == null) { + throw new NullPointerException("libset"); + } + linkerDef.addSyslibset(libset); + } + + /** + * Specifies the generation of IDE project file. Experimental. + * + * @param projectDef + * project file generation specification + */ + public void addProject(final ProjectDef projectDef) { + if (projectDef == null) { + throw new NullPointerException("projectDef"); + } + projects.addElement(projectDef); + } + + public void setProjectsOnly(final boolean value) { + projectsOnly = value; + } + + /** + * Checks all targets that are not forced to be rebuilt or are missing + * object files to be checked for modified include files + * + * @returns total number of targets to be rebuilt + * + */ + protected int checkForChangedIncludeFiles(Hashtable targets) { + int potentialTargets = 0; + int definiteTargets = 0; + Enumeration targetEnum = targets.elements(); + while (targetEnum.hasMoreElements()) { + TargetInfo target = (TargetInfo) targetEnum.nextElement(); + if (!target.getRebuild()) { + potentialTargets++; + } else { + definiteTargets++; + } + } + // + // If there were remaining targets that + // might be out of date + // + if (potentialTargets > 0) { + log("Starting dependency analysis for " + + Integer.toString(potentialTargets) + " files."); + DependencyTable dependencyTable = new DependencyTable(_objDir); + try { + dependencyTable.load(); + } catch (Exception ex) { + log("Problem reading dependencies.xml: " + ex.toString()); + } + targetEnum = targets.elements(); + while (targetEnum.hasMoreElements()) { + TargetInfo target = (TargetInfo) targetEnum.nextElement(); + if (!target.getRebuild()) { + if (dependencyTable.needsRebuild(this, target, + dependencyDepth)) { + target.mustRebuild(); + } + } + } + dependencyTable.commit(this); + } + // + // count files being rebuilt now + // + int currentTargets = 0; + targetEnum = targets.elements(); + while (targetEnum.hasMoreElements()) { + TargetInfo target = (TargetInfo) targetEnum.nextElement(); + if (target.getRebuild()) { + currentTargets++; + } + } + if (potentialTargets > 0) { + log(Integer.toString(potentialTargets - currentTargets + + definiteTargets) + + " files are up to date."); + log(Integer.toString(currentTargets - definiteTargets) + + " files to be recompiled from dependency analysis."); + } + log(Integer.toString(currentTargets) + " total files to be compiled."); + return currentTargets; + } + + protected LinkerConfiguration collectExplicitObjectFiles( + Vector objectFiles, Vector sysObjectFiles, VersionInfo versionInfo) { + // + // find the first eligible linker + // + // + ProcessorConfiguration linkerConfig = null; + LinkerDef selectedLinkerDef = null; + Linker selectedLinker = null; + Hashtable sysLibraries = new Hashtable(); + TargetDef targetPlatform = getTargetPlatform(); + FileVisitor objCollector = null; + FileVisitor sysLibraryCollector = null; + for (int i = 0; i < _linkers.size(); i++) { + LinkerDef currentLinkerDef = (LinkerDef) _linkers.elementAt(i); + if (currentLinkerDef.isActive()) { + selectedLinkerDef = currentLinkerDef; + selectedLinker = currentLinkerDef.getProcessor().getLinker( + linkType); + // + // skip the linker if it doesn't know how to + // produce the specified link type + if (selectedLinker != null) { + linkerConfig = currentLinkerDef.createConfiguration(this, + linkType, linkerDef, targetPlatform, versionInfo); + if (linkerConfig != null) { + // + // create collectors for object files + // and system libraries + objCollector = new ObjectFileCollector(selectedLinker, + objectFiles); + sysLibraryCollector = new SystemLibraryCollector( + selectedLinker, sysLibraries); + // + // if the has embedded 's + // (such as linker specific libraries) + // add them as object files. + // + if (currentLinkerDef.hasFileSets()) { + currentLinkerDef.visitFiles(objCollector); + } + // + // user libraries are just a specialized form + // of an object fileset + selectedLinkerDef.visitUserLibraries(selectedLinker, + objCollector); + } + break; + } + } + } + if (linkerConfig == null) { + linkerConfig = linkerDef.createConfiguration(this, linkType, null, + targetPlatform, versionInfo); + selectedLinker = (Linker) linkerDef.getProcessor().getLinker( + linkType); + objCollector = new ObjectFileCollector(selectedLinker, objectFiles); + sysLibraryCollector = new SystemLibraryCollector(selectedLinker, + sysLibraries); + } + // + // unless there was a element that + // explicitly did not inherit files from + // containing element + if (selectedLinkerDef == null || selectedLinkerDef.getInherit()) { + linkerDef.visitUserLibraries(selectedLinker, objCollector); + linkerDef.visitSystemLibraries(selectedLinker, sysLibraryCollector); + } + // + // if there was a in a nested + // evaluate it last so it takes priority over + // identically named libs from element + // + if (selectedLinkerDef != null) { + // + // add any system libraries to the hashtable + // done in reverse order so the earliest + // on the classpath takes priority + selectedLinkerDef.visitSystemLibraries(selectedLinker, + sysLibraryCollector); + } + // + // copy over any system libraries to the + // object files vector + // + Enumeration sysLibEnum = sysLibraries.elements(); + while (sysLibEnum.hasMoreElements()) { + sysObjectFiles.addElement(sysLibEnum.nextElement()); + } + return (LinkerConfiguration) linkerConfig; + } + + /** + * Adds an include path. + * + * Include paths will be inherited by nested compiler elements that do not + * have inherit="false". + */ + public IncludePath createIncludePath() { + return compilerDef.createIncludePath(); + } + + /** + * Specifies precompilation prototype file and exclusions. Inherited by all + * compilers that do not have inherit="false". + * + */ + public PrecompileDef createPrecompile() throws BuildException { + return compilerDef.createPrecompile(); + } + + /** + * Adds a system include path. Locations and timestamps of files located + * using the system include paths are not used in dependency analysis. + * + * + * Standard include locations should not be specified. The compiler adapters + * should recognized the settings from the appropriate environment variables + * or configuration files. + * + * System include paths will be inherited by nested compiler elements that + * do not have inherit="false". + */ + public SystemIncludePath createSysIncludePath() { + return compilerDef.createSysIncludePath(); + } + + /** + * Executes the task. Compiles the given files. + * + * @throws BuildException + * if someting goes wrong with the build + */ + public void execute() throws BuildException { + // + // if link type allowed objdir to be defaulted + // provide it from outfile + if (_objDir == null) { + if (_outfile != null) { + _objDir = new File(_outfile.getParent()); + } else { + _objDir = new File("."); + } + } + + // + // if the object directory does not exist + // + if (!_objDir.exists()) { + throw new BuildException("Object directory does not exist"); + } + TargetHistoryTable objHistory = new TargetHistoryTable(this, _objDir); + + // + // get the first active version info + // + VersionInfo versionInfo = null; + Enumeration versionEnum = versionInfos.elements(); + while (versionEnum.hasMoreElements()) { + versionInfo = (VersionInfo) versionEnum.nextElement(); + versionInfo = versionInfo.merge(); + if (versionInfo.isActive()) { + break; + } else { + versionInfo = null; + } + } + + // + // determine the eventual linker configuration + // (may be null) and collect any explicit + // object files or libraries + Vector objectFiles = new Vector(); + Vector sysObjectFiles = new Vector(); + LinkerConfiguration linkerConfig = collectExplicitObjectFiles( + objectFiles, sysObjectFiles, versionInfo); + + // + // Assemble hashtable of all files + // that we know how to compile (keyed by output file name) + // + Hashtable targets = getTargets(linkerConfig, objectFiles, versionInfo, + _outfile); + TargetInfo linkTarget = null; + // + // if output file is not specified, + // then skip link step + // + if (_outfile != null) { + linkTarget = getLinkTarget(linkerConfig, objectFiles, + sysObjectFiles, targets, versionInfo); + } + + if (projects.size() > 0) { + ArrayList files = new ArrayList(); + ProjectFileCollector matcher = new ProjectFileCollector(files); + for (int i = 0; i < _compilers.size(); i++) { + CompilerDef currentCompilerDef = (CompilerDef) _compilers + .elementAt(i); + if (currentCompilerDef.isActive()) { + if (currentCompilerDef.hasFileSets()) { + currentCompilerDef.visitFiles(matcher); + } + } + } + compilerDef.visitFiles(matcher); + + Enumeration iter = projects.elements(); + while (iter.hasMoreElements()) { + ProjectDef projectDef = (ProjectDef) iter.nextElement(); + if (projectDef.isActive()) { + projectDef.execute(this, files, targets, linkTarget); + } + } + } + if (projectsOnly) + return; + + // + // mark targets that don't have a history record or + // whose source last modification time is not + // the same as the history to be rebuilt + // + objHistory.markForRebuild(targets); + CCTaskProgressMonitor monitor = new CCTaskProgressMonitor(objHistory, + versionInfo); + // + // check for changed include files + // + int rebuildCount = checkForChangedIncludeFiles(targets); + if (rebuildCount > 0) { + BuildException compileException = null; + // + // compile all targets with getRebuild() == true + // + Hashtable targetsByConfig = getTargetsToBuildByConfiguration(targets); + // + // build array containing Vectors with precompiled generation + // steps going first + // + Vector[] targetVectors = new Vector[targetsByConfig.size()]; + int index = 0; + Enumeration targetVectorEnum = targetsByConfig.elements(); + while (targetVectorEnum.hasMoreElements()) { + Vector targetsForConfig = (Vector) targetVectorEnum + .nextElement(); + // + // get the configuration from the first entry + // + CompilerConfiguration config = (CompilerConfiguration) ((TargetInfo) targetsForConfig + .elementAt(0)).getConfiguration(); + if (config.isPrecompileGeneration()) { + targetVectors[index++] = targetsForConfig; + } + } + targetVectorEnum = targetsByConfig.elements(); + while (targetVectorEnum.hasMoreElements()) { + Vector targetsForConfig = (Vector) targetVectorEnum + .nextElement(); + for (int i = 0; i < targetVectors.length; i++) { + if (targetVectors[i] == targetsForConfig) { + break; + } + if (targetVectors[i] == null) { + targetVectors[i] = targetsForConfig; + break; + } + } + } + + // BEGINFREEHEP + Progress progress = new Progress(getObjdir(), rebuildCount); + progress.start(); + + for (int i = 0; i < targetVectors.length; i++) { + // + // get the targets for this configuration + // + Vector targetsForConfig = targetVectors[i]; + // + // get the configuration from the first entry + // + CompilerConfiguration config = (CompilerConfiguration) ((TargetInfo) targetsForConfig + .elementAt(0)).getConfiguration(); + // + // prepare the list of source files + // + + // BEGINFREEHEP + int noOfCores = Runtime.getRuntime().availableProcessors(); + int noOfFiles = targetsForConfig.size(); + if (noOfFiles < noOfCores) noOfCores = targetsForConfig.size(); + + Set[] sourceFiles = new HashSet[noOfCores]; + for (int j=0; j= 0) { + throw new BuildException( + "All files at depth " + + Integer.toString(dependencyDepth) + + " from changes successfully compiled.\n" + + "Remove or change dependencyDepth to -1 to perform full compilation."); + } + // + // if no link target then + // commit the history for the object files + // and leave the task + if (linkTarget != null) { + // + // get the history for the link target (may be the same + // as the object history) + TargetHistoryTable linkHistory = getLinkHistory(objHistory); + // + // see if it needs to be rebuilt + // + linkHistory.markForRebuild(linkTarget); + // + // if it needs to be rebuilt, rebuild it + // + File output = linkTarget.getOutput(); + if (linkTarget.getRebuild()) { + LinkerConfiguration linkConfig = (LinkerConfiguration) linkTarget + .getConfiguration(); + // BEGINFREEHEP + log("Linking..."); + log("Starting link {" + linkConfig.getIdentifier() + "}"); + // ENDFREEHEP + if (failOnError) { + linkConfig.link(this, linkTarget); + } else { + try { + linkConfig.link(this, linkTarget); + } catch (BuildException ex) { + log(ex.getMessage(), Project.MSG_ERR); + return; + } + } + if (outputFileProperty != null) + getProject().setProperty(outputFileProperty, + output.getAbsolutePath()); + linkHistory.update(linkTarget); + try { + linkHistory.commit(); + } catch (IOException ex) { + log("Error writing link history.xml: " + ex.toString()); + } + } else { + if (outputFileProperty != null) + getProject().setProperty(outputFileProperty, + output.getAbsolutePath()); + } + } + } + + // BEGINFREEHEP + class Core extends Thread { + private CompilerConfiguration config; + private File objDir; + private Set sourceFiles; + private boolean relentless; + private CCTaskProgressMonitor monitor; + private Exception compileException; + private CCTask task; + + Core(CCTask task, CompilerConfiguration config, File objDir, + Set set, boolean relentless, + CCTaskProgressMonitor monitor) { + this.task = task; + this.config = config; + this.objDir = objDir; + this.sourceFiles = set; + this.relentless = relentless; + this.monitor = monitor; + } + + public Exception getException() { + return compileException; + } + + public void run() { + super.run(); + try { + String[] sources = new String[sourceFiles.size()]; + sources = (String[])sourceFiles.toArray(sources); + config.compile(task, objDir, sources, relentless, monitor); + } catch (Exception ex) { + if (compileException == null) { + compileException = ex; + } + } + } + } + + // ENDFREEHEP + + // BEGINFREEHEP class Progress extends Thread { - + private boolean stop = false; private File objDir; private int rebuildCount; - + public Progress(File objDir, int rebuildCount) { this.objDir = objDir; this.rebuildCount = rebuildCount; } - + public void run() { - if (rebuildCount < 10) return; + if (rebuildCount < 10) + return; try { FileFilter updatedFiles = new FileFilter() { private long startTime = System.currentTimeMillis(); - + public boolean accept(File file) { - return file.lastModified() > startTime && !file.getName().endsWith(".xml"); + return file.lastModified() > startTime + && !file.getName().endsWith(".xml"); } }; while (!stop) { - System.err.print("\r"+objDir.listFiles(updatedFiles).length+" / "+rebuildCount+" files compiled..."); + System.err.print("\r" + + objDir.listFiles(updatedFiles).length + " / " + + rebuildCount + " files compiled..."); System.err.flush(); Thread.sleep(5000); } } catch (InterruptedException e) { } - System.err.print("\r "); + System.err + .print("\r "); System.err.print("\r"); - log(Integer.toString(rebuildCount) + " files were compiled."); System.err.flush(); + log(Integer.toString(rebuildCount) + " files were compiled."); } - + public void exit() { stop = true; } - - } -// ENDFREEHEP - - /** - * Gets the dataset. - * - * @return Returns a String - */ - public String getDataset() { - return dataset; - } - protected TargetHistoryTable getLinkHistory(TargetHistoryTable objHistory) { - File outputFileDir = new File(_outfile.getParent()); - // - // if the output file is being produced in the link - // directory, then we can use the same history file - // - if (_objDir.equals(outputFileDir)) { - return objHistory; - } - return new TargetHistoryTable(this, outputFileDir); - } - protected TargetInfo getLinkTarget(LinkerConfiguration linkerConfig, - Vector objectFiles, Vector sysObjectFiles, + + } + + // ENDFREEHEP + + /** + * Gets the dataset. + * + * @return Returns a String + */ + public String getDataset() { + return dataset; + } + + protected TargetHistoryTable getLinkHistory(TargetHistoryTable objHistory) { + File outputFileDir = new File(_outfile.getParent()); + // + // if the output file is being produced in the link + // directory, then we can use the same history file + // + if (_objDir.equals(outputFileDir)) { + return objHistory; + } + return new TargetHistoryTable(this, outputFileDir); + } + + protected TargetInfo getLinkTarget(LinkerConfiguration linkerConfig, + Vector objectFiles, Vector sysObjectFiles, Hashtable compileTargets, VersionInfo versionInfo) { - // - // walk the compile phase targets and - // add those sources that have already been - // assigned to the linker or - // our output files the linker knows how to consume - // files the linker knows how to consume - // - Enumeration compileTargetsEnum = compileTargets.elements(); - while (compileTargetsEnum.hasMoreElements()) { - TargetInfo compileTarget = (TargetInfo) compileTargetsEnum - .nextElement(); - // - // output of compile tasks - // - int bid = linkerConfig.bid(compileTarget.getOutput().toString()); - if (bid > 0) { - objectFiles.addElement(compileTarget.getOutput()); - } - } - File[] objectFileArray = new File[objectFiles.size()]; - objectFiles.copyInto(objectFileArray); - File[] sysObjectFileArray = new File[sysObjectFiles.size()]; - sysObjectFiles.copyInto(sysObjectFileArray); - String baseName = _outfile.getName(); - String[] fullNames = linkerConfig.getOutputFileNames(baseName, versionInfo); - File outputFile = new File(_outfile.getParent(), fullNames[0]); - return new TargetInfo(linkerConfig, objectFileArray, - sysObjectFileArray, outputFile, linkerConfig.getRebuild()); - } - public File getObjdir() { - return _objDir; - } - public File getOutfile() { - return _outfile; - } - - public TargetDef getTargetPlatform() { - return null; - } - /** - * This method collects a Hashtable, keyed by output file name, of - * TargetInfo's for every source file that is specified in the filesets of - * the and nested elements. The TargetInfo's contain the - * appropriate compiler configurations for their possible compilation - * - */ - private Hashtable getTargets(LinkerConfiguration linkerConfig, - Vector objectFiles, VersionInfo versionInfo, File outputFile) { - Hashtable targets = new Hashtable(1000); - TargetDef targetPlatform = getTargetPlatform(); - // - // find active (specialized) compilers - // - Vector biddingProcessors = new Vector(_compilers.size()); - for (int i = 0; i < _compilers.size(); i++) { - CompilerDef currentCompilerDef = (CompilerDef) _compilers - .elementAt(i); - if (currentCompilerDef.isActive()) { - ProcessorConfiguration config = currentCompilerDef - .createConfiguration(this, linkType, compilerDef, - targetPlatform, versionInfo); - // - // see if this processor had a precompile child element - // - PrecompileDef precompileDef = currentCompilerDef - .getActivePrecompile(compilerDef); - ProcessorConfiguration[] localConfigs = new ProcessorConfiguration[]{config}; - // - // if it does then - // - if (precompileDef != null) { - File prototype = precompileDef.getPrototype(); - // - // will throw exceptions if prototype doesn't exist, etc - // - if (!prototype.exists()) { - throw new BuildException("prototype (" - + prototype.toString() + ") does not exist."); - } - if (prototype.isDirectory()) { - throw new BuildException("prototype (" - + prototype.toString() + ") is a directory."); - } - String[] exceptFiles = precompileDef.getExceptFiles(); - // - // create a precompile building and precompile using - // variants of the configuration - // or return null if compiler doesn't support - // precompilation - CompilerConfiguration[] configs = ((CompilerConfiguration) config) - .createPrecompileConfigurations(prototype, - exceptFiles); - if (configs != null && configs.length == 2) { - // - // visit the precompiled file to add it into the - // targets list (just like any other file if - // compiler doesn't support precompilation) - TargetMatcher matcher = new TargetMatcher(this, - _objDir, - new ProcessorConfiguration[]{configs[0]}, - linkerConfig, objectFiles, targets, versionInfo); - - matcher.visit(new File(prototype.getParent()), - prototype.getName()); - // - // only the configuration that uses the - // precompiled header gets added to the bidding list - biddingProcessors.addElement(configs[1]); - localConfigs = new ProcessorConfiguration[2]; - localConfigs[0] = configs[1]; - localConfigs[1] = config; - } - } - // - // if the compiler has a fileset - // then allow it to add its files - // to the set of potential targets - if (currentCompilerDef.hasFileSets()) { - TargetMatcher matcher = new TargetMatcher(this, _objDir, - localConfigs, linkerConfig, objectFiles, targets, + // + // walk the compile phase targets and + // add those sources that have already been + // assigned to the linker or + // our output files the linker knows how to consume + // files the linker knows how to consume + // + Enumeration compileTargetsEnum = compileTargets.elements(); + while (compileTargetsEnum.hasMoreElements()) { + TargetInfo compileTarget = (TargetInfo) compileTargetsEnum + .nextElement(); + // + // output of compile tasks + // + int bid = linkerConfig.bid(compileTarget.getOutput().toString()); + if (bid > 0) { + objectFiles.addElement(compileTarget.getOutput()); + } + } + File[] objectFileArray = new File[objectFiles.size()]; + objectFiles.copyInto(objectFileArray); + File[] sysObjectFileArray = new File[sysObjectFiles.size()]; + sysObjectFiles.copyInto(sysObjectFileArray); + String baseName = _outfile.getName(); + String[] fullNames = linkerConfig.getOutputFileNames(baseName, + versionInfo); + File outputFile = new File(_outfile.getParent(), fullNames[0]); + return new TargetInfo(linkerConfig, objectFileArray, + sysObjectFileArray, outputFile, linkerConfig.getRebuild()); + } + + public File getObjdir() { + return _objDir; + } + + public File getOutfile() { + return _outfile; + } + + public TargetDef getTargetPlatform() { + return null; + } + + /** + * This method collects a Hashtable, keyed by output file name, of + * TargetInfo's for every source file that is specified in the filesets of + * the and nested elements. The TargetInfo's contain the + * appropriate compiler configurations for their possible compilation + * + */ + private Hashtable getTargets(LinkerConfiguration linkerConfig, + Vector objectFiles, VersionInfo versionInfo, File outputFile) { + Hashtable targets = new Hashtable(1000); + TargetDef targetPlatform = getTargetPlatform(); + // + // find active (specialized) compilers + // + Vector biddingProcessors = new Vector(_compilers.size()); + for (int i = 0; i < _compilers.size(); i++) { + CompilerDef currentCompilerDef = (CompilerDef) _compilers + .elementAt(i); + if (currentCompilerDef.isActive()) { + ProcessorConfiguration config = currentCompilerDef + .createConfiguration(this, linkType, compilerDef, + targetPlatform, versionInfo); + // + // see if this processor had a precompile child element + // + PrecompileDef precompileDef = currentCompilerDef + .getActivePrecompile(compilerDef); + ProcessorConfiguration[] localConfigs = new ProcessorConfiguration[] { config }; + // + // if it does then + // + if (precompileDef != null) { + File prototype = precompileDef.getPrototype(); + // + // will throw exceptions if prototype doesn't exist, etc + // + if (!prototype.exists()) { + throw new BuildException("prototype (" + + prototype.toString() + ") does not exist."); + } + if (prototype.isDirectory()) { + throw new BuildException("prototype (" + + prototype.toString() + ") is a directory."); + } + String[] exceptFiles = precompileDef.getExceptFiles(); + // + // create a precompile building and precompile using + // variants of the configuration + // or return null if compiler doesn't support + // precompilation + CompilerConfiguration[] configs = ((CompilerConfiguration) config) + .createPrecompileConfigurations(prototype, + exceptFiles); + if (configs != null && configs.length == 2) { + // + // visit the precompiled file to add it into the + // targets list (just like any other file if + // compiler doesn't support precompilation) + TargetMatcher matcher = new TargetMatcher(this, + _objDir, + new ProcessorConfiguration[] { configs[0] }, + linkerConfig, objectFiles, targets, versionInfo); + + matcher.visit(new File(prototype.getParent()), + prototype.getName()); + // + // only the configuration that uses the + // precompiled header gets added to the bidding list + biddingProcessors.addElement(configs[1]); + localConfigs = new ProcessorConfiguration[2]; + localConfigs[0] = configs[1]; + localConfigs[1] = config; + } + } + // + // if the compiler has a fileset + // then allow it to add its files + // to the set of potential targets + if (currentCompilerDef.hasFileSets()) { + TargetMatcher matcher = new TargetMatcher(this, _objDir, + localConfigs, linkerConfig, objectFiles, targets, versionInfo); - currentCompilerDef.visitFiles(matcher); - } - biddingProcessors.addElement(config); - } - } - // - // add fallback compiler at the end - // - ProcessorConfiguration config = compilerDef.createConfiguration(this, - linkType, null, targetPlatform, versionInfo); - biddingProcessors.addElement(config); - ProcessorConfiguration[] bidders = new ProcessorConfiguration[biddingProcessors - .size()]; - biddingProcessors.copyInto(bidders); - // - // bid out the 's in the cctask - // - TargetMatcher matcher = new TargetMatcher(this, _objDir, bidders, - linkerConfig, objectFiles, targets, versionInfo); - compilerDef.visitFiles(matcher); - - if (outputFile != null && versionInfo != null) { - boolean isDebug = linkerConfig.isDebug(); - try { - linkerConfig.getLinker().addVersionFiles(versionInfo, linkType, - outputFile, - isDebug, - _objDir, matcher); - } catch(IOException ex) { - throw new BuildException(ex); - } - } - return targets; - } - /** - * Sets the default compiler adapter. Use the "name" attribute when the - * compiler is a supported compiler. - * - * @param classname - * fully qualified classname which implements CompilerAdapter - */ - public void setClassname(String classname) { - compilerDef.setClassname(classname); - linkerDef.setClassname(classname); - } - /** - * Sets the dataset for OS/390 builds. - * - * @param dataset - * The dataset to set - */ - public void setDataset(String dataset) { - this.dataset = dataset; - } - /** - * Enables or disables generation of debug info. - */ - public void setDebug(boolean debug) { - compilerDef.setDebug(debug); - linkerDef.setDebug(debug); - } - - /** - * Gets debug state. - * @return true if building for debugging - */ - public boolean getDebug() { - return compilerDef.getDebug(null, 0); - } - - /** - * Deprecated. - * - * Controls the depth of the dependency evaluation. Used to do a quick - * check of changes before a full build. - * - * Any negative value which will perform full dependency checking. Positive - * values will truncate dependency checking. A value of 0 will cause only - * those files that changed to be recompiled, a value of 1 which cause - * files that changed or that explicitly include a file that changed to be - * recompiled. - * - * Any non-negative value will cause a BuildException to be thrown before - * attempting a link or completing the task. - * - */ - public void setDependencyDepth(int depth) { - dependencyDepth = depth; - } - /** - * Enables generation of exception handling code - */ - public void setExceptions(boolean exceptions) { - compilerDef.setExceptions(exceptions); - } - /** - * Enables run-time type information. - */ - public void setRtti(boolean rtti) { - compilerDef.setRtti(rtti); - } - // public LinkType getLinkType() { - // return linkType; - // } - /** - * Enables or disables incremental linking. - * - * @param incremental - * new state - */ - public void setIncremental(boolean incremental) { - linkerDef.setIncremental(incremental); - } - /** - * Set use of libtool. - * - * If set to true, the "libtool " will be prepended to the command line for - * compatible processors - * - * @param libtool - * If true, use libtool. - */ - public void setLibtool(boolean libtool) { - compilerDef.setLibtool(libtool); - linkerDef.setLibtool(libtool); - } - /** - * Sets the output file type. Supported values "executable", "shared", and - * "static". Deprecated, specify outtype instead. - * - * @deprecated - */ - public void setLink(OutputTypeEnum outputType) { - linkType.setOutputType(outputType); - } - -// BEGINFREEHEP - public void setLinkCPP(boolean linkCPP) { - linkType.setLinkCPP(linkCPP); - } -// ENDFREEHEP - /** - * Enables or disables generation of multithreaded code - * - * @param multi - * If true, generated code may be multithreaded. - */ - public void setMultithreaded(boolean multi) { - compilerDef.setMultithreaded(multi); - } - // - // keep near duplicate comment at CompilerDef.setName in sync - // - /** - * Sets type of the default compiler and linker. - * - * Supported compilers - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
    gcc (default)GCC C++ compiler
    g++GCC C++ compiler
    c++GCC C++ compiler
    g77GNU FORTRAN compiler
    msvcMicrosoft Visual C++
    bccBorland C++ Compiler
    msrcMicrosoft Resource Compiler
    brcBorland Resource Compiler
    dfCompaq Visual Fortran Compiler
    midlMicrosoft MIDL Compiler
    iclIntel C++ compiler for Windows (IA-32)
    eclIntel C++ compiler for Windows (IA-64)
    iccIntel C++ compiler for Linux (IA-32)
    eccIntel C++ compiler for Linux (IA-64)
    CCSun ONE C++ compiler
    aCCHP aC++ C++ Compiler
    os390OS390 C Compiler
    os400Icc Compiler
    sunc89Sun C89 C Compiler
    xlCVisualAge C Compiler
    uicQt user interface compiler (creates .h, .cpp and moc_*.cpp files).
    mocQt meta-object compiler
    xpidlMozilla xpidl compiler (creates .h and .xpt files).
    wclOpenWatcom C/C++ compiler
    wflOpenWatcom FORTRAN compiler
    - * - */ - public void setName(CompilerEnum name) { - compilerDef.setName(name); - Processor compiler = compilerDef.getProcessor(); - Linker linker = compiler.getLinker(linkType); - linkerDef.setProcessor(linker); - } - /** - * Do not propagate old environment when new environment variables are - * specified. - */ - public void setNewenvironment(boolean newenv) { - compilerDef.setNewenvironment(newenv); - linkerDef.setNewenvironment(newenv); - } - /** - * Sets the destination directory for object files. - * - * Generally this should be a property expression that evaluates to - * distinct debug and release object file directories. - * - * @param dir - * object directory - */ - public void setObjdir(File dir) { - if (dir == null) { - throw new NullPointerException("dir"); - } - _objDir = dir; - } - /** - * Sets the output file name. If not specified, the task will only compile - * files and not attempt to link. If an extension is not specified, the - * task may use a system appropriate extension and prefix, for example, - * outfile="example" may result in "libexample.so" being created. - * - * @param outfile - * output file name - */ - public void setOutfile(File outfile) { - // - // if file name was empty, skip link step - // - if (outfile == null || outfile.toString().length() > 0) { - _outfile = outfile; - } - } - /** - * Specifies the name of a property to set with the physical filename that - * is produced by the linker - */ - public void setOutputFileProperty(String outputFileProperty) { - this.outputFileProperty = outputFileProperty; - } - /** - * Sets the output file type. Supported values "executable", "shared", and - * "static". - */ - public void setOuttype(OutputTypeEnum outputType) { - linkType.setOutputType(outputType); - } - - /** - * Gets output type. - * @return output type - */ - public String getOuttype() { - return linkType.getOutputType(); - } - - /** - * Sets the project. - */ - public void setProject(Project project) { - super.setProject(project); - compilerDef.setProject(project); - linkerDef.setProject(project); - } - /** - * If set to true, all files will be rebuilt. - * - * @paran rebuildAll If true, all files will be rebuilt. If false, up to - * date files will not be rebuilt. - */ - public void setRebuild(boolean rebuildAll) { - compilerDef.setRebuild(rebuildAll); - linkerDef.setRebuild(rebuildAll); - } - /** - * If set to true, compilation errors will not stop the task until all - * files have been attempted. - * - * @param relentless - * If true, don't stop on the first compilation error - * - */ - public void setRelentless(boolean relentless) { - this.relentless = relentless; - } - /** - * Sets the type of runtime library, possible values "dynamic", "static". - */ - public void setRuntime(RuntimeType rtlType) { - linkType.setStaticRuntime((rtlType.getIndex() == 1)); - } - /** - * Sets the nature of the subsystem under which that the program will - * execute. - * - * Supported subsystems - * - * - * - * - * - * - * - * - * - * - * - * - *
    guiGraphical User Interface
    consoleCommand Line Console
    otherOther
    - * - * @param subsystem - * subsystem - * @throws NullPointerException - * if subsystem is null - */ - public void setSubsystem(SubsystemEnum subsystem) { - if (subsystem == null) { - throw new NullPointerException("subsystem"); - } - linkType.setSubsystem(subsystem); - } - - /** - * Gets subsystem name. - * @return Subsystem name - */ - public String getSubsystem() { - return linkType.getSubsystem(); - } - - /** - * Enumerated attribute with the values "none", "severe", "default", - * "production", "diagnostic", and "failtask". - */ - public void setWarnings(WarningLevelEnum level) { - compilerDef.setWarnings(level); - } - - /** - * Indicates whether the build will continue - * even if there are compilation errors; defaults to true. - * @param fail if true halt the build on failure - */ - public void setFailonerror(boolean fail) { - failOnError = fail; - } - - /** - * Gets the failonerror flag. - * @return the failonerror flag - */ - public boolean getFailonerror() { - return failOnError; - } - /** - * Adds a target definition or reference (Non-functional prototype). - * - * @param target - * target - * @throws NullPointerException - * if compiler is null - */ - public void addConfiguredTarget(TargetDef target) { - if (target == null) { - throw new NullPointerException("target"); - } - target.setProject(getProject()); - targetPlatforms.addElement(target); - } - /** - * Adds a distributer definition or reference (Non-functional prototype). - * - * @param distributer - * distributer - * @throws NullPointerException - * if compiler is null - */ - public void addConfiguredDistributer(DistributerDef distributer) { - if (distributer == null) { - throw new NullPointerException("distributer"); - } - distributer.setProject(getProject()); - distributers.addElement(distributer); - } - /** - * Sets optimization. - * @param optimization - */ - public void setOptimize(OptimizationEnum optimization) { - compilerDef.setOptimize(optimization); - } - - /** - * Adds desriptive version information to be included in the - * generated file. The first active version info block will - * be used. - */ - public void addConfiguredVersioninfo(VersionInfo newVersionInfo) { - newVersionInfo.setProject(this.getProject()); - versionInfos.addElement(newVersionInfo); - } - + currentCompilerDef.visitFiles(matcher); + } + biddingProcessors.addElement(config); + } + } + // + // add fallback compiler at the end + // + ProcessorConfiguration config = compilerDef.createConfiguration(this, + linkType, null, targetPlatform, versionInfo); + biddingProcessors.addElement(config); + ProcessorConfiguration[] bidders = new ProcessorConfiguration[biddingProcessors + .size()]; + biddingProcessors.copyInto(bidders); + // + // bid out the 's in the cctask + // + TargetMatcher matcher = new TargetMatcher(this, _objDir, bidders, + linkerConfig, objectFiles, targets, versionInfo); + compilerDef.visitFiles(matcher); + + if (outputFile != null && versionInfo != null) { + boolean isDebug = linkerConfig.isDebug(); + try { + linkerConfig.getLinker().addVersionFiles(versionInfo, linkType, + outputFile, isDebug, _objDir, matcher); + } catch (IOException ex) { + throw new BuildException(ex); + } + } + return targets; + } + + /** + * Sets the default compiler adapter. Use the "name" attribute when the + * compiler is a supported compiler. + * + * @param classname + * fully qualified classname which implements CompilerAdapter + */ + public void setClassname(String classname) { + compilerDef.setClassname(classname); + linkerDef.setClassname(classname); + } + + /** + * Sets the dataset for OS/390 builds. + * + * @param dataset + * The dataset to set + */ + public void setDataset(String dataset) { + this.dataset = dataset; + } + + /** + * Enables or disables generation of debug info. + */ + public void setDebug(boolean debug) { + compilerDef.setDebug(debug); + linkerDef.setDebug(debug); + } + + /** + * Gets debug state. + * + * @return true if building for debugging + */ + public boolean getDebug() { + return compilerDef.getDebug(null, 0); + } + + /** + * Deprecated. + * + * Controls the depth of the dependency evaluation. Used to do a quick check + * of changes before a full build. + * + * Any negative value which will perform full dependency checking. Positive + * values will truncate dependency checking. A value of 0 will cause only + * those files that changed to be recompiled, a value of 1 which cause files + * that changed or that explicitly include a file that changed to be + * recompiled. + * + * Any non-negative value will cause a BuildException to be thrown before + * attempting a link or completing the task. + * + */ + public void setDependencyDepth(int depth) { + dependencyDepth = depth; + } + + /** + * Enables generation of exception handling code + */ + public void setExceptions(boolean exceptions) { + compilerDef.setExceptions(exceptions); + } + + /** + * Enables run-time type information. + */ + public void setRtti(boolean rtti) { + compilerDef.setRtti(rtti); + } + + // public LinkType getLinkType() { + // return linkType; + // } + /** + * Enables or disables incremental linking. + * + * @param incremental + * new state + */ + public void setIncremental(boolean incremental) { + linkerDef.setIncremental(incremental); + } + + /** + * Set use of libtool. + * + * If set to true, the "libtool " will be prepended to the command line for + * compatible processors + * + * @param libtool + * If true, use libtool. + */ + public void setLibtool(boolean libtool) { + compilerDef.setLibtool(libtool); + linkerDef.setLibtool(libtool); + } + + /** + * Sets the output file type. Supported values "executable", "shared", and + * "static". Deprecated, specify outtype instead. + * + * @deprecated + */ + public void setLink(OutputTypeEnum outputType) { + linkType.setOutputType(outputType); + } + + // BEGINFREEHEP + public void setLinkCPP(boolean linkCPP) { + linkType.setLinkCPP(linkCPP); + } + + // ENDFREEHEP + /** + * Enables or disables generation of multithreaded code + * + * @param multi + * If true, generated code may be multithreaded. + */ + public void setMultithreaded(boolean multi) { + compilerDef.setMultithreaded(multi); + } + + // + // keep near duplicate comment at CompilerDef.setName in sync + // + /** + * Sets type of the default compiler and linker. + * + * Supported compilers + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    gcc (default)GCC C++ compiler
    g++GCC C++ compiler
    c++GCC C++ compiler
    g77GNU FORTRAN compiler
    msvcMicrosoft Visual C++
    bccBorland C++ Compiler
    msrcMicrosoft Resource Compiler
    brcBorland Resource Compiler
    dfCompaq Visual Fortran Compiler
    midlMicrosoft MIDL Compiler
    iclIntel C++ compiler for Windows (IA-32)
    eclIntel C++ compiler for Windows (IA-64)
    iccIntel C++ compiler for Linux (IA-32)
    eccIntel C++ compiler for Linux (IA-64)
    CCSun ONE C++ compiler
    aCCHP aC++ C++ Compiler
    os390OS390 C Compiler
    os400Icc Compiler
    sunc89Sun C89 C Compiler
    xlCVisualAge C Compiler
    uicQt user interface compiler (creates .h, .cpp and moc_*.cpp files).
    mocQt meta-object compiler
    xpidlMozilla xpidl compiler (creates .h and .xpt files).
    wclOpenWatcom C/C++ compiler
    wflOpenWatcom FORTRAN compiler
    + * + */ + public void setName(CompilerEnum name) { + compilerDef.setName(name); + Processor compiler = compilerDef.getProcessor(); + Linker linker = compiler.getLinker(linkType); + linkerDef.setProcessor(linker); + } + + /** + * Do not propagate old environment when new environment variables are + * specified. + */ + public void setNewenvironment(boolean newenv) { + compilerDef.setNewenvironment(newenv); + linkerDef.setNewenvironment(newenv); + } + + /** + * Sets the destination directory for object files. + * + * Generally this should be a property expression that evaluates to distinct + * debug and release object file directories. + * + * @param dir + * object directory + */ + public void setObjdir(File dir) { + if (dir == null) { + throw new NullPointerException("dir"); + } + _objDir = dir; + } + + /** + * Sets the output file name. If not specified, the task will only compile + * files and not attempt to link. If an extension is not specified, the task + * may use a system appropriate extension and prefix, for example, + * outfile="example" may result in "libexample.so" being created. + * + * @param outfile + * output file name + */ + public void setOutfile(File outfile) { + // + // if file name was empty, skip link step + // + if (outfile == null || outfile.toString().length() > 0) { + _outfile = outfile; + } + } + + /** + * Specifies the name of a property to set with the physical filename that + * is produced by the linker + */ + public void setOutputFileProperty(String outputFileProperty) { + this.outputFileProperty = outputFileProperty; + } + + /** + * Sets the output file type. Supported values "executable", "shared", and + * "static". + */ + public void setOuttype(OutputTypeEnum outputType) { + linkType.setOutputType(outputType); + } + + /** + * Gets output type. + * + * @return output type + */ + public String getOuttype() { + return linkType.getOutputType(); + } + + /** + * Sets the project. + */ + public void setProject(Project project) { + super.setProject(project); + compilerDef.setProject(project); + linkerDef.setProject(project); + } + + /** + * If set to true, all files will be rebuilt. + * + * @paran rebuildAll If true, all files will be rebuilt. If false, up to + * date files will not be rebuilt. + */ + public void setRebuild(boolean rebuildAll) { + compilerDef.setRebuild(rebuildAll); + linkerDef.setRebuild(rebuildAll); + } + + /** + * If set to true, compilation errors will not stop the task until all files + * have been attempted. + * + * @param relentless + * If true, don't stop on the first compilation error + * + */ + public void setRelentless(boolean relentless) { + this.relentless = relentless; + } + + /** + * Sets the type of runtime library, possible values "dynamic", "static". + */ + public void setRuntime(RuntimeType rtlType) { + linkType.setStaticRuntime((rtlType.getIndex() == 1)); + } + + /** + * Sets the nature of the subsystem under which that the program will + * execute. + * + * Supported subsystems + * + * + * + * + * + * + * + * + * + * + * + * + *
    guiGraphical User Interface
    consoleCommand Line Console
    otherOther
    + * + * @param subsystem + * subsystem + * @throws NullPointerException + * if subsystem is null + */ + public void setSubsystem(SubsystemEnum subsystem) { + if (subsystem == null) { + throw new NullPointerException("subsystem"); + } + linkType.setSubsystem(subsystem); + } + + /** + * Gets subsystem name. + * + * @return Subsystem name + */ + public String getSubsystem() { + return linkType.getSubsystem(); + } + + /** + * Enumerated attribute with the values "none", "severe", "default", + * "production", "diagnostic", and "failtask". + */ + public void setWarnings(WarningLevelEnum level) { + compilerDef.setWarnings(level); + } + + /** + * Indicates whether the build will continue even if there are compilation + * errors; defaults to true. + * + * @param fail + * if true halt the build on failure + */ + public void setFailonerror(boolean fail) { + failOnError = fail; + } + + /** + * Gets the failonerror flag. + * + * @return the failonerror flag + */ + public boolean getFailonerror() { + return failOnError; + } + + /** + * Adds a target definition or reference (Non-functional prototype). + * + * @param target + * target + * @throws NullPointerException + * if compiler is null + */ + public void addConfiguredTarget(TargetDef target) { + if (target == null) { + throw new NullPointerException("target"); + } + target.setProject(getProject()); + targetPlatforms.addElement(target); + } + + /** + * Adds a distributer definition or reference (Non-functional prototype). + * + * @param distributer + * distributer + * @throws NullPointerException + * if compiler is null + */ + public void addConfiguredDistributer(DistributerDef distributer) { + if (distributer == null) { + throw new NullPointerException("distributer"); + } + distributer.setProject(getProject()); + distributers.addElement(distributer); + } + + /** + * Sets optimization. + * + * @param optimization + */ + public void setOptimize(OptimizationEnum optimization) { + compilerDef.setOptimize(optimization); + } + + /** + * Adds desriptive version information to be included in the generated file. + * The first active version info block will be used. + */ + public void addConfiguredVersioninfo(VersionInfo newVersionInfo) { + newVersionInfo.setProject(this.getProject()); + versionInfos.addElement(newVersionInfo); + } + } diff --git a/src/net/sf/antcontrib/cpptasks/TargetHistoryTable.java b/src/net/sf/antcontrib/cpptasks/TargetHistoryTable.java index bdab94c..1a6eda1 100644 --- a/src/net/sf/antcontrib/cpptasks/TargetHistoryTable.java +++ b/src/net/sf/antcontrib/cpptasks/TargetHistoryTable.java @@ -323,7 +323,8 @@ public final class TargetHistoryTable { markForRebuild((TargetInfo) targetInfoEnum.nextElement()); } } - public void markForRebuild(TargetInfo targetInfo) { + // FREEHEP added synchronized + public synchronized void markForRebuild(TargetInfo targetInfo) { // // if it must already be rebuilt, no need to check further // @@ -382,7 +383,8 @@ public final class TargetHistoryTable { } } } - private void update(String configId, String outputName, String[] sources) { +// FREEHEP added synchronized + private synchronized void update(String configId, String outputName, String[] sources) { File outputFile = new File(outputDir, outputName); // // if output file doesn't exist or predates the start of the @@ -407,7 +409,8 @@ public final class TargetHistoryTable { history.put(outputName, newHistory); } } - public void update(TargetInfo linkTarget) { + // FREEHEP added synchronized + public synchronized void update(TargetInfo linkTarget) { File outputFile = linkTarget.getOutput(); String outputName = outputFile.getName(); // -- cgit v1.2.3