blob: f16ec6caf3d8ed126c9ecb40f109b4165e655955 [file] [log] [blame]
/*
*
* 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;
}
}