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()));
178 result
= runner
.execute();
179 } catch (IOException e
) {
180 throw new BuildException(e
.getMessage());
184 EdkLog
.log(EdkLog
.EDK_INFO
, "MakeDeps failed!");
188 // change the old DEP file format (makefile compatible) to just file list
190 throw new BuildException(depsFile
+ " was not generated");
195 /// Remove any duplicated path separator or inconsistent path separator
197 private String
cleanupPathName(String path
) {
199 path
= (new File(path
)).getCanonicalPath();
200 } catch (IOException e
) {
201 String separator
= "\\" + File
.separator
;
202 String duplicateSeparator
= separator
+ "{2}";
203 path
= Path
.translateFile(path
);
204 path
= path
.replaceAll(duplicateSeparator
, separator
);
212 Set method for "DepsFile" attribute
214 @param name The name of dependency list file
216 public void setDepsFile(String name
) {
217 depsFile
= cleanupPathName(name
);
221 Get method for "DepsFile" attribute
223 @returns The name of dependency list file
225 public String
getDepsFile() {
230 Set method for "IgnoreError" attribute
232 @param ignore flag to control error handling (true/false)
234 public void setIgnoreError(boolean ignore
) {
235 ignoreError
= ignore
;
239 Get method for "IgnoreError" attribute
241 @returns The value of current IgnoreError flag
243 public boolean getIgnoreError() {
248 Set method for "QuietMode" attribute
250 @param quiet flag to control the output information (true/false)
252 public void setQuietMode(boolean quiet
) {
257 Get method for "QuietMode" attribute
259 @returns value of current QuietMode flag
261 public boolean getQuietMode() {
266 Set method for "SubDir" attribute
268 @param dir The name of sub-directory in which source files will be scanned
270 public void setSubDir(String dir
) {
275 Get method for "SubDir" attribute
277 @returns The name of sub-directory
279 public String
getSubDir() {
284 Set method for "IncludePath" attribute
286 @param path The name of include path
288 public void setIncludePath(String path
) {
289 includePath
= cleanupPathName(path
);
293 Get method for "IncludePath" attribute
295 @returns The name of include path
297 public String
getIncludePath() {
302 Set method for "ExtraDeps" attribute
304 @param deps The name of dependency file specified separately
306 public void setExtraDeps(String deps
) {
311 Get method for "ExtraDeps" attribute
313 @returns The name of dependency file specified separately
315 public String
getExtraDeps () {
320 Add method for "IncludePath" nested element
322 @param path The IncludePath object from nested IncludePath type of element
324 public void addIncludepath(IncludePath path
) {
325 includePathList
.add(path
);
329 Add method for "Input" nested element
331 @param input The Input object from nested Input type of element
333 public void addInput(Input inputFile
) {
334 inputFileList
.add(inputFile
);
338 The original file generated by MakeDeps.exe is for makefile uses. The target
339 part (before :) is not useful for ANT. This method will do the removal.
341 @returns true if cleaned files is saved successfully
342 @returns false if error occurs in file I/O system
344 private boolean cleanup() {
345 File df
= new File(depsFile
);
351 LineNumberReader lineReader
= null;
352 FileReader fileReader
= null;
353 Set
<String
> lineSet
= new HashSet
<String
>(100); // used to remove duplicated lines
355 fileReader
= new FileReader(df
);
356 lineReader
= new LineNumberReader(fileReader
);
359 /// clean-up each line in deps file
362 while ((line
= lineReader
.readLine()) != null) {
363 Pattern pattern
= Pattern
.compile(target
+ "[ ]*:[ ]*(.+)");
364 Matcher matcher
= pattern
.matcher(line
);
366 while (matcher
.find()) {
368 /// keep the file name after ":"
370 String filePath
= line
.substring(matcher
.start(1), matcher
.end(1));
371 filePath
= cleanupPathName(filePath
);
372 lineSet
.add(filePath
);
379 /// we may have explicitly specified dependency files
381 StringTokenizer fileTokens
= new StringTokenizer(extraDeps
, ";");
382 while (fileTokens
.hasMoreTokens()) {
383 lineSet
.add(cleanupPathName(fileTokens
.nextToken()));
387 /// compose the final file content
389 StringBuffer cleanedLines
= new StringBuffer(40960);
390 Iterator
<String
> it
= lineSet
.iterator();
391 while (it
.hasNext()) {
392 String filePath
= it
.next();
393 cleanedLines
.append(filePath
);
394 cleanedLines
.append("\n");
397 /// overwrite old dep file with new content
399 FileWriter fileWriter
= null;
400 fileWriter
= new FileWriter(df
);
401 fileWriter
.write(cleanedLines
.toString());
403 } catch (IOException e
) {
404 log (e
.getMessage());
411 Check if the dependency list file should be (re-)generated or not.
413 @returns true The dependency list file is uptodate. No re-generation is needed.
414 @returns false The dependency list file is outofdate. Re-generation is needed.
416 private boolean isUptodate() {
417 File df
= new File(depsFile
);
423 /// If the source file(s) is newer than dependency list file, we need to
424 /// re-generate the dependency list file
426 long depsFileTimeStamp
= df
.lastModified();
427 Iterator iterator
= inputFileList
.iterator();
428 while (iterator
.hasNext()) {
429 Input inputFile
= (Input
)iterator
.next();
430 File sf
= new File(inputFile
.getFile());
431 if (sf
.lastModified() > depsFileTimeStamp
) {
437 /// If the source files haven't been changed since last time the dependency
438 /// list file was generated, we need to check each file in the file list to
439 /// see if any of them is changed or not. If anyone of them is newer than
440 /// the dependency list file, MakeDeps.exe is needed to run again.
442 LineNumberReader lineReader
= null;
443 FileReader fileReader
= null;
446 fileReader
= new FileReader(df
);
447 lineReader
= new LineNumberReader(fileReader
);
450 while ((line
= lineReader
.readLine()) != null) {
451 File sourceFile
= new File(line
);
452 if (sourceFile
.lastModified() > depsFileTimeStamp
) {
459 } catch (IOException e
) {
460 log (e
.getMessage());