]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - Tools/Source/FrameworkTasks/org/tianocore/framework/tasks/MakeDeps.java
Fixed EDKT118
[mirror_edk2.git] / Tools / Source / FrameworkTasks / org / tianocore / framework / tasks / MakeDeps.java
... / ...
CommitLineData
1/** @file\r
2This file is to wrap MakeDeps.exe tool as ANT task, which is used to generate\r
3dependency files for source code.\r
4\r
5Copyright (c) 2006, Intel Corporation\r
6All rights reserved. This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15package org.tianocore.framework.tasks;\r
16\r
17import java.io.File;\r
18import java.io.FileReader;\r
19import java.io.FileWriter;\r
20import java.io.IOException;\r
21import java.io.LineNumberReader;\r
22import java.util.ArrayList;\r
23import java.util.HashSet;\r
24import java.util.Iterator;\r
25import java.util.List;\r
26import java.util.Set;\r
27import java.util.StringTokenizer;\r
28import java.util.regex.Matcher;\r
29import java.util.regex.Pattern;\r
30\r
31import org.apache.tools.ant.BuildException;\r
32import org.apache.tools.ant.Project;\r
33import org.apache.tools.ant.Task;\r
34import org.apache.tools.ant.taskdefs.Execute;\r
35import org.apache.tools.ant.taskdefs.LogStreamHandler;\r
36import org.apache.tools.ant.types.Commandline;\r
37import org.apache.tools.ant.types.Path;\r
38import org.tianocore.logger.EdkLog;\r
39\r
40/**\r
41 Class MakeDeps is used to wrap MakeDeps.exe as an ANT task.\r
42 **/\r
43public class MakeDeps extends Task {\r
44\r
45 //\r
46 // private members, use set/get to access them\r
47 //\r
48 private static final String cmdName = "MakeDeps";\r
49 private static final String target = "dummy";\r
50 private String includePath = null;\r
51 private String depsFile = null;\r
52 private String subDir = null;\r
53 private boolean quietMode = true;\r
54 private boolean ignoreError = true;\r
55 private String extraDeps = "";\r
56 private List<IncludePath> includePathList = new ArrayList<IncludePath>();\r
57 private List<Input> inputFileList = new ArrayList<Input>();\r
58\r
59 public MakeDeps() {\r
60\r
61 }\r
62\r
63 /**\r
64 The Standard execute method for ANT task. It will check if it's necessary\r
65 to generate the dependency list file. If no file is found or the dependency\r
66 is changed, it will compose the command line and call MakeDeps.exe to\r
67 generate the dependency list file.\r
68\r
69 @throws BuildException\r
70 **/\r
71 public void execute() throws BuildException {\r
72 ///\r
73 /// check if the dependency list file is uptodate or not\r
74 ///\r
75 if (isUptodate()) {\r
76 return;\r
77 }\r
78\r
79 Project prj = this.getOwningTarget().getProject();\r
80 String toolPath = prj.getProperty("env.FRAMEWORK_TOOLS_PATH");\r
81 FrameworkLogger logger = new FrameworkLogger(prj, "makedeps");\r
82 EdkLog.setLogLevel(prj.getProperty("env.LOGLEVEL"));\r
83 EdkLog.setLogger(logger);\r
84\r
85 ///\r
86 /// compose full tool path\r
87 ///\r
88 if (toolPath == null || toolPath.length() == 0) {\r
89 toolPath = "./" + cmdName;\r
90 } else {\r
91 if (toolPath.endsWith("/") || toolPath.endsWith("\\")) {\r
92 toolPath = toolPath + cmdName;\r
93 } else {\r
94 toolPath = toolPath + "/" + cmdName;\r
95 }\r
96 }\r
97\r
98 ///\r
99 /// compose tool arguments\r
100 ///\r
101 StringBuffer args = new StringBuffer(4096);\r
102 if (ignoreError) {\r
103 args.append(" -ignorenotfound");\r
104 }\r
105 if (quietMode) {\r
106 args.append(" -q");\r
107 }\r
108 if (subDir != null && subDir.length() > 0) {\r
109 args.append(" -s ");\r
110 args.append(subDir);\r
111 }\r
112\r
113 ///\r
114 /// if there's no source files, we can do nothing about dependency\r
115 /// \r
116 if (inputFileList.size() == 0) {\r
117 throw new BuildException("No source files specified to scan");\r
118 }\r
119\r
120 ///\r
121 /// compose source file arguments\r
122 ///\r
123 Iterator iterator = inputFileList.iterator();\r
124 while (iterator.hasNext()) {\r
125 Input inputFile = (Input)iterator.next();\r
126 String inputFileString = cleanupPathName(inputFile.getFile());\r
127 args.append(" -f ");\r
128 args.append(inputFileString);\r
129 }\r
130\r
131 ///\r
132 /// compose search pathes argument\r
133 ///\r
134 StringBuffer includePathArg = new StringBuffer(4096);\r
135 if (includePath != null && includePath.length() > 0) {\r
136 StringTokenizer pathTokens = new StringTokenizer(includePath, ";");\r
137 while (pathTokens.hasMoreTokens()) {\r
138 String tmpPath = pathTokens.nextToken().trim();\r
139 if (tmpPath.length() == 0) {\r
140 continue;\r
141 }\r
142\r
143 includePathArg.append(" -i ");\r
144 includePathArg.append(cleanupPathName(tmpPath));\r
145 }\r
146 }\r
147 iterator = includePathList.iterator();\r
148 while (iterator.hasNext()) {\r
149 IncludePath path = (IncludePath)iterator.next();\r
150 includePathArg.append(cleanupPathName(path.getPath()));\r
151 }\r
152 args.append(includePathArg);\r
153\r
154 ///\r
155 /// We don't need a real target. So just a "dummy" is given\r
156 ///\r
157 args.append(" -target dummy");\r
158 args.append(" -o ");\r
159 args.append(cleanupPathName(depsFile));\r
160\r
161 ///\r
162 /// prepare to execute the tool\r
163 ///\r
164 Commandline cmd = new Commandline();\r
165 cmd.setExecutable(toolPath);\r
166 cmd.createArgument().setLine(args.toString());\r
167\r
168 LogStreamHandler streamHandler = new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN);\r
169 Execute runner = new Execute(streamHandler, null);\r
170\r
171 runner.setAntRun(prj);\r
172 runner.setCommandline(cmd.getCommandline());\r
173\r
174 EdkLog.log(EdkLog.EDK_VERBOSE, Commandline.toString(cmd.getCommandline()));\r
175\r
176 int result = 0;\r
177 try {\r
178 result = runner.execute();\r
179 } catch (IOException e) {\r
180 throw new BuildException(e.getMessage());\r
181 }\r
182\r
183 if (result != 0) {\r
184 EdkLog.log(EdkLog.EDK_INFO, "MakeDeps failed!");\r
185 return;\r
186 }\r
187\r
188 // change the old DEP file format (makefile compatible) to just file list\r
189 if (!cleanup()) {\r
190 throw new BuildException(depsFile + " was not generated");\r
191 }\r
192 }\r
193\r
194 ///\r
195 /// Remove any duplicated path separator or inconsistent path separator\r
196 ///\r
197 private String cleanupPathName(String path) {\r
198 String separator = "\\" + File.separator;\r
199 String duplicateSeparator = separator + "{2}";\r
200 path = Path.translateFile(path);\r
201 path = path.replaceAll(duplicateSeparator, separator);\r
202 return path;\r
203 }\r
204\r
205 /**\r
206 Set method for "DepsFile" attribute\r
207\r
208 @param name The name of dependency list file\r
209 **/\r
210 public void setDepsFile(String name) {\r
211 depsFile = cleanupPathName(name);\r
212 }\r
213\r
214 /**\r
215 Get method for "DepsFile" attribute\r
216\r
217 @returns The name of dependency list file\r
218 **/\r
219 public String getDepsFile() {\r
220 return depsFile;\r
221 }\r
222\r
223 /**\r
224 Set method for "IgnoreError" attribute\r
225\r
226 @param ignore flag to control error handling (true/false)\r
227 **/\r
228 public void setIgnoreError(boolean ignore) {\r
229 ignoreError = ignore;\r
230 }\r
231\r
232 /**\r
233 Get method for "IgnoreError" attribute\r
234\r
235 @returns The value of current IgnoreError flag\r
236 **/\r
237 public boolean getIgnoreError() {\r
238 return ignoreError;\r
239 }\r
240\r
241 /**\r
242 Set method for "QuietMode" attribute\r
243\r
244 @param quiet flag to control the output information (true/false)\r
245 **/\r
246 public void setQuietMode(boolean quiet) {\r
247 quietMode = quiet;\r
248 }\r
249\r
250 /**\r
251 Get method for "QuietMode" attribute\r
252\r
253 @returns value of current QuietMode flag\r
254 **/\r
255 public boolean getQuietMode() {\r
256 return quietMode;\r
257 }\r
258\r
259 /**\r
260 Set method for "SubDir" attribute\r
261\r
262 @param dir The name of sub-directory in which source files will be scanned\r
263 **/\r
264 public void setSubDir(String dir) {\r
265 subDir = dir;\r
266 }\r
267\r
268 /**\r
269 Get method for "SubDir" attribute\r
270\r
271 @returns The name of sub-directory\r
272 **/\r
273 public String getSubDir() {\r
274 return subDir;\r
275 }\r
276\r
277 /**\r
278 Set method for "IncludePath" attribute\r
279\r
280 @param path The name of include path\r
281 **/\r
282 public void setIncludePath(String path) {\r
283 includePath = cleanupPathName(path);\r
284 }\r
285\r
286 /**\r
287 Get method for "IncludePath" attribute\r
288\r
289 @returns The name of include path\r
290 **/\r
291 public String getIncludePath() {\r
292 return includePath;\r
293 }\r
294\r
295 /**\r
296 Set method for "ExtraDeps" attribute\r
297\r
298 @param deps The name of dependency file specified separately\r
299 **/\r
300 public void setExtraDeps(String deps) {\r
301 extraDeps = deps;\r
302 }\r
303\r
304 /**\r
305 Get method for "ExtraDeps" attribute\r
306\r
307 @returns The name of dependency file specified separately\r
308 **/\r
309 public String getExtraDeps () {\r
310 return extraDeps;\r
311 }\r
312\r
313 /**\r
314 Add method for "IncludePath" nested element\r
315\r
316 @param path The IncludePath object from nested IncludePath type of element\r
317 **/\r
318 public void addIncludepath(IncludePath path) {\r
319 includePathList.add(path);\r
320 }\r
321\r
322 /**\r
323 Add method for "Input" nested element\r
324\r
325 @param input The Input object from nested Input type of element\r
326 **/\r
327 public void addInput(Input inputFile) {\r
328 inputFileList.add(inputFile);\r
329 }\r
330\r
331 /**\r
332 The original file generated by MakeDeps.exe is for makefile uses. The target\r
333 part (before :) is not useful for ANT. This method will do the removal.\r
334\r
335 @returns true if cleaned files is saved successfully\r
336 @returns false if error occurs in file I/O system\r
337 **/\r
338 private boolean cleanup() {\r
339 File df = new File(depsFile);\r
340\r
341 if (!df.exists()) {\r
342 return false;\r
343 }\r
344\r
345 LineNumberReader lineReader = null;\r
346 FileReader fileReader = null;\r
347 Set<String> lineSet = new HashSet<String>(100); // used to remove duplicated lines\r
348 try {\r
349 fileReader = new FileReader(df);\r
350 lineReader = new LineNumberReader(fileReader);\r
351\r
352 ///\r
353 /// clean-up each line in deps file\r
354 //\r
355 String line = null;\r
356 while ((line = lineReader.readLine()) != null) {\r
357 Pattern pattern = Pattern.compile(target + "[ ]*:[ ]*(.+)");\r
358 Matcher matcher = pattern.matcher(line);\r
359\r
360 while (matcher.find()) {\r
361 ///\r
362 /// keep the file name after ":"\r
363 ///\r
364 String filePath = line.substring(matcher.start(1), matcher.end(1));\r
365 filePath = cleanupPathName(filePath);\r
366 lineSet.add(filePath);\r
367 }\r
368 }\r
369 lineReader.close();\r
370 fileReader.close();\r
371\r
372 ///\r
373 /// we may have explicitly specified dependency files\r
374 ///\r
375 StringTokenizer fileTokens = new StringTokenizer(extraDeps, ";");\r
376 while (fileTokens.hasMoreTokens()) {\r
377 lineSet.add(cleanupPathName(fileTokens.nextToken()));\r
378 }\r
379\r
380 ///\r
381 /// compose the final file content\r
382 /// \r
383 StringBuffer cleanedLines = new StringBuffer(40960);\r
384 Iterator<String> it = lineSet.iterator();\r
385 while (it.hasNext()) {\r
386 String filePath = it.next();\r
387 cleanedLines.append(filePath);\r
388 cleanedLines.append("\n");\r
389 }\r
390 ///\r
391 /// overwrite old dep file with new content\r
392 ///\r
393 FileWriter fileWriter = null;\r
394 fileWriter = new FileWriter(df);\r
395 fileWriter.write(cleanedLines.toString());\r
396 fileWriter.close();\r
397 } catch (IOException e) {\r
398 log (e.getMessage());\r
399 }\r
400\r
401 return true;\r
402 }\r
403\r
404 /**\r
405 Check if the dependency list file should be (re-)generated or not.\r
406\r
407 @returns true The dependency list file is uptodate. No re-generation is needed.\r
408 @returns false The dependency list file is outofdate. Re-generation is needed.\r
409 **/\r
410 private boolean isUptodate() {\r
411 File df = new File(depsFile);\r
412 if (!df.exists()) {\r
413 return false;\r
414 }\r
415\r
416 ///\r
417 /// If the source file(s) is newer than dependency list file, we need to\r
418 /// re-generate the dependency list file\r
419 ///\r
420 long depsFileTimeStamp = df.lastModified();\r
421 Iterator iterator = inputFileList.iterator();\r
422 while (iterator.hasNext()) {\r
423 Input inputFile = (Input)iterator.next();\r
424 File sf = new File(inputFile.getFile());\r
425 if (sf.lastModified() > depsFileTimeStamp) {\r
426 return false;\r
427 }\r
428 }\r
429\r
430 ///\r
431 /// If the source files haven't been changed since last time the dependency\r
432 /// list file was generated, we need to check each file in the file list to\r
433 /// see if any of them is changed or not. If anyone of them is newer than\r
434 /// the dependency list file, MakeDeps.exe is needed to run again.\r
435 ///\r
436 LineNumberReader lineReader = null;\r
437 FileReader fileReader = null;\r
438 boolean ret = true;\r
439 try {\r
440 fileReader = new FileReader(df);\r
441 lineReader = new LineNumberReader(fileReader);\r
442\r
443 String line = null;\r
444 while ((line = lineReader.readLine()) != null) {\r
445 File sourceFile = new File(line);\r
446 if (sourceFile.lastModified() > depsFileTimeStamp) {\r
447 ret = false;\r
448 break;\r
449 }\r
450 }\r
451 lineReader.close();\r
452 fileReader.close();\r
453 } catch (IOException e) {\r
454 log (e.getMessage());\r
455 }\r
456\r
457 return ret;\r
458 }\r
459}\r
460\r