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