]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/MakeDeps.java
Removed the output line code to reduce confusion.
[mirror_edk2.git] / Tools / 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.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;
26 import java.util.Set;
27 import java.util.StringTokenizer;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30
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;
39
40 /**
41 Class MakeDeps is used to wrap MakeDeps.exe as an ANT task.
42 **/
43 public class MakeDeps extends Task {
44
45 //
46 // private members, use set/get to access them
47 //
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>();
58
59 public MakeDeps() {
60
61 }
62
63 /**
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.
68
69 @throws BuildException
70 **/
71 public void execute() throws BuildException {
72 ///
73 /// check if the dependency list file is uptodate or not
74 ///
75 if (isUptodate()) {
76 return;
77 }
78
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);
84
85 ///
86 /// compose full tool path
87 ///
88 if (toolPath == null || toolPath.length() == 0) {
89 toolPath = "./" + cmdName;
90 } else {
91 if (toolPath.endsWith("/") || toolPath.endsWith("\\")) {
92 toolPath = toolPath + cmdName;
93 } else {
94 toolPath = toolPath + "/" + cmdName;
95 }
96 }
97
98 ///
99 /// compose tool arguments
100 ///
101 StringBuffer args = new StringBuffer(4096);
102 if (ignoreError) {
103 args.append(" -ignorenotfound");
104 }
105 if (quietMode) {
106 args.append(" -q");
107 }
108 if (subDir != null && subDir.length() > 0) {
109 args.append(" -s ");
110 args.append(subDir);
111 }
112
113 ///
114 /// if there's no source files, we can do nothing about dependency
115 ///
116 if (inputFileList.size() == 0) {
117 throw new BuildException("No source files specified to scan");
118 }
119
120 ///
121 /// compose source file arguments
122 ///
123 Iterator iterator = inputFileList.iterator();
124 while (iterator.hasNext()) {
125 Input inputFile = (Input)iterator.next();
126 String inputFileString = cleanupPathName(inputFile.getFile());
127 args.append(" -f ");
128 args.append(inputFileString);
129 }
130
131 ///
132 /// compose search pathes argument
133 ///
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) {
140 continue;
141 }
142
143 includePathArg.append(" -i ");
144 includePathArg.append(cleanupPathName(tmpPath));
145 }
146 }
147 iterator = includePathList.iterator();
148 while (iterator.hasNext()) {
149 IncludePath path = (IncludePath)iterator.next();
150 includePathArg.append(cleanupPathName(path.getPath()));
151 }
152 args.append(includePathArg);
153
154 ///
155 /// We don't need a real target. So just a "dummy" is given
156 ///
157 args.append(" -target dummy");
158 args.append(" -o ");
159 args.append(cleanupPathName(depsFile));
160
161 ///
162 /// prepare to execute the tool
163 ///
164 Commandline cmd = new Commandline();
165 cmd.setExecutable(toolPath);
166 cmd.createArgument().setLine(args.toString());
167
168 LogStreamHandler streamHandler = new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN);
169 Execute runner = new Execute(streamHandler, null);
170
171 runner.setAntRun(prj);
172 runner.setCommandline(cmd.getCommandline());
173
174 EdkLog.log(EdkLog.EDK_VERBOSE, Commandline.toString(cmd.getCommandline()));
175
176 int result = 0;
177 try {
178 result = runner.execute();
179 } catch (IOException e) {
180 throw new BuildException(e.getMessage());
181 }
182
183 if (result != 0) {
184 EdkLog.log(EdkLog.EDK_INFO, "MakeDeps failed!");
185 return;
186 }
187
188 // change the old DEP file format (makefile compatible) to just file list
189 if (!cleanup()) {
190 throw new BuildException(depsFile + " was not generated");
191 }
192 }
193
194 ///
195 /// Remove any duplicated path separator or inconsistent path separator
196 ///
197 private String cleanupPathName(String path) {
198 try {
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);
205 return path;
206 }
207
208 return path;
209 }
210
211 /**
212 Set method for "DepsFile" attribute
213
214 @param name The name of dependency list file
215 **/
216 public void setDepsFile(String name) {
217 depsFile = cleanupPathName(name);
218 }
219
220 /**
221 Get method for "DepsFile" attribute
222
223 @returns The name of dependency list file
224 **/
225 public String getDepsFile() {
226 return depsFile;
227 }
228
229 /**
230 Set method for "IgnoreError" attribute
231
232 @param ignore flag to control error handling (true/false)
233 **/
234 public void setIgnoreError(boolean ignore) {
235 ignoreError = ignore;
236 }
237
238 /**
239 Get method for "IgnoreError" attribute
240
241 @returns The value of current IgnoreError flag
242 **/
243 public boolean getIgnoreError() {
244 return ignoreError;
245 }
246
247 /**
248 Set method for "QuietMode" attribute
249
250 @param quiet flag to control the output information (true/false)
251 **/
252 public void setQuietMode(boolean quiet) {
253 quietMode = quiet;
254 }
255
256 /**
257 Get method for "QuietMode" attribute
258
259 @returns value of current QuietMode flag
260 **/
261 public boolean getQuietMode() {
262 return quietMode;
263 }
264
265 /**
266 Set method for "SubDir" attribute
267
268 @param dir The name of sub-directory in which source files will be scanned
269 **/
270 public void setSubDir(String dir) {
271 subDir = dir;
272 }
273
274 /**
275 Get method for "SubDir" attribute
276
277 @returns The name of sub-directory
278 **/
279 public String getSubDir() {
280 return subDir;
281 }
282
283 /**
284 Set method for "IncludePath" attribute
285
286 @param path The name of include path
287 **/
288 public void setIncludePath(String path) {
289 includePath = cleanupPathName(path);
290 }
291
292 /**
293 Get method for "IncludePath" attribute
294
295 @returns The name of include path
296 **/
297 public String getIncludePath() {
298 return includePath;
299 }
300
301 /**
302 Set method for "ExtraDeps" attribute
303
304 @param deps The name of dependency file specified separately
305 **/
306 public void setExtraDeps(String deps) {
307 extraDeps = deps;
308 }
309
310 /**
311 Get method for "ExtraDeps" attribute
312
313 @returns The name of dependency file specified separately
314 **/
315 public String getExtraDeps () {
316 return extraDeps;
317 }
318
319 /**
320 Add method for "IncludePath" nested element
321
322 @param path The IncludePath object from nested IncludePath type of element
323 **/
324 public void addIncludepath(IncludePath path) {
325 includePathList.add(path);
326 }
327
328 /**
329 Add method for "Input" nested element
330
331 @param input The Input object from nested Input type of element
332 **/
333 public void addInput(Input inputFile) {
334 inputFileList.add(inputFile);
335 }
336
337 /**
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.
340
341 @returns true if cleaned files is saved successfully
342 @returns false if error occurs in file I/O system
343 **/
344 private boolean cleanup() {
345 File df = new File(depsFile);
346
347 if (!df.exists()) {
348 return false;
349 }
350
351 LineNumberReader lineReader = null;
352 FileReader fileReader = null;
353 Set<String> lineSet = new HashSet<String>(100); // used to remove duplicated lines
354 try {
355 fileReader = new FileReader(df);
356 lineReader = new LineNumberReader(fileReader);
357
358 ///
359 /// clean-up each line in deps file
360 //
361 String line = null;
362 while ((line = lineReader.readLine()) != null) {
363 Pattern pattern = Pattern.compile(target + "[ ]*:[ ]*(.+)");
364 Matcher matcher = pattern.matcher(line);
365
366 while (matcher.find()) {
367 ///
368 /// keep the file name after ":"
369 ///
370 String filePath = line.substring(matcher.start(1), matcher.end(1));
371 filePath = cleanupPathName(filePath);
372 lineSet.add(filePath);
373 }
374 }
375 lineReader.close();
376 fileReader.close();
377
378 ///
379 /// we may have explicitly specified dependency files
380 ///
381 StringTokenizer fileTokens = new StringTokenizer(extraDeps, ";");
382 while (fileTokens.hasMoreTokens()) {
383 lineSet.add(cleanupPathName(fileTokens.nextToken()));
384 }
385
386 ///
387 /// compose the final file content
388 ///
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");
395 }
396 ///
397 /// overwrite old dep file with new content
398 ///
399 FileWriter fileWriter = null;
400 fileWriter = new FileWriter(df);
401 fileWriter.write(cleanedLines.toString());
402 fileWriter.close();
403 } catch (IOException e) {
404 log (e.getMessage());
405 }
406
407 return true;
408 }
409
410 /**
411 Check if the dependency list file should be (re-)generated or not.
412
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.
415 **/
416 private boolean isUptodate() {
417 File df = new File(depsFile);
418 if (!df.exists()) {
419 return false;
420 }
421
422 ///
423 /// If the source file(s) is newer than dependency list file, we need to
424 /// re-generate the dependency list file
425 ///
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) {
432 return false;
433 }
434 }
435
436 ///
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.
441 ///
442 LineNumberReader lineReader = null;
443 FileReader fileReader = null;
444 boolean ret = true;
445 try {
446 fileReader = new FileReader(df);
447 lineReader = new LineNumberReader(fileReader);
448
449 String line = null;
450 while ((line = lineReader.readLine()) != null) {
451 File sourceFile = new File(line);
452 if (sourceFile.lastModified() > depsFileTimeStamp) {
453 ret = false;
454 break;
455 }
456 }
457 lineReader.close();
458 fileReader.close();
459 } catch (IOException e) {
460 log (e.getMessage());
461 }
462
463 return ret;
464 }
465 }
466