Initial import.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
@ -0,0 +1,426 @@
|
||||
/*
|
||||
*
|
||||
* 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.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import net.sf.antcontrib.cpptasks.compiler.ProcessorConfiguration;
|
||||
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
/**
|
||||
* A history of the compiler and linker settings used to build the files in the
|
||||
* same directory as the history.
|
||||
*
|
||||
* @author Curt Arnold
|
||||
*/
|
||||
public final class TargetHistoryTable {
|
||||
/**
|
||||
* This class handles populates the TargetHistory hashtable in response to
|
||||
* SAX parse events
|
||||
*/
|
||||
private class TargetHistoryTableHandler extends DefaultHandler {
|
||||
private final File baseDir;
|
||||
private String config;
|
||||
private final Hashtable history;
|
||||
private String output;
|
||||
private long outputLastModified;
|
||||
private final Vector sources = new Vector();
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param history
|
||||
* hashtable of TargetHistory keyed by output name
|
||||
* @param outputFiles
|
||||
* existing files in output directory
|
||||
*/
|
||||
private TargetHistoryTableHandler(Hashtable history, File baseDir) {
|
||||
this.history = history;
|
||||
config = null;
|
||||
output = null;
|
||||
this.baseDir = baseDir;
|
||||
}
|
||||
public void endElement(String namespaceURI, String localName,
|
||||
String qName) throws SAXException {
|
||||
//
|
||||
// if </target> then
|
||||
// create TargetHistory object and add to hashtable
|
||||
// if corresponding output file exists and
|
||||
// has the same timestamp
|
||||
//
|
||||
if (qName.equals("target")) {
|
||||
if (config != null && output != null) {
|
||||
File existingFile = new File(baseDir, output);
|
||||
//
|
||||
// if the corresponding files doesn't exist or has a
|
||||
// different
|
||||
// modification time, then discard this record
|
||||
if (existingFile.exists()) {
|
||||
long existingLastModified = existingFile.lastModified();
|
||||
//
|
||||
// would have expected exact time stamps
|
||||
// but have observed slight differences
|
||||
// in return value for multiple evaluations of
|
||||
// lastModified(). Check if times are within
|
||||
// a second
|
||||
long diff = outputLastModified - existingLastModified;
|
||||
if (diff >= -500 && diff <= 500) {
|
||||
SourceHistory[] sourcesArray = new SourceHistory[sources
|
||||
.size()];
|
||||
sources.copyInto(sourcesArray);
|
||||
TargetHistory targetHistory = new TargetHistory(
|
||||
config, output, outputLastModified,
|
||||
sourcesArray);
|
||||
history.put(output, targetHistory);
|
||||
}
|
||||
}
|
||||
}
|
||||
output = null;
|
||||
sources.setSize(0);
|
||||
} else {
|
||||
//
|
||||
// reset config so targets not within a processor element
|
||||
// don't pick up a previous processors signature
|
||||
//
|
||||
if (qName.equals("processor")) {
|
||||
config = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* startElement handler
|
||||
*/
|
||||
public void startElement(String namespaceURI, String localName,
|
||||
String qName, Attributes atts) throws SAXException {
|
||||
//
|
||||
// if sourceElement
|
||||
//
|
||||
if (qName.equals("source")) {
|
||||
String sourceFile = atts.getValue("file");
|
||||
long sourceLastModified = Long.parseLong(atts
|
||||
.getValue("lastModified"), 16);
|
||||
sources.addElement(new SourceHistory(sourceFile,
|
||||
sourceLastModified));
|
||||
} else {
|
||||
//
|
||||
// if <target> element,
|
||||
// grab file name and lastModified values
|
||||
// TargetHistory object will be created in endElement
|
||||
//
|
||||
if (qName.equals("target")) {
|
||||
sources.setSize(0);
|
||||
output = atts.getValue("file");
|
||||
outputLastModified = Long.parseLong(atts
|
||||
.getValue("lastModified"), 16);
|
||||
} else {
|
||||
//
|
||||
// if <processor> element,
|
||||
// grab signature attribute
|
||||
//
|
||||
if (qName.equals("processor")) {
|
||||
config = atts.getValue("signature");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Flag indicating whether the cache should be written back to file. */
|
||||
private boolean dirty;
|
||||
/**
|
||||
* a hashtable of TargetHistory's keyed by output file name
|
||||
*/
|
||||
private final Hashtable history = new Hashtable();
|
||||
/** The file the cache was loaded from. */
|
||||
private/* final */File historyFile;
|
||||
private/* final */File outputDir;
|
||||
private String outputDirPath;
|
||||
/**
|
||||
* Creates a target history table from history.xml in the output directory,
|
||||
* if it exists. Otherwise, initializes the history table empty.
|
||||
*
|
||||
* @param task
|
||||
* task used for logging history load errors
|
||||
* @param outputDir
|
||||
* output directory for task
|
||||
*/
|
||||
public TargetHistoryTable(CCTask task, File outputDir)
|
||||
throws BuildException {
|
||||
if (outputDir == null) {
|
||||
throw new NullPointerException("outputDir");
|
||||
}
|
||||
if (!outputDir.isDirectory()) {
|
||||
throw new BuildException("Output directory is not a directory");
|
||||
}
|
||||
if (!outputDir.exists()) {
|
||||
throw new BuildException("Output directory does not exist");
|
||||
}
|
||||
this.outputDir = outputDir;
|
||||
try {
|
||||
outputDirPath = outputDir.getCanonicalPath();
|
||||
} catch (IOException ex) {
|
||||
outputDirPath = outputDir.toString();
|
||||
}
|
||||
//
|
||||
// load any existing history from file
|
||||
// suppressing any records whose corresponding
|
||||
// file does not exist, is zero-length or
|
||||
// last modified dates differ
|
||||
historyFile = new File(outputDir, "history.xml");
|
||||
if (historyFile.exists()) {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setValidating(false);
|
||||
try {
|
||||
SAXParser parser = factory.newSAXParser();
|
||||
parser.parse(historyFile, new TargetHistoryTableHandler(
|
||||
history, outputDir));
|
||||
} catch (Exception ex) {
|
||||
//
|
||||
// a failure on loading this history is not critical
|
||||
// but should be logged
|
||||
task.log("Error reading history.xml: " + ex.toString());
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// create empty history file for identifying new files by last
|
||||
// modified
|
||||
// timestamp comperation (to compare with
|
||||
// System.currentTimeMillis() don't work on Unix, because it
|
||||
// maesure timestamps only in seconds).
|
||||
//
|
||||
try {
|
||||
FileOutputStream outputStream = new FileOutputStream(
|
||||
historyFile);
|
||||
byte[] historyElement = new byte[]{0x3C, 0x68, 0x69, 0x73,
|
||||
0x74, 0x6F, 0x72, 0x79, 0x2F, 0x3E};
|
||||
outputStream.write(historyElement);
|
||||
outputStream.close();
|
||||
} catch (IOException ex) {
|
||||
throw new BuildException("Can't create history file", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void commit() throws IOException {
|
||||
//
|
||||
// if not dirty, no need to update file
|
||||
//
|
||||
if (dirty) {
|
||||
//
|
||||
// build (small) hashtable of config id's in history
|
||||
//
|
||||
Hashtable configs = new Hashtable(20);
|
||||
Enumeration elements = history.elements();
|
||||
while (elements.hasMoreElements()) {
|
||||
TargetHistory targetHistory = (TargetHistory) elements
|
||||
.nextElement();
|
||||
String configId = targetHistory.getProcessorConfiguration();
|
||||
if (configs.get(configId) == null) {
|
||||
configs.put(configId, configId);
|
||||
}
|
||||
}
|
||||
FileOutputStream outStream = new FileOutputStream(historyFile);
|
||||
OutputStreamWriter outWriter;
|
||||
//
|
||||
// early VM's don't support UTF-8 encoding
|
||||
// try and fallback to the default encoding
|
||||
// otherwise
|
||||
String encodingName = "UTF-8";
|
||||
try {
|
||||
outWriter = new OutputStreamWriter(outStream, "UTF-8");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
outWriter = new OutputStreamWriter(outStream);
|
||||
encodingName = outWriter.getEncoding();
|
||||
}
|
||||
BufferedWriter writer = new BufferedWriter(outWriter);
|
||||
writer.write("<?xml version='1.0' encoding='");
|
||||
writer.write(encodingName);
|
||||
writer.write("'?>\n");
|
||||
writer.write("<history>\n");
|
||||
StringBuffer buf = new StringBuffer(200);
|
||||
Enumeration configEnum = configs.elements();
|
||||
while (configEnum.hasMoreElements()) {
|
||||
String configId = (String) configEnum.nextElement();
|
||||
buf.setLength(0);
|
||||
buf.append(" <processor signature=\"");
|
||||
buf.append(CUtil.xmlAttribEncode(configId));
|
||||
buf.append("\">\n");
|
||||
writer.write(buf.toString());
|
||||
elements = history.elements();
|
||||
while (elements.hasMoreElements()) {
|
||||
TargetHistory targetHistory = (TargetHistory) elements
|
||||
.nextElement();
|
||||
if (targetHistory.getProcessorConfiguration().equals(
|
||||
configId)) {
|
||||
buf.setLength(0);
|
||||
buf.append(" <target file=\"");
|
||||
buf.append(CUtil.xmlAttribEncode(targetHistory
|
||||
.getOutput()));
|
||||
buf.append("\" lastModified=\"");
|
||||
buf.append(Long.toHexString(targetHistory
|
||||
.getOutputLastModified()));
|
||||
buf.append("\">\n");
|
||||
writer.write(buf.toString());
|
||||
SourceHistory[] sourceHistories = targetHistory
|
||||
.getSources();
|
||||
for (int i = 0; i < sourceHistories.length; i++) {
|
||||
buf.setLength(0);
|
||||
buf.append(" <source file=\"");
|
||||
buf.append(CUtil.xmlAttribEncode(sourceHistories[i]
|
||||
.getRelativePath()));
|
||||
buf.append("\" lastModified=\"");
|
||||
buf.append(Long.toHexString(sourceHistories[i]
|
||||
.getLastModified()));
|
||||
buf.append("\"/>\n");
|
||||
writer.write(buf.toString());
|
||||
}
|
||||
writer.write(" </target>\n");
|
||||
}
|
||||
}
|
||||
writer.write(" </processor>\n");
|
||||
}
|
||||
writer.write("</history>\n");
|
||||
writer.close();
|
||||
dirty = false;
|
||||
}
|
||||
}
|
||||
public TargetHistory get(String configId, String outputName) {
|
||||
TargetHistory targetHistory = (TargetHistory) history.get(outputName);
|
||||
if (targetHistory != null) {
|
||||
if (!targetHistory.getProcessorConfiguration().equals(configId)) {
|
||||
targetHistory = null;
|
||||
}
|
||||
}
|
||||
return targetHistory;
|
||||
}
|
||||
public void markForRebuild(Hashtable targetInfos) {
|
||||
Enumeration targetInfoEnum = targetInfos.elements();
|
||||
while (targetInfoEnum.hasMoreElements()) {
|
||||
markForRebuild((TargetInfo) targetInfoEnum.nextElement());
|
||||
}
|
||||
}
|
||||
public void markForRebuild(TargetInfo targetInfo) {
|
||||
//
|
||||
// if it must already be rebuilt, no need to check further
|
||||
//
|
||||
if (!targetInfo.getRebuild()) {
|
||||
TargetHistory history = get(targetInfo.getConfiguration()
|
||||
.toString(), targetInfo.getOutput().getName());
|
||||
if (history == null) {
|
||||
targetInfo.mustRebuild();
|
||||
} else {
|
||||
SourceHistory[] sourceHistories = history.getSources();
|
||||
File[] sources = targetInfo.getSources();
|
||||
if (sourceHistories.length != sources.length) {
|
||||
targetInfo.mustRebuild();
|
||||
} else {
|
||||
for (int i = 0; i < sourceHistories.length
|
||||
&& !targetInfo.getRebuild(); i++) {
|
||||
//
|
||||
// relative file name, must absolutize it on output
|
||||
// directory
|
||||
//
|
||||
boolean foundMatch = false;
|
||||
String historySourcePath = sourceHistories[i]
|
||||
.getAbsolutePath(outputDir);
|
||||
for (int j = 0; j < sources.length; j++) {
|
||||
File targetSource = sources[j];
|
||||
String targetSourcePath = targetSource
|
||||
.getAbsolutePath();
|
||||
if (targetSourcePath.equals(historySourcePath)) {
|
||||
foundMatch = true;
|
||||
if (targetSource.lastModified() != sourceHistories[i]
|
||||
.getLastModified()) {
|
||||
targetInfo.mustRebuild();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!foundMatch) {
|
||||
targetInfo.mustRebuild();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void update(ProcessorConfiguration config, String[] sources) {
|
||||
String configId = config.getIdentifier();
|
||||
String[] onesource = new String[1];
|
||||
String outputName;
|
||||
for (int i = 0; i < sources.length; i++) {
|
||||
onesource[0] = sources[i];
|
||||
outputName = config.getOutputFileName(sources[i]);
|
||||
update(configId, outputName, onesource);
|
||||
}
|
||||
}
|
||||
private 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
|
||||
// compile step (most likely a compilation error) then
|
||||
// do not write add a history entry
|
||||
//
|
||||
if (outputFile.exists()
|
||||
&& outputFile.lastModified() >= historyFile.lastModified()) {
|
||||
dirty = true;
|
||||
history.remove(outputName);
|
||||
SourceHistory[] sourceHistories = new SourceHistory[sources.length];
|
||||
for (int i = 0; i < sources.length; i++) {
|
||||
File sourceFile = new File(sources[i]);
|
||||
long lastModified = sourceFile.lastModified();
|
||||
String relativePath = CUtil.getRelativePath(outputDirPath,
|
||||
sourceFile);
|
||||
sourceHistories[i] = new SourceHistory(relativePath,
|
||||
lastModified);
|
||||
}
|
||||
TargetHistory newHistory = new TargetHistory(configId, outputName,
|
||||
outputFile.lastModified(), sourceHistories);
|
||||
history.put(outputName, newHistory);
|
||||
}
|
||||
}
|
||||
public void update(TargetInfo linkTarget) {
|
||||
File outputFile = linkTarget.getOutput();
|
||||
String outputName = outputFile.getName();
|
||||
//
|
||||
// if output file doesn't exist or predates the start of the
|
||||
// compile or link step (most likely a compilation error) then
|
||||
// do not write add a history entry
|
||||
//
|
||||
if (outputFile.exists()
|
||||
&& outputFile.lastModified() >= historyFile.lastModified()) {
|
||||
dirty = true;
|
||||
history.remove(outputName);
|
||||
SourceHistory[] sourceHistories = linkTarget
|
||||
.getSourceHistories(outputDirPath);
|
||||
TargetHistory newHistory = new TargetHistory(linkTarget
|
||||
.getConfiguration().getIdentifier(), outputName, outputFile
|
||||
.lastModified(), sourceHistories);
|
||||
history.put(outputName, newHistory);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user