8f5664f01dcee3055c7e6073bbeca4bc3d27bc25
[mirror_edk2.git] / Tools / Java / Source / FrameworkTasks / org / tianocore / framework / tasks / MakeDeps.java
1 /** @file
2 This file is to wrap MakeDeps.exe tool as ANT task, which is used to generate
3 dependency files for source code.
4
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
10
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.
13
14 **/
15 package org.tianocore.framework.tasks;
16
17 import java.io.File;
18 import java.io.FileReader;
19 import java.io.IOException;
20 import java.io.LineNumberReader;
21 import java.util.List;
22
23 import org.apache.tools.ant.BuildException;
24 import org.apache.tools.ant.Project;
25 import org.apache.tools.ant.Task;
26 import org.apache.tools.ant.taskdefs.Execute;
27 import org.apache.tools.ant.taskdefs.LogStreamHandler;
28 import org.apache.tools.ant.types.Commandline;
29
30 import org.tianocore.common.logger.EdkLog;
31 import org.tianocore.common.cache.FileTimeStamp;
32
33 /**
34 Class MakeDeps is used to wrap MakeDeps.exe as an ANT task.
35 **/
36 public class MakeDeps extends Task {
37
38 //
39 // private members, use set/get to access them
40 //
41 private static final String toolName = "MakeDeps";
42 private FileArg depsFile = new FileArg();
43 private ToolArg subDir = new ToolArg();
44 private ToolArg quietMode = new ToolArg(" -", "q");
45 private ToolArg ignoreError = new ToolArg(" -", "ignorenotfound");
46 private IncludePath includePathList = new IncludePath();
47 private Input inputFileList = new Input();
48 private ToolArg target = new FileArg(" -target ", "dummy");
49
50 public MakeDeps() {
51
52 }
53
54 /**
55 The Standard execute method for ANT task. It will check if it's necessary
56 to generate the dependency list file. If no file is found or the dependency
57 is changed, it will compose the command line and call MakeDeps.exe to
58 generate the dependency list file.
59
60 @throws BuildException
61 **/
62 public void execute() throws BuildException {
63 ///
64 /// check if the dependency list file is uptodate or not
65 ///
66 if (isUptodate()) {
67 return;
68 }
69
70 Project prj = this.getOwningTarget().getProject();
71 String toolPath = prj.getProperty("env.FRAMEWORK_TOOLS_PATH");
72
73 ///
74 /// compose full tool path
75 ///
76 if (toolPath == null || toolPath.length() == 0) {
77 toolPath = toolName;
78 } else {
79 if (toolPath.endsWith("/") || toolPath.endsWith("\\")) {
80 toolPath = toolPath + toolName;
81 } else {
82 toolPath = toolPath + File.separator + toolName;
83 }
84 }
85
86 ///
87 /// compose tool arguments
88 ///
89 String argument = "" + inputFileList + includePathList + subDir
90 + quietMode + ignoreError + target + depsFile;
91
92 ///
93 /// prepare to execute the tool
94 ///
95 Commandline cmd = new Commandline();
96 cmd.setExecutable(toolPath);
97 cmd.createArgument().setLine(argument);
98
99 LogStreamHandler streamHandler = new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN);
100 Execute runner = new Execute(streamHandler, null);
101
102 runner.setAntRun(prj);
103 runner.setCommandline(cmd.getCommandline());
104
105 EdkLog.log(this, EdkLog.EDK_VERBOSE, Commandline.toString(cmd.getCommandline()));
106
107 int result = 0;
108 try {
109 result = runner.execute();
110 } catch (IOException e) {
111 throw new BuildException(e.getMessage());
112 }
113
114 if (result != 0) {
115 EdkLog.log(this, EdkLog.EDK_INFO, toolName + " failed!");
116 throw new BuildException(toolName + ": failed to generate dependency file!");
117 } else {
118 EdkLog.log(this, EdkLog.EDK_VERBOSE, toolName + " succeeded!");
119 }
120 }
121
122 /**
123 Set method for "DepsFile" attribute
124
125 @param name The name of dependency list file
126 **/
127 public void setDepsFile(String name) {
128 depsFile.setArg(" -o ", name);
129 }
130
131 /**
132 Get method for "DepsFile" attribute
133
134 @returns The name of dependency list file
135 **/
136 public String getDepsFile() {
137 return depsFile.getValue();
138 }
139
140 /**
141 Set method for "IgnoreError" attribute
142
143 @param ignore flag to control error handling (true/false)
144 **/
145 public void setIgnoreError(boolean ignore) {
146 if (!ignore) {
147 ignoreError.setArg(" ", " ");
148 }
149 }
150
151 /**
152 Get method for "IgnoreError" attribute
153
154 @returns The value of current IgnoreError flag
155 **/
156 public boolean getIgnoreError() {
157 return ignoreError.getValue().length() > 0;
158 }
159
160 /**
161 Set method for "QuietMode" attribute
162
163 @param quiet flag to control the output information (true/false)
164 **/
165 public void setQuietMode(boolean quiet) {
166 if (!quiet) {
167 quietMode.setArg(" ", " ");
168 }
169 }
170
171 /**
172 Get method for "QuietMode" attribute
173
174 @returns value of current QuietMode flag
175 **/
176 public boolean getQuietMode() {
177 return quietMode.getValue().length() > 0;
178 }
179
180 /**
181 Set method for "SubDir" attribute
182
183 @param dir The name of sub-directory in which source files will be scanned
184 **/
185 public void setSubDir(String dir) {
186 subDir.setArg(" -s ", dir);
187 }
188
189 /**
190 Get method for "SubDir" attribute
191
192 @returns The name of sub-directory
193 **/
194 public String getSubDir() {
195 return subDir.getValue();
196 }
197
198 /**
199 Add method for "IncludePath" nested element
200
201 @param path The IncludePath object from nested IncludePath type of element
202 **/
203 public void addConfiguredIncludepath(IncludePath path) {
204 includePathList.insert(path);
205 }
206
207 /**
208 Add method for "Input" nested element
209
210 @param input The Input object from nested Input type of element
211 **/
212 public void addConfiguredInput(Input inputFile) {
213 inputFileList.insert(inputFile);
214 }
215
216 /**
217 Check if the dependency list file should be (re-)generated or not.
218
219 @returns true The dependency list file is uptodate. No re-generation is needed.
220 @returns false The dependency list file is outofdate. Re-generation is needed.
221 **/
222 private boolean isUptodate() {
223 String dfName = depsFile.getValue();
224 File df = new File(dfName);
225 if (!df.exists()) {
226 EdkLog.log(this, EdkLog.EDK_VERBOSE, dfName + " doesn't exist!");
227 return false;
228 }
229
230 //
231 // If the source file(s) is newer than dependency list file, we need to
232 // re-generate the dependency list file
233 //
234 long depsFileTimeStamp = FileTimeStamp.get(dfName);
235 List<String> fileList = inputFileList.getNameList();
236 for (int i = 0, length = fileList.size(); i < length; ++i) {
237 String sf = fileList.get(i);
238 if (FileTimeStamp.get(sf) > depsFileTimeStamp) {
239 EdkLog.log(this, EdkLog.EDK_VERBOSE, sf + " has been changed since last build!");
240 return false;
241 }
242 }
243
244 //
245 // If the source files haven't been changed since last time the dependency
246 // list file was generated, we need to check each file in the file list to
247 // see if any of them is changed or not. If anyone of them is newer than
248 // the dependency list file, MakeDeps.exe is needed to run again.
249 //
250 LineNumberReader lineReader = null;
251 FileReader fileReader = null;
252 boolean ret = false;
253 try {
254 fileReader = new FileReader(df);
255 lineReader = new LineNumberReader(fileReader);
256
257 String line = null;
258 int lines = 0;
259 while ((line = lineReader.readLine()) != null) {
260 //
261 // check file end flag "\t" to see if the .dep was generated correctly
262 //
263 if (line.equals("\t")) {
264 ret = true;
265 continue;
266 }
267 line = line.trim();
268 //
269 // skip empty line
270 //
271 if (line.length() == 0) {
272 continue;
273 }
274 ++lines;
275
276 //
277 // If a file cannot be found (moved or removed) or newer, regenerate the dep file
278 //
279 File sourceFile = new File(line);
280 if ((!sourceFile.exists()) || (FileTimeStamp.get(line) > depsFileTimeStamp)) {
281 EdkLog.log(this, EdkLog.EDK_VERBOSE, sourceFile.getPath() + " has been (re)moved or changed since last build!");
282 ret = false;
283 break;
284 }
285 }
286
287 //
288 // check if the .dep file is empty
289 //
290 if (lines == 0) {
291 EdkLog.log(this, EdkLog.EDK_VERBOSE, dfName + " is empty!");
292 ret = false;
293 }
294
295 lineReader.close();
296 fileReader.close();
297 } catch (IOException e) {
298 throw new BuildException(e.getMessage());
299 }
300
301 return ret;
302 }
303 }
304