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
;
17 import java
.io
.BufferedReader
;
18 import java
.io
.BufferedWriter
;
20 import java
.io
.FileReader
;
21 import java
.io
.FileWriter
;
22 import java
.io
.IOException
;
23 import java
.io
.LineNumberReader
;
24 import java
.util
.HashMap
;
25 import java
.util
.HashSet
;
26 import java
.util
.Iterator
;
27 import java
.util
.LinkedHashSet
;
28 import java
.util
.List
;
30 import java
.util
.Stack
;
31 import java
.util
.regex
.Matcher
;
32 import java
.util
.regex
.Pattern
;
34 import org
.apache
.tools
.ant
.BuildException
;
35 import org
.apache
.tools
.ant
.Task
;
36 import org
.tianocore
.common
.cache
.FileTimeStamp
;
37 import org
.tianocore
.common
.logger
.EdkLog
;
40 Class MakeDeps is used to wrap MakeDeps.exe as an ANT task.
42 public class MakeDeps
extends Task
{
45 // private members, use set/get to access them
47 private String depsFilePath
= "";
48 private IncludePath includePathList
= new IncludePath();
49 private Input inputFileList
= new Input();
51 // cache the including files to speed up dependency check
53 private static HashMap
<String
, Set
<String
>> includesCache
= new HashMap
<String
, Set
<String
>>();
55 // regular expression for "#include ..." directive
57 private static final Pattern incPattern
= Pattern
.compile("[\n\r \t]*#[ \t]*include[ \t\"<]+([^\n\r\"<>]+)");
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
80 // if no include path is specified, try locally
82 if (includePathList
.isEmpty()) {
83 includePathList
.insPath(".");
86 Set
<String
> depFiles
= getDependencies(inputFileList
.toArray());
88 File depsFile
= new File(depsFilePath
);
89 FileWriter fileWriter
= null;
90 BufferedWriter bufWriter
= null;
93 fileWriter
= new FileWriter(depsFile
);
94 bufWriter
= new BufferedWriter(fileWriter
);
97 for (Iterator it
= depFiles
.iterator(); it
.hasNext();) {
98 String depFile
= (String
)it
.next();
99 bufWriter
.write(depFile
, 0, depFile
.length());
100 bufWriter
.write("\n", 0, 1);
103 // put a "tab" at the end of file as file ending flag
105 bufWriter
.write("\t", 0, 1);
106 } catch (Exception e
) {
107 throw new BuildException(e
.getMessage());
110 if (bufWriter
!= null) {
113 if (fileWriter
!= null) {
116 } catch (Exception e
) {
117 throw new BuildException(e
.getMessage());
122 // update time stamp of dependency file
124 FileTimeStamp
.update(depsFilePath
, depsFile
.lastModified());
128 Set method for "DepsFile" attribute
130 @param name The name of dependency list file
132 public void setDepsFile(String name
) {
137 Get method for "DepsFile" attribute
139 @returns The name of dependency list file
141 public String
getDepsFile() {
146 Add method for "IncludePath" nested element
148 @param path The IncludePath object from nested IncludePath type of element
150 public void addConfiguredIncludepath(IncludePath path
) {
151 includePathList
.insert(path
);
155 Add method for "Input" nested element
157 @param input The Input object from nested Input type of element
159 public void addConfiguredInput(Input inputFile
) {
160 inputFileList
.insert(inputFile
);
164 Check if the dependency list file should be (re-)generated or not.
166 @returns true The dependency list file is uptodate. No re-generation is needed.
167 @returns false The dependency list file is outofdate. Re-generation is needed.
169 private boolean isUptodate() {
170 File df
= new File(depsFilePath
);
172 EdkLog
.log(this, EdkLog
.EDK_VERBOSE
, depsFilePath
+ " doesn't exist!");
177 // If the source file(s) is newer than dependency list file, we need to
178 // re-generate the dependency list file
180 long depsFileTimeStamp
= FileTimeStamp
.get(depsFilePath
);
181 List
<String
> fileList
= inputFileList
.getNameList();
182 for (int i
= 0, length
= fileList
.size(); i
< length
; ++i
) {
183 String sf
= fileList
.get(i
);
184 if (FileTimeStamp
.get(sf
) > depsFileTimeStamp
) {
185 EdkLog
.log(this, EdkLog
.EDK_VERBOSE
, sf
+ " has been changed since last build!");
191 // If the source files haven't been changed since last time the dependency
192 // list file was generated, we need to check each file in the file list to
193 // see if any of them is changed or not. If anyone of them is newer than
194 // the dependency list file, MakeDeps.exe is needed to run again.
196 LineNumberReader lineReader
= null;
197 FileReader fileReader
= null;
200 fileReader
= new FileReader(df
);
201 lineReader
= new LineNumberReader(fileReader
);
205 while ((line
= lineReader
.readLine()) != null) {
207 // check file end flag "\t" to see if the .dep was generated correctly
209 if (line
.equals("\t")) {
217 if (line
.length() == 0) {
223 // If a file cannot be found (moved or removed) or newer, regenerate the dep file
225 File sourceFile
= new File(line
);
226 if ((!sourceFile
.exists()) || (FileTimeStamp
.get(line
) > depsFileTimeStamp
)) {
227 EdkLog
.log(this, EdkLog
.EDK_VERBOSE
, sourceFile
.getPath() + " has been (re)moved or changed since last build!");
234 // check if the .dep file is empty
237 EdkLog
.log(this, EdkLog
.EDK_VERBOSE
, depsFilePath
+ " is empty!");
240 } catch (IOException e
) {
241 throw new BuildException(e
.getMessage());
244 if (lineReader
!= null) {
247 if (fileReader
!= null) {
250 } catch (Exception e
) {
251 throw new BuildException(e
.getMessage());
259 // get dependent files list by parsing "#include" directive
261 private synchronized Set
<String
> getDependencies(String
[] sourceFiles
) {
262 Set
<String
> dependencies
= new LinkedHashSet
<String
>();
263 String
[] searchPathList
= includePathList
.toArray();
265 Stack
<String
> pendingFiles
= new Stack
<String
>();
266 for (int i
= 0; i
< sourceFiles
.length
; ++i
) {
267 File srcFile
= new File(sourceFiles
[i
]);
268 if (srcFile
.exists()) {
270 // a file must depend itself
272 dependencies
.add(srcFile
.getAbsolutePath());
273 pendingFiles
.push(sourceFiles
[i
]);
277 while (!pendingFiles
.empty()) {
278 String src
= pendingFiles
.pop();
279 File srcFile
= new File(src
);
280 if (!srcFile
.exists()) {
287 Set
<String
> incFiles
= includesCache
.get(src
);
288 if (incFiles
== null) {
289 incFiles
= new HashSet
<String
>();
290 FileReader fileReader
= null;
291 BufferedReader bufReader
= null;
292 String fileContent
= "";
293 int fileLength
= (int)srcFile
.length();
296 fileReader
= new FileReader(srcFile
);
297 bufReader
= new BufferedReader(fileReader
);
298 char[] buf
= new char[fileLength
];
300 bufReader
.read(buf
, 0, fileLength
);
301 fileContent
= new String(buf
);
302 } catch (IOException e
) {
303 throw new BuildException(e
.getMessage());
306 if (bufReader
!= null) {
309 if (fileReader
!= null) {
312 } catch (Exception e
) {
313 throw new BuildException(e
.getMessage());
318 // find out all "#include" lines
320 Matcher matcher
= incPattern
.matcher(fileContent
);
321 while (matcher
.find()) {
322 String incFilePath
= fileContent
.substring(matcher
.start(1), matcher
.end(1));
323 incFiles
.add(incFilePath
);
327 // put the includes in cache to avoid re-parsing
329 includesCache
.put(src
, incFiles
);
333 // try each include search path to see if the include file exists or not
335 for (Iterator
<String
> it
= incFiles
.iterator(); it
.hasNext();) {
336 String depFilePath
= it
.next();
338 for (int i
= 0; i
< searchPathList
.length
; ++i
) {
339 File depFile
= new File(searchPathList
[i
] + File
.separator
+ depFilePath
);
340 String filePath
= depFile
.getAbsolutePath();
342 // following check is a must. it can prevent dead loop if two
343 // files include each other
345 if (depFile
.exists() && !dependencies
.contains(filePath
)) {
346 dependencies
.add(filePath
);
347 pendingFiles
.push(filePath
);