| /* | |
| * | |
| * 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; | |
| /** | |
| * 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; | |
| 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); | |
| public ProcessorConfiguration createConfiguration(CCTask task, | |
| LinkType linkType, ProcessorDef[] baseConfigs, | |
| ProcessorDef specificConfig, TargetDef targetPlatform) { | |
| if (specificConfig == null) { | |
| throw new NullPointerException("specificConfig"); | |
| } | |
| return createConfiguration(task, linkType, baseConfigs, | |
| (CompilerDef) specificConfig, targetPlatform); | |
| } | |
| 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 getOutputFileName(String inputFile) { | |
| // | |
| // if a recognized input file | |
| // | |
| if (bid(inputFile) > 1) { | |
| String baseName = getBaseOutputName(inputFile); | |
| return baseName + outputSuffix; | |
| } | |
| return null; | |
| } | |
| /** | |
| * 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++; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| 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; | |
| } | |
| } |