Removed the need of external MakeDeps.exe. Now parsing include files is built in makedeps task.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1683 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
@@ -14,11 +14,22 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
**/
|
**/
|
||||||
package org.tianocore.framework.tasks;
|
package org.tianocore.framework.tasks;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.LineNumberReader;
|
import java.io.LineNumberReader;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.Stack;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.apache.tools.ant.BuildException;
|
import org.apache.tools.ant.BuildException;
|
||||||
import org.apache.tools.ant.Project;
|
import org.apache.tools.ant.Project;
|
||||||
@@ -26,9 +37,8 @@ import org.apache.tools.ant.Task;
|
|||||||
import org.apache.tools.ant.taskdefs.Execute;
|
import org.apache.tools.ant.taskdefs.Execute;
|
||||||
import org.apache.tools.ant.taskdefs.LogStreamHandler;
|
import org.apache.tools.ant.taskdefs.LogStreamHandler;
|
||||||
import org.apache.tools.ant.types.Commandline;
|
import org.apache.tools.ant.types.Commandline;
|
||||||
|
|
||||||
import org.tianocore.common.logger.EdkLog;
|
|
||||||
import org.tianocore.common.cache.FileTimeStamp;
|
import org.tianocore.common.cache.FileTimeStamp;
|
||||||
|
import org.tianocore.common.logger.EdkLog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Class MakeDeps is used to wrap MakeDeps.exe as an ANT task.
|
Class MakeDeps is used to wrap MakeDeps.exe as an ANT task.
|
||||||
@@ -38,14 +48,17 @@ public class MakeDeps extends Task {
|
|||||||
//
|
//
|
||||||
// private members, use set/get to access them
|
// private members, use set/get to access them
|
||||||
//
|
//
|
||||||
private static final String toolName = "MakeDeps";
|
private String depsFilePath = "";
|
||||||
private FileArg depsFile = new FileArg();
|
private IncludePath includePathList = new IncludePath();
|
||||||
private ToolArg subDir = new ToolArg();
|
private Input inputFileList = new Input();
|
||||||
private ToolArg quietMode = new ToolArg(" -", "q");
|
//
|
||||||
private ToolArg ignoreError = new ToolArg(" -", "ignorenotfound");
|
// cache the including files to speed up dependency check
|
||||||
private IncludePath includePathList = new IncludePath();
|
//
|
||||||
private Input inputFileList = new Input();
|
private static HashMap<String, Set<String>> includesCache = new HashMap<String, Set<String>>();
|
||||||
private ToolArg target = new FileArg(" -target ", "dummy");
|
//
|
||||||
|
// regular expression for "#include ..." directive
|
||||||
|
//
|
||||||
|
private static final Pattern incPattern = Pattern.compile("[\n\r \t]*#[ \t]*include[ \t\"<]+([^\n\r\"<>]+)");
|
||||||
|
|
||||||
public MakeDeps() {
|
public MakeDeps() {
|
||||||
|
|
||||||
@@ -60,63 +73,59 @@ public class MakeDeps extends Task {
|
|||||||
@throws BuildException
|
@throws BuildException
|
||||||
**/
|
**/
|
||||||
public void execute() throws BuildException {
|
public void execute() throws BuildException {
|
||||||
///
|
//
|
||||||
/// check if the dependency list file is uptodate or not
|
// check if the dependency list file is uptodate or not
|
||||||
///
|
//
|
||||||
if (isUptodate()) {
|
if (isUptodate()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Project prj = this.getOwningTarget().getProject();
|
//
|
||||||
String toolPath = prj.getProperty("env.FRAMEWORK_TOOLS_PATH");
|
// if no include path is specified, try locally
|
||||||
|
//
|
||||||
|
if (includePathList.isEmpty()) {
|
||||||
|
includePathList.insPath(".");
|
||||||
|
}
|
||||||
|
|
||||||
///
|
Set<String> depFiles = getDependencies(inputFileList.toArray());
|
||||||
/// compose full tool path
|
|
||||||
///
|
File depsFile = new File(depsFilePath);
|
||||||
if (toolPath == null || toolPath.length() == 0) {
|
FileWriter fileWriter = null;
|
||||||
toolPath = toolName;
|
BufferedWriter bufWriter = null;
|
||||||
} else {
|
|
||||||
if (toolPath.endsWith("/") || toolPath.endsWith("\\")) {
|
try {
|
||||||
toolPath = toolPath + toolName;
|
fileWriter = new FileWriter(depsFile);
|
||||||
} else {
|
bufWriter = new BufferedWriter(fileWriter);
|
||||||
toolPath = toolPath + File.separator + toolName;
|
|
||||||
|
|
||||||
|
for (Iterator it = depFiles.iterator(); it.hasNext();) {
|
||||||
|
String depFile = (String)it.next();
|
||||||
|
bufWriter.write(depFile, 0, depFile.length());
|
||||||
|
bufWriter.write("\n", 0, 1);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// put a "tab" at the end of file as file ending flag
|
||||||
|
//
|
||||||
|
bufWriter.write("\t", 0, 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new BuildException(e.getMessage());
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (bufWriter != null) {
|
||||||
|
bufWriter.close();
|
||||||
|
}
|
||||||
|
if (fileWriter != null) {
|
||||||
|
fileWriter.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new BuildException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
//
|
||||||
/// compose tool arguments
|
// update time stamp of dependency file
|
||||||
///
|
//
|
||||||
String argument = "" + inputFileList + includePathList + subDir
|
FileTimeStamp.update(depsFilePath, depsFile.lastModified());
|
||||||
+ quietMode + ignoreError + target + depsFile;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// prepare to execute the tool
|
|
||||||
///
|
|
||||||
Commandline cmd = new Commandline();
|
|
||||||
cmd.setExecutable(toolPath);
|
|
||||||
cmd.createArgument().setLine(argument);
|
|
||||||
|
|
||||||
LogStreamHandler streamHandler = new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN);
|
|
||||||
Execute runner = new Execute(streamHandler, null);
|
|
||||||
|
|
||||||
runner.setAntRun(prj);
|
|
||||||
runner.setCommandline(cmd.getCommandline());
|
|
||||||
|
|
||||||
EdkLog.log(this, EdkLog.EDK_VERBOSE, Commandline.toString(cmd.getCommandline()));
|
|
||||||
|
|
||||||
int result = 0;
|
|
||||||
try {
|
|
||||||
result = runner.execute();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new BuildException(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != 0) {
|
|
||||||
EdkLog.log(this, EdkLog.EDK_INFO, toolName + " failed!");
|
|
||||||
throw new BuildException(toolName + ": failed to generate dependency file!");
|
|
||||||
} else {
|
|
||||||
EdkLog.log(this, EdkLog.EDK_VERBOSE, toolName + " succeeded!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,7 +134,7 @@ public class MakeDeps extends Task {
|
|||||||
@param name The name of dependency list file
|
@param name The name of dependency list file
|
||||||
**/
|
**/
|
||||||
public void setDepsFile(String name) {
|
public void setDepsFile(String name) {
|
||||||
depsFile.setArg(" -o ", name);
|
depsFilePath = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,65 +143,7 @@ public class MakeDeps extends Task {
|
|||||||
@returns The name of dependency list file
|
@returns The name of dependency list file
|
||||||
**/
|
**/
|
||||||
public String getDepsFile() {
|
public String getDepsFile() {
|
||||||
return depsFile.getValue();
|
return depsFilePath;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set method for "IgnoreError" attribute
|
|
||||||
|
|
||||||
@param ignore flag to control error handling (true/false)
|
|
||||||
**/
|
|
||||||
public void setIgnoreError(boolean ignore) {
|
|
||||||
if (!ignore) {
|
|
||||||
ignoreError.setArg(" ", " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get method for "IgnoreError" attribute
|
|
||||||
|
|
||||||
@returns The value of current IgnoreError flag
|
|
||||||
**/
|
|
||||||
public boolean getIgnoreError() {
|
|
||||||
return ignoreError.getValue().length() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set method for "QuietMode" attribute
|
|
||||||
|
|
||||||
@param quiet flag to control the output information (true/false)
|
|
||||||
**/
|
|
||||||
public void setQuietMode(boolean quiet) {
|
|
||||||
if (!quiet) {
|
|
||||||
quietMode.setArg(" ", " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get method for "QuietMode" attribute
|
|
||||||
|
|
||||||
@returns value of current QuietMode flag
|
|
||||||
**/
|
|
||||||
public boolean getQuietMode() {
|
|
||||||
return quietMode.getValue().length() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set method for "SubDir" attribute
|
|
||||||
|
|
||||||
@param dir The name of sub-directory in which source files will be scanned
|
|
||||||
**/
|
|
||||||
public void setSubDir(String dir) {
|
|
||||||
subDir.setArg(" -s ", dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get method for "SubDir" attribute
|
|
||||||
|
|
||||||
@returns The name of sub-directory
|
|
||||||
**/
|
|
||||||
public String getSubDir() {
|
|
||||||
return subDir.getValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -220,10 +171,9 @@ public class MakeDeps extends Task {
|
|||||||
@returns false The dependency list file is outofdate. Re-generation is needed.
|
@returns false The dependency list file is outofdate. Re-generation is needed.
|
||||||
**/
|
**/
|
||||||
private boolean isUptodate() {
|
private boolean isUptodate() {
|
||||||
String dfName = depsFile.getValue();
|
File df = new File(depsFilePath);
|
||||||
File df = new File(dfName);
|
|
||||||
if (!df.exists()) {
|
if (!df.exists()) {
|
||||||
EdkLog.log(this, EdkLog.EDK_VERBOSE, dfName + " doesn't exist!");
|
EdkLog.log(this, EdkLog.EDK_VERBOSE, depsFilePath + " doesn't exist!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +181,7 @@ public class MakeDeps extends Task {
|
|||||||
// If the source file(s) is newer than dependency list file, we need to
|
// If the source file(s) is newer than dependency list file, we need to
|
||||||
// re-generate the dependency list file
|
// re-generate the dependency list file
|
||||||
//
|
//
|
||||||
long depsFileTimeStamp = FileTimeStamp.get(dfName);
|
long depsFileTimeStamp = FileTimeStamp.get(depsFilePath);
|
||||||
List<String> fileList = inputFileList.getNameList();
|
List<String> fileList = inputFileList.getNameList();
|
||||||
for (int i = 0, length = fileList.size(); i < length; ++i) {
|
for (int i = 0, length = fileList.size(); i < length; ++i) {
|
||||||
String sf = fileList.get(i);
|
String sf = fileList.get(i);
|
||||||
@@ -288,17 +238,124 @@ public class MakeDeps extends Task {
|
|||||||
// check if the .dep file is empty
|
// check if the .dep file is empty
|
||||||
//
|
//
|
||||||
if (lines == 0) {
|
if (lines == 0) {
|
||||||
EdkLog.log(this, EdkLog.EDK_VERBOSE, dfName + " is empty!");
|
EdkLog.log(this, EdkLog.EDK_VERBOSE, depsFilePath + " is empty!");
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
lineReader.close();
|
|
||||||
fileReader.close();
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new BuildException(e.getMessage());
|
throw new BuildException(e.getMessage());
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (lineReader != null) {
|
||||||
|
lineReader.close();
|
||||||
|
}
|
||||||
|
if (fileReader != null) {
|
||||||
|
fileReader.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new BuildException(e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// get dependent files list by parsing "#include" directive
|
||||||
|
//
|
||||||
|
private synchronized Set<String> getDependencies(String[] sourceFiles) {
|
||||||
|
Set<String> dependencies = new LinkedHashSet<String>();
|
||||||
|
String[] searchPathList = includePathList.toArray();
|
||||||
|
|
||||||
|
Stack<String> pendingFiles = new Stack<String>();
|
||||||
|
for (int i = 0; i < sourceFiles.length; ++i) {
|
||||||
|
File srcFile = new File(sourceFiles[i]);
|
||||||
|
if (srcFile.exists()) {
|
||||||
|
//
|
||||||
|
// a file must depend itself
|
||||||
|
//
|
||||||
|
dependencies.add(srcFile.getAbsolutePath());
|
||||||
|
pendingFiles.push(sourceFiles[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!pendingFiles.empty()) {
|
||||||
|
String src = pendingFiles.pop();
|
||||||
|
File srcFile = new File(src);
|
||||||
|
if (!srcFile.exists()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// try cache first
|
||||||
|
//
|
||||||
|
Set<String> incFiles = includesCache.get(src);
|
||||||
|
if (incFiles == null) {
|
||||||
|
incFiles = new HashSet<String>();
|
||||||
|
FileReader fileReader = null;
|
||||||
|
BufferedReader bufReader = null;
|
||||||
|
String fileContent = "";
|
||||||
|
int fileLength = (int)srcFile.length();
|
||||||
|
|
||||||
|
try {
|
||||||
|
fileReader = new FileReader(srcFile);
|
||||||
|
bufReader = new BufferedReader(fileReader);
|
||||||
|
char[] buf = new char[fileLength];
|
||||||
|
|
||||||
|
bufReader.read(buf, 0, fileLength);
|
||||||
|
fileContent = new String(buf);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new BuildException(e.getMessage());
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (bufReader != null) {
|
||||||
|
bufReader.close();
|
||||||
|
}
|
||||||
|
if (fileReader != null) {
|
||||||
|
fileReader.close();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new BuildException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// find out all "#include" lines
|
||||||
|
//
|
||||||
|
Matcher matcher = incPattern.matcher(fileContent);
|
||||||
|
while (matcher.find()) {
|
||||||
|
String incFilePath = fileContent.substring(matcher.start(1), matcher.end(1));
|
||||||
|
incFiles.add(incFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// put the includes in cache to avoid re-parsing
|
||||||
|
//
|
||||||
|
includesCache.put(src, incFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// try each include search path to see if the include file exists or not
|
||||||
|
//
|
||||||
|
for (Iterator<String> it = incFiles.iterator(); it.hasNext();) {
|
||||||
|
String depFilePath = it.next();
|
||||||
|
|
||||||
|
for (int i = 0; i < searchPathList.length; ++i) {
|
||||||
|
File depFile = new File(searchPathList[i] + File.separator + depFilePath);
|
||||||
|
String filePath = depFile.getAbsolutePath();
|
||||||
|
//
|
||||||
|
// following check is a must. it can prevent dead loop if two
|
||||||
|
// files include each other
|
||||||
|
//
|
||||||
|
if (depFile.exists() && !dependencies.contains(filePath)) {
|
||||||
|
dependencies.add(filePath);
|
||||||
|
pendingFiles.push(filePath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dependencies;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -333,6 +333,24 @@ public class NestElement extends DataType {
|
|||||||
return toFileList(" ");
|
return toFileList(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the array of names
|
||||||
|
|
||||||
|
@return String[] The array contains the names
|
||||||
|
**/
|
||||||
|
public String[] toArray() {
|
||||||
|
return nameList.toArray(new String[nameList.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check if we have any name or not
|
||||||
|
|
||||||
|
@return boolean
|
||||||
|
**/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return nameList.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Remove any duplicated path separator or inconsistent path separator
|
// Remove any duplicated path separator or inconsistent path separator
|
||||||
//
|
//
|
||||||
|
Reference in New Issue
Block a user