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