/* * * 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.compiler; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.util.Vector; import net.sf.antcontrib.cpptasks.CCTask; import net.sf.antcontrib.cpptasks.CUtil; import net.sf.antcontrib.cpptasks.CompilerDef; import net.sf.antcontrib.cpptasks.DependencyInfo; import net.sf.antcontrib.cpptasks.ProcessorDef; import net.sf.antcontrib.cpptasks.parser.Parser; import net.sf.antcontrib.cpptasks.TargetDef; import net.sf.antcontrib.cpptasks.VersionInfo; /** * An abstract compiler implementation. * * @author Adam Murdoch * @author Curt Arnold */ public abstract class AbstractCompiler extends AbstractProcessor implements Compiler { private static final String[] emptyIncludeArray = new String[0]; private String outputSuffix; private static String outputFilePrefix; protected AbstractCompiler(String[] sourceExtensions, String[] headerExtensions, String outputSuffix) { super(sourceExtensions, headerExtensions); this.outputSuffix = outputSuffix; } /** * Checks file name to see if parse should be attempted * * Default implementation returns false for files with extensions '.dll', * 'tlb', '.res' * */ protected boolean canParse(File sourceFile) { String sourceName = sourceFile.toString(); int lastPeriod = sourceName.lastIndexOf('.'); if (lastPeriod >= 0 && lastPeriod == sourceName.length() - 4) { String ext = sourceName.substring(lastPeriod).toUpperCase(); if (ext.equals(".DLL") || ext.equals(".TLB") || ext.equals(".RES")) { return false; } } return true; } abstract protected CompilerConfiguration createConfiguration(CCTask task, LinkType linkType, ProcessorDef[] baseConfigs, CompilerDef specificConfig, TargetDef targetPlatform, VersionInfo versionInfo); public ProcessorConfiguration createConfiguration(CCTask task, LinkType linkType, ProcessorDef[] baseConfigs, ProcessorDef specificConfig, TargetDef targetPlatform, VersionInfo versionInfo) { if (specificConfig == null) { throw new NullPointerException("specificConfig"); } return createConfiguration(task, linkType, baseConfigs, (CompilerDef) specificConfig, targetPlatform, versionInfo); } abstract protected Parser createParser(File sourceFile); protected String getBaseOutputName(String inputFile) { int lastSlash = inputFile.lastIndexOf('/'); int lastReverse = inputFile.lastIndexOf('\\'); int lastSep = inputFile.lastIndexOf(File.separatorChar); if (lastReverse > lastSlash) { lastSlash = lastReverse; } if (lastSep > lastSlash) { lastSlash = lastSep; } int lastPeriod = inputFile.lastIndexOf('.'); if (lastPeriod < 0) { lastPeriod = inputFile.length(); } return inputFile.substring(lastSlash + 1, lastPeriod); } public String[] getOutputFileNames(String inputFile, VersionInfo versionInfo) { // // if a recognized input file // if (bid(inputFile) > 1) { String baseName = getBaseOutputName(inputFile); return new String[] { baseName + outputSuffix }; } return new String[0]; } /** * Returns dependency info for the specified source file * * @param task * task for any diagnostic output * @param source * file to be parsed * @param includePath * include path to be used to resolve included files * * @param sysIncludePath * sysinclude path from build file, files resolved using * sysInclude path will not participate in dependency analysis * * @param envIncludePath * include path from environment variable, files resolved with * envIncludePath will not participate in dependency analysis * * @param baseDir * used to produce relative paths in DependencyInfo * @param includePathIdentifier * used to distinguish DependencyInfo's from different include * path settings * * @author Curt Arnold */ public final DependencyInfo parseIncludes(CCTask task, File source, File[] includePath, File[] sysIncludePath, File[] envIncludePath, File baseDir, String includePathIdentifier) { // // if any of the include files can not be identified // change the sourceLastModified to Long.MAX_VALUE to // force recompilation of anything that depends on it long sourceLastModified = source.lastModified(); File[] sourcePath = new File[1]; sourcePath[0] = new File(source.getParent()); Vector onIncludePath = new Vector(); Vector onSysIncludePath = new Vector(); String baseDirPath; try { baseDirPath = baseDir.getCanonicalPath(); } catch (IOException ex) { baseDirPath = baseDir.toString(); } String relativeSource = CUtil.getRelativePath(baseDirPath, source); String[] includes = emptyIncludeArray; if (canParse(source)) { Parser parser = createParser(source); try { Reader reader = new BufferedReader(new FileReader(source)); parser.parse(reader); includes = parser.getIncludes(); } catch (IOException ex) { task.log("Error parsing " + source.toString() + ":" + ex.toString()); includes = new String[0]; } } for (int i = 0; i < includes.length; i++) { String includeName = includes[i]; if (!resolveInclude(includeName, sourcePath, onIncludePath)) { if (!resolveInclude(includeName, includePath, onIncludePath)) { if (!resolveInclude(includeName, sysIncludePath, onSysIncludePath)) { if (!resolveInclude(includeName, envIncludePath, onSysIncludePath)) { // // this should be enough to require us to reparse // the file with the missing include for dependency // information without forcing a rebuild sourceLastModified += 2 * CUtil.FILETIME_EPSILON; } } } } } for (int i = 0; i < onIncludePath.size(); i++) { String relativeInclude = CUtil.getRelativePath(baseDirPath, (File) onIncludePath.elementAt(i)); onIncludePath.setElementAt(relativeInclude, i); } for (int i = 0; i < onSysIncludePath.size(); i++) { String relativeInclude = CUtil.getRelativePath(baseDirPath, (File) onSysIncludePath.elementAt(i)); onSysIncludePath.setElementAt(relativeInclude, i); } return new DependencyInfo(includePathIdentifier, relativeSource, sourceLastModified, onIncludePath, onSysIncludePath); } protected boolean resolveInclude(String includeName, File[] includePath, Vector onThisPath) { for (int i = 0; i < includePath.length; i++) { File includeFile = new File(includePath[i], includeName); if (includeFile.exists()) { onThisPath.addElement(includeFile); return true; } } return false; } public void setOutputFilePrefix(String outputFilePrefix){ this.outputFilePrefix = outputFilePrefix; } }