mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-04 13:35:48 +01:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			427 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			427 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
/*
 | 
						|
 * 
 | 
						|
 * 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);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |