summaryrefslogtreecommitdiffstats
path: root/src/net/sf/antcontrib/cpptasks/DependencyTable.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/sf/antcontrib/cpptasks/DependencyTable.java')
-rw-r--r--src/net/sf/antcontrib/cpptasks/DependencyTable.java612
1 files changed, 0 insertions, 612 deletions
diff --git a/src/net/sf/antcontrib/cpptasks/DependencyTable.java b/src/net/sf/antcontrib/cpptasks/DependencyTable.java
deleted file mode 100644
index 9e57eb1..0000000
--- a/src/net/sf/antcontrib/cpptasks/DependencyTable.java
+++ /dev/null
@@ -1,612 +0,0 @@
-/*
- *
- * 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.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Vector;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-import net.sf.antcontrib.cpptasks.compiler.CompilerConfiguration;
-import org.apache.tools.ant.BuildException;
-import org.apache.tools.ant.Project;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
-/**
- * @author Curt Arnold
- */
-public final class DependencyTable {
- /**
- * This class handles populates the TargetHistory hashtable in response to
- * SAX parse events
- */
- private class DependencyTableHandler extends DefaultHandler {
- private File baseDir;
- private final DependencyTable dependencyTable;
- private String includePath;
- private Vector includes;
- private String source;
- private long sourceLastModified;
- private Vector sysIncludes;
- /**
- * Constructor
- *
- * @param history
- * hashtable of TargetHistory keyed by output name
- * @param outputFiles
- * existing files in output directory
- */
- private DependencyTableHandler(DependencyTable dependencyTable,
- File baseDir) {
- this.dependencyTable = dependencyTable;
- this.baseDir = baseDir;
- includes = new Vector();
- sysIncludes = new Vector();
- source = null;
- }
- public void endElement(String namespaceURI, String localName,
- String qName) throws SAXException {
- //
- // if </source> then
- // create Dependency object and add to hashtable
- // if corresponding source file exists and
- // has the same timestamp
- //
- if (qName.equals("source")) {
- if (source != null && includePath != null) {
- File existingFile = new File(baseDir, source);
- //
- // if the file exists and the time stamp is right
- // preserve the dependency info
- if (existingFile.exists()) {
- //
- // would have expected exact matches
- // but was seeing some unexpected difference by
- // a few tens of milliseconds, as long
- // as the times are within a second
- long existingLastModified = existingFile.lastModified();
- if (!CUtil.isSignificantlyAfter(existingLastModified, sourceLastModified) &&
- !CUtil.isSignificantlyBefore(existingLastModified, sourceLastModified)) {
- DependencyInfo dependInfo = new DependencyInfo(
- includePath, source, sourceLastModified,
- includes, sysIncludes);
- dependencyTable.putDependencyInfo(source,
- dependInfo);
- }
- }
- source = null;
- includes.setSize(0);
- }
- } else {
- //
- // this causes any <source> elements outside the
- // scope of an <includePath> to be discarded
- //
- if (qName.equals("includePath")) {
- includePath = null;
- }
- }
- }
- /**
- * startElement handler
- */
- public void startElement(String namespaceURI, String localName,
- String qName, Attributes atts) throws SAXException {
- //
- // if includes, then add relative file name to vector
- //
- if (qName.equals("include")) {
- includes.addElement(atts.getValue("file"));
- } else {
- if (qName.equals("sysinclude")) {
- sysIncludes.addElement(atts.getValue("file"));
- } else {
- //
- // if source then
- // capture source file name,
- // modification time and reset includes vector
- //
- if (qName.equals("source")) {
- source = atts.getValue("file");
- sourceLastModified = Long.parseLong(atts
- .getValue("lastModified"), 16);
- includes.setSize(0);
- sysIncludes.setSize(0);
- } else {
- if (qName.equals("includePath")) {
- includePath = atts.getValue("signature");
- }
- }
- }
- }
- }
- }
- public abstract class DependencyVisitor {
- /**
- * Previews all the children of this source file.
- *
- * May be called multiple times as DependencyInfo's for children are
- * filled in.
- *
- * @return true to continue towards recursion into included files
- */
- public abstract boolean preview(DependencyInfo parent,
- DependencyInfo[] children);
- /**
- * Called if the dependency depth exhausted the stack.
- */
- public abstract void stackExhausted();
- /**
- * Visits the dependency info.
- *
- * @returns true to continue towards recursion into included files
- */
- public abstract boolean visit(DependencyInfo dependInfo);
- }
- public class TimestampChecker extends DependencyVisitor {
- private boolean noNeedToRebuild;
- private long outputLastModified;
- private boolean rebuildOnStackExhaustion;
- public TimestampChecker(final long outputLastModified,
- boolean rebuildOnStackExhaustion) {
- this.outputLastModified = outputLastModified;
- noNeedToRebuild = true;
- this.rebuildOnStackExhaustion = rebuildOnStackExhaustion;
- }
- public boolean getMustRebuild() {
- return !noNeedToRebuild;
- }
- public boolean preview(DependencyInfo parent, DependencyInfo[] children) {
- int withCompositeTimes = 0;
- long parentCompositeLastModified = parent.getSourceLastModified();
- for (int i = 0; i < children.length; i++) {
- if (children[i] != null) {
- //
- // expedient way to determine if a child forces us to
- // rebuild
- //
- visit(children[i]);
- long childCompositeLastModified = children[i]
- .getCompositeLastModified();
- if (childCompositeLastModified != Long.MIN_VALUE) {
- withCompositeTimes++;
- if (childCompositeLastModified > parentCompositeLastModified) {
- parentCompositeLastModified = childCompositeLastModified;
- }
- }
- }
- }
- if (withCompositeTimes == children.length) {
- parent.setCompositeLastModified(parentCompositeLastModified);
- }
- //
- // may have been changed by an earlier call to visit()
- //
- return noNeedToRebuild;
- }
- public void stackExhausted() {
- if (rebuildOnStackExhaustion) {
- noNeedToRebuild = false;
- }
- }
- public boolean visit(DependencyInfo dependInfo) {
- if (noNeedToRebuild) {
- if (CUtil.isSignificantlyAfter(dependInfo.getSourceLastModified(), outputLastModified)
- || CUtil.isSignificantlyAfter(dependInfo.getCompositeLastModified(), outputLastModified)) {
- noNeedToRebuild = false;
- }
- }
- //
- // only need to process the children if
- // it has not yet been determined whether
- // we need to rebuild and the composite modified time
- // has not been determined for this file
- return noNeedToRebuild
- && dependInfo.getCompositeLastModified() == Long.MIN_VALUE;
- }
- }
- private/* final */File baseDir;
- private String baseDirPath;
- /**
- * a hashtable of DependencyInfo[] keyed by output file name
- */
- private final Hashtable dependencies = new Hashtable();
- /** The file the cache was loaded from. */
- private/* final */File dependenciesFile;
- /** Flag indicating whether the cache should be written back to file. */
- private boolean dirty;
- /**
- * Creates a target history table from dependencies.xml in the prject
- * directory, if it exists. Otherwise, initializes the dependencies empty.
- *
- * @param task
- * task used for logging history load errors
- * @param baseDir
- * output directory for task
- */
- public DependencyTable(File baseDir) {
- if (baseDir == null) {
- throw new NullPointerException("baseDir");
- }
- this.baseDir = baseDir;
- try {
- baseDirPath = baseDir.getCanonicalPath();
- } catch (IOException ex) {
- baseDirPath = baseDir.toString();
- }
- dirty = false;
- //
- // load any existing dependencies from file
- dependenciesFile = new File(baseDir, "dependencies.xml");
- }
- public void commit(CCTask task) {
- //
- // if not dirty, no need to update file
- //
- if (dirty) {
- //
- // walk through dependencies to get vector of include paths
- // identifiers
- //
- Vector includePaths = getIncludePaths();
- //
- //
- // write dependency file
- //
- try {
- FileOutputStream outStream = new FileOutputStream(
- dependenciesFile);
- OutputStreamWriter streamWriter;
- //
- // Early VM's may not have UTF-8 support
- // fallback to default code page which
- // "should" be okay unless there are
- // non ASCII file names
- String encodingName = "UTF-8";
- try {
- streamWriter = new OutputStreamWriter(outStream, "UTF-8");
- } catch (UnsupportedEncodingException ex) {
- streamWriter = new OutputStreamWriter(outStream);
- encodingName = streamWriter.getEncoding();
- }
- BufferedWriter writer = new BufferedWriter(streamWriter);
- writer.write("<?xml version='1.0' encoding='");
- writer.write(encodingName);
- writer.write("'?>\n");
- writer.write("<dependencies>\n");
- StringBuffer buf = new StringBuffer();
- Enumeration includePathEnum = includePaths.elements();
- while (includePathEnum.hasMoreElements()) {
- writeIncludePathDependencies((String) includePathEnum
- .nextElement(), writer, buf);
- }
- writer.write("</dependencies>\n");
- writer.close();
- dirty = false;
- } catch (IOException ex) {
- task.log("Error writing " + dependenciesFile.toString() + ":"
- + ex.toString());
- }
- }
- }
- /**
- * Returns an enumerator of DependencyInfo's
- */
- public Enumeration elements() {
- return dependencies.elements();
- }
- /**
- * This method returns a DependencyInfo for the specific source file and
- * include path identifier
- *
- */
- public DependencyInfo getDependencyInfo(String sourceRelativeName,
- String includePathIdentifier) {
- DependencyInfo dependInfo = null;
- DependencyInfo[] dependInfos = (DependencyInfo[]) dependencies
- .get(sourceRelativeName);
- if (dependInfos != null) {
- for (int i = 0; i < dependInfos.length; i++) {
- dependInfo = dependInfos[i];
- if (dependInfo.getIncludePathIdentifier().equals(
- includePathIdentifier)) {
- return dependInfo;
- }
- }
- }
- return null;
- }
- private Vector getIncludePaths() {
- Vector includePaths = new Vector();
- DependencyInfo[] dependInfos;
- Enumeration dependenciesEnum = dependencies.elements();
- while (dependenciesEnum.hasMoreElements()) {
- dependInfos = (DependencyInfo[]) dependenciesEnum.nextElement();
- for (int i = 0; i < dependInfos.length; i++) {
- DependencyInfo dependInfo = dependInfos[i];
- boolean matchesExisting = false;
- final String dependIncludePath = dependInfo
- .getIncludePathIdentifier();
- Enumeration includePathEnum = includePaths.elements();
- while (includePathEnum.hasMoreElements()) {
- if (dependIncludePath.equals(includePathEnum.nextElement())) {
- matchesExisting = true;
- break;
- }
- }
- if (!matchesExisting) {
- includePaths.addElement(dependIncludePath);
- }
- }
- }
- return includePaths;
- }
- public void load() throws IOException, ParserConfigurationException,
- SAXException {
- dependencies.clear();
- if (dependenciesFile.exists()) {
- SAXParserFactory factory = SAXParserFactory.newInstance();
- factory.setValidating(false);
- SAXParser parser = factory.newSAXParser();
- parser.parse(dependenciesFile, new DependencyTableHandler(this,
- baseDir));
- dirty = false;
- }
- }
- /**
- * Determines if the specified target needs to be rebuilt.
- *
- * This task may result in substantial IO as files are parsed to determine
- * their dependencies
- */
- public boolean needsRebuild(CCTask task, TargetInfo target,
- int dependencyDepth) {
- // look at any files where the compositeLastModified
- // is not known, but the includes are known
- //
- boolean mustRebuild = false;
- CompilerConfiguration compiler = (CompilerConfiguration) target
- .getConfiguration();
- String includePathIdentifier = compiler.getIncludePathIdentifier();
- File[] sources = target.getSources();
- DependencyInfo[] dependInfos = new DependencyInfo[sources.length];
- long outputLastModified = target.getOutput().lastModified();
- //
- // try to solve problem using existing dependency info
- // (not parsing any new files)
- //
- DependencyInfo[] stack = new DependencyInfo[50];
- boolean rebuildOnStackExhaustion = true;
- if (dependencyDepth >= 0) {
- if (dependencyDepth < 50) {
- stack = new DependencyInfo[dependencyDepth];
- }
- rebuildOnStackExhaustion = false;
- }
- TimestampChecker checker = new TimestampChecker(outputLastModified,
- rebuildOnStackExhaustion);
- for (int i = 0; i < sources.length && !mustRebuild; i++) {
- File source = sources[i];
- String relative = CUtil.getRelativePath(baseDirPath, source);
- DependencyInfo dependInfo = getDependencyInfo(relative,
- includePathIdentifier);
- if (dependInfo == null) {
- task.log("Parsing " + relative, Project.MSG_VERBOSE);
- dependInfo = parseIncludes(task, compiler, source);
- }
- walkDependencies(task, dependInfo, compiler, stack, checker);
- mustRebuild = checker.getMustRebuild();
- }
- return mustRebuild;
- }
- public DependencyInfo parseIncludes(CCTask task,
- CompilerConfiguration compiler, File source) {
- DependencyInfo dependInfo = compiler.parseIncludes(task, baseDir,
- source);
- String relativeSource = CUtil.getRelativePath(baseDirPath, source);
- putDependencyInfo(relativeSource, dependInfo);
- return dependInfo;
- }
- private void putDependencyInfo(String key, DependencyInfo dependInfo) {
- //
- // optimistic, add new value
- //
- DependencyInfo[] old = (DependencyInfo[]) dependencies.put(key,
- new DependencyInfo[]{dependInfo});
- dirty = true;
- //
- // something was already there
- //
- if (old != null) {
- //
- // see if the include path matches a previous entry
- // if so replace it
- String includePathIdentifier = dependInfo
- .getIncludePathIdentifier();
- for (int i = 0; i < old.length; i++) {
- DependencyInfo oldDepend = old[i];
- if (oldDepend.getIncludePathIdentifier().equals(
- includePathIdentifier)) {
- old[i] = dependInfo;
- dependencies.put(key, old);
- return;
- }
- }
- //
- // no match prepend the new entry to the array
- // of dependencies for the file
- DependencyInfo[] combined = new DependencyInfo[old.length + 1];
- combined[0] = dependInfo;
- for (int i = 0; i < old.length; i++) {
- combined[i + 1] = old[i];
- }
- dependencies.put(key, combined);
- }
- return;
- }
- public void walkDependencies(CCTask task, DependencyInfo dependInfo,
- CompilerConfiguration compiler, DependencyInfo[] stack,
- DependencyVisitor visitor) throws BuildException {
- //
- // visit this node
- // if visit returns true then
- // visit the referenced include and sysInclude dependencies
- //
- if (visitor.visit(dependInfo)) {
- //
- // find first null entry on stack
- //
- int stackPosition = -1;
- for (int i = 0; i < stack.length; i++) {
- if (stack[i] == null) {
- stackPosition = i;
- stack[i] = dependInfo;
- break;
- } else {
- //
- // if we have appeared early in the calling history
- // then we didn't exceed the criteria
- if (stack[i] == dependInfo) {
- return;
- }
- }
- }
- if (stackPosition == -1) {
- visitor.stackExhausted();
- return;
- }
- //
- // locate dependency infos
- //
- String[] includes = dependInfo.getIncludes();
- String includePathIdentifier = compiler.getIncludePathIdentifier();
- DependencyInfo[] includeInfos = new DependencyInfo[includes.length];
- for (int i = 0; i < includes.length; i++) {
- DependencyInfo includeInfo = getDependencyInfo(includes[i],
- includePathIdentifier);
- includeInfos[i] = includeInfo;
- }
- //
- // preview with only the already available dependency infos
- //
- if (visitor.preview(dependInfo, includeInfos)) {
- //
- // now need to fill in the missing DependencyInfos
- //
- int missingCount = 0;
- for (int i = 0; i < includes.length; i++) {
- if (includeInfos[i] == null) {
- missingCount++;
- task.log("Parsing " + includes[i], Project.MSG_VERBOSE);
- //
- // If the include filepath is relative
- // then anchor it the base directory
- File src = new File(includes[i]);
- if (!src.isAbsolute()) {
- src = new File(baseDir, includes[i]);
- }
- DependencyInfo includeInfo = parseIncludes(task,
- compiler, src);
- includeInfos[i] = includeInfo;
- }
- }
- //
- // if it passes a review the second time
- // then recurse into all the children
- if (missingCount == 0
- || visitor.preview(dependInfo, includeInfos)) {
- //
- // recurse into
- //
- for (int i = 0; i < includeInfos.length; i++) {
- DependencyInfo includeInfo = includeInfos[i];
- walkDependencies(task, includeInfo, compiler, stack,
- visitor);
- }
- }
- }
- stack[stackPosition] = null;
- }
- }
- private void writeDependencyInfo(BufferedWriter writer, StringBuffer buf,
- DependencyInfo dependInfo) throws IOException {
- String[] includes = dependInfo.getIncludes();
- String[] sysIncludes = dependInfo.getSysIncludes();
- //
- // if the includes have not been evaluted then
- // it is not worth our time saving it
- // and trying to distiguish between files with
- // no dependencies and those with undetermined dependencies
- buf.setLength(0);
- buf.append(" <source file=\"");
- buf.append(CUtil.xmlAttribEncode(dependInfo.getSource()));
- buf.append("\" lastModified=\"");
- buf.append(Long.toHexString(dependInfo.getSourceLastModified()));
- buf.append("\">\n");
- writer.write(buf.toString());
- for (int i = 0; i < includes.length; i++) {
- buf.setLength(0);
- buf.append(" <include file=\"");
- buf.append(CUtil.xmlAttribEncode(includes[i]));
- buf.append("\"/>\n");
- writer.write(buf.toString());
- }
- for (int i = 0; i < sysIncludes.length; i++) {
- buf.setLength(0);
- buf.append(" <sysinclude file=\"");
- buf.append(CUtil.xmlAttribEncode(sysIncludes[i]));
- buf.append("\"/>\n");
- writer.write(buf.toString());
- }
- writer.write(" </source>\n");
- return;
- }
- private void writeIncludePathDependencies(String includePathIdentifier,
- BufferedWriter writer, StringBuffer buf) throws IOException {
- //
- // include path element
- //
- buf.setLength(0);
- buf.append(" <includePath signature=\"");
- buf.append(CUtil.xmlAttribEncode(includePathIdentifier));
- buf.append("\">\n");
- writer.write(buf.toString());
- Enumeration dependenciesEnum = dependencies.elements();
- while (dependenciesEnum.hasMoreElements()) {
- DependencyInfo[] dependInfos = (DependencyInfo[]) dependenciesEnum
- .nextElement();
- for (int i = 0; i < dependInfos.length; i++) {
- DependencyInfo dependInfo = dependInfos[i];
- //
- // if this is for the same include path
- // then output the info
- if (dependInfo.getIncludePathIdentifier().equals(
- includePathIdentifier)) {
- writeDependencyInfo(writer, buf, dependInfo);
- }
- }
- }
- writer.write(" </includePath>\n");
- }
-}