2 This file is to wrap MakeDeps.exe tool as ANT task, which is used to generate
3 dependency files for source code.
5 Copyright (c) 2006, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 package org
.tianocore
.framework
.tasks
;
18 import java
.io
.FileReader
;
19 import java
.io
.FileWriter
;
20 import java
.io
.IOException
;
21 import java
.io
.LineNumberReader
;
22 import java
.util
.ArrayList
;
23 import java
.util
.HashSet
;
24 import java
.util
.Iterator
;
25 import java
.util
.List
;
27 import java
.util
.StringTokenizer
;
28 import java
.util
.regex
.Matcher
;
29 import java
.util
.regex
.Pattern
;
31 import org
.apache
.tools
.ant
.BuildException
;
32 import org
.apache
.tools
.ant
.Project
;
33 import org
.apache
.tools
.ant
.Task
;
34 import org
.apache
.tools
.ant
.taskdefs
.Execute
;
35 import org
.apache
.tools
.ant
.taskdefs
.LogStreamHandler
;
36 import org
.apache
.tools
.ant
.types
.Commandline
;
37 import org
.apache
.tools
.ant
.types
.Path
;
38 import org
.tianocore
.logger
.EdkLog
;
41 Class MakeDeps is used to wrap MakeDeps.exe as an ANT task.
43 public class MakeDeps
extends Task
{
46 // private members, use set/get to access them
48 private static final String cmdName
= "MakeDeps";
49 private static final String target
= "dummy";
50 private String includePath
= null;
51 private String depsFile
= null;
52 private String subDir
= null;
53 private boolean quietMode
= true;
54 private boolean ignoreError
= true;
55 private String extraDeps
= "";
56 private List
<IncludePath
> includePathList
= new ArrayList
<IncludePath
>();
57 private List
<Input
> inputFileList
= new ArrayList
<Input
>();
64 The Standard execute method for ANT task. It will check if it's necessary
65 to generate the dependency list file. If no file is found or the dependency
66 is changed, it will compose the command line and call MakeDeps.exe to
67 generate the dependency list file.
69 @throws BuildException
71 public void execute() throws BuildException
{
73 /// check if the dependency list file is uptodate or not
79 Project prj
= this.getOwningTarget().getProject();
80 String toolPath
= prj
.getProperty("env.FRAMEWORK_TOOLS_PATH");
81 FrameworkLogger logger
= new FrameworkLogger(prj
, "makedeps");
82 EdkLog
.setLogLevel(prj
.getProperty("env.LOGLEVEL"));
83 EdkLog
.setLogger(logger
);
86 /// compose full tool path
88 if (toolPath
== null || toolPath
.length() == 0) {
89 toolPath
= "./" + cmdName
;
91 if (toolPath
.endsWith("/") || toolPath
.endsWith("\\")) {
92 toolPath
= toolPath
+ cmdName
;
94 toolPath
= toolPath
+ "/" + cmdName
;
99 /// compose tool arguments
101 StringBuffer args
= new StringBuffer(4096);
103 args
.append(" -ignorenotfound");
108 if (subDir
!= null && subDir
.length() > 0) {
114 /// if there's no source files, we can do nothing about dependency
116 if (inputFileList
.size() == 0) {
117 throw new BuildException("No source files specified to scan");
121 /// compose source file arguments
123 Iterator iterator
= inputFileList
.iterator();
124 while (iterator
.hasNext()) {
125 Input inputFile
= (Input
)iterator
.next();
126 String inputFileString
= cleanupPathName(inputFile
.getFile());
128 args
.append(inputFileString
);
132 /// compose search pathes argument
134 StringBuffer includePathArg
= new StringBuffer(4096);
135 if (includePath
!= null && includePath
.length() > 0) {
136 StringTokenizer pathTokens
= new StringTokenizer(includePath
, ";");
137 while (pathTokens
.hasMoreTokens()) {
138 String tmpPath
= pathTokens
.nextToken().trim();
139 if (tmpPath
.length() == 0) {
143 includePathArg
.append(" -i ");
144 includePathArg
.append(cleanupPathName(tmpPath
));
147 iterator
= includePathList
.iterator();
148 while (iterator
.hasNext()) {
149 IncludePath path
= (IncludePath
)iterator
.next();
150 includePathArg
.append(cleanupPathName(path
.getPath()));
152 args
.append(includePathArg
);
155 /// We don't need a real target. So just a "dummy" is given
157 args
.append(" -target dummy");
159 args
.append(cleanupPathName(depsFile
));
162 /// prepare to execute the tool
164 Commandline cmd
= new Commandline();
165 cmd
.setExecutable(toolPath
);
166 cmd
.createArgument().setLine(args
.toString());
168 LogStreamHandler streamHandler
= new LogStreamHandler(this, Project
.MSG_INFO
, Project
.MSG_WARN
);
169 Execute runner
= new Execute(streamHandler
, null);
171 runner
.setAntRun(prj
);
172 runner
.setCommandline(cmd
.getCommandline());
174 EdkLog
.log(EdkLog
.EDK_VERBOSE
, Commandline
.toString(cmd
.getCommandline()));
175 EdkLog
.log(EdkLog
.EDK_INFO
, " ");
179 result
= runner
.execute();
180 } catch (IOException e
) {
181 throw new BuildException(e
.getMessage());
185 EdkLog
.log(EdkLog
.EDK_INFO
, "MakeDeps failed!");
189 // change the old DEP file format (makefile compatible) to just file list
191 throw new BuildException(depsFile
+ " was not generated");
196 /// Remove any duplicated path separator or inconsistent path separator
198 private String
cleanupPathName(String path
) {
200 path
= (new File(path
)).getCanonicalPath();
201 } catch (IOException e
) {
202 String separator
= "\\" + File
.separator
;
203 String duplicateSeparator
= separator
+ "{2}";
204 path
= Path
.translateFile(path
);
205 path
= path
.replaceAll(duplicateSeparator
, separator
);
213 Set method for "DepsFile" attribute
215 @param name The name of dependency list file
217 public void setDepsFile(String name
) {
218 depsFile
= cleanupPathName(name
);
222 Get method for "DepsFile" attribute
224 @returns The name of dependency list file
226 public String
getDepsFile() {
231 Set method for "IgnoreError" attribute
233 @param ignore flag to control error handling (true/false)
235 public void setIgnoreError(boolean ignore
) {
236 ignoreError
= ignore
;
240 Get method for "IgnoreError" attribute
242 @returns The value of current IgnoreError flag
244 public boolean getIgnoreError() {
249 Set method for "QuietMode" attribute
251 @param quiet flag to control the output information (true/false)
253 public void setQuietMode(boolean quiet
) {
258 Get method for "QuietMode" attribute
260 @returns value of current QuietMode flag
262 public boolean getQuietMode() {
267 Set method for "SubDir" attribute
269 @param dir The name of sub-directory in which source files will be scanned
271 public void setSubDir(String dir
) {
276 Get method for "SubDir" attribute
278 @returns The name of sub-directory
280 public String
getSubDir() {
285 Set method for "IncludePath" attribute
287 @param path The name of include path
289 public void setIncludePath(String path
) {
290 includePath
= cleanupPathName(path
);
294 Get method for "IncludePath" attribute
296 @returns The name of include path
298 public String
getIncludePath() {
303 Set method for "ExtraDeps" attribute
305 @param deps The name of dependency file specified separately
307 public void setExtraDeps(String deps
) {
312 Get method for "ExtraDeps" attribute
314 @returns The name of dependency file specified separately
316 public String
getExtraDeps () {
321 Add method for "IncludePath" nested element
323 @param path The IncludePath object from nested IncludePath type of element
325 public void addIncludepath(IncludePath path
) {
326 includePathList
.add(path
);
330 Add method for "Input" nested element
332 @param input The Input object from nested Input type of element
334 public void addInput(Input inputFile
) {
335 inputFileList
.add(inputFile
);
339 The original file generated by MakeDeps.exe is for makefile uses. The target
340 part (before :) is not useful for ANT. This method will do the removal.
342 @returns true if cleaned files is saved successfully
343 @returns false if error occurs in file I/O system
345 private boolean cleanup() {
346 File df
= new File(depsFile
);
352 LineNumberReader lineReader
= null;
353 FileReader fileReader
= null;
354 Set
<String
> lineSet
= new HashSet
<String
>(100); // used to remove duplicated lines
356 fileReader
= new FileReader(df
);
357 lineReader
= new LineNumberReader(fileReader
);
360 /// clean-up each line in deps file
363 while ((line
= lineReader
.readLine()) != null) {
364 Pattern pattern
= Pattern
.compile(target
+ "[ ]*:[ ]*(.+)");
365 Matcher matcher
= pattern
.matcher(line
);
367 while (matcher
.find()) {
369 /// keep the file name after ":"
371 String filePath
= line
.substring(matcher
.start(1), matcher
.end(1));
372 filePath
= cleanupPathName(filePath
);
373 lineSet
.add(filePath
);
380 /// we may have explicitly specified dependency files
382 StringTokenizer fileTokens
= new StringTokenizer(extraDeps
, ";");
383 while (fileTokens
.hasMoreTokens()) {
384 lineSet
.add(cleanupPathName(fileTokens
.nextToken()));
388 /// compose the final file content
390 StringBuffer cleanedLines
= new StringBuffer(40960);
391 Iterator
<String
> it
= lineSet
.iterator();
392 while (it
.hasNext()) {
393 String filePath
= it
.next();
394 cleanedLines
.append(filePath
);
395 cleanedLines
.append("\n");
398 /// overwrite old dep file with new content
400 FileWriter fileWriter
= null;
401 fileWriter
= new FileWriter(df
);
402 fileWriter
.write(cleanedLines
.toString());
404 } catch (IOException e
) {
405 log (e
.getMessage());
412 Check if the dependency list file should be (re-)generated or not.
414 @returns true The dependency list file is uptodate. No re-generation is needed.
415 @returns false The dependency list file is outofdate. Re-generation is needed.
417 private boolean isUptodate() {
418 File df
= new File(depsFile
);
424 /// If the source file(s) is newer than dependency list file, we need to
425 /// re-generate the dependency list file
427 long depsFileTimeStamp
= df
.lastModified();
428 Iterator iterator
= inputFileList
.iterator();
429 while (iterator
.hasNext()) {
430 Input inputFile
= (Input
)iterator
.next();
431 File sf
= new File(inputFile
.getFile());
432 if (sf
.lastModified() > depsFileTimeStamp
) {
438 /// If the source files haven't been changed since last time the dependency
439 /// list file was generated, we need to check each file in the file list to
440 /// see if any of them is changed or not. If anyone of them is newer than
441 /// the dependency list file, MakeDeps.exe is needed to run again.
443 LineNumberReader lineReader
= null;
444 FileReader fileReader
= null;
447 fileReader
= new FileReader(df
);
448 lineReader
= new LineNumberReader(fileReader
);
451 while ((line
= lineReader
.readLine()) != null) {
452 File sourceFile
= new File(line
);
453 if (sourceFile
.lastModified() > depsFileTimeStamp
) {
460 } catch (IOException e
) {
461 log (e
.getMessage());