e240150c29c471bc42f1ce79686e42842d80f8d2
[people/mcb30/edk2.git] / edk2 / Tools / Java / Source / GenBuild / org / tianocore / build / FrameworkBuildTask.java
1 /** @file FrameworkBuildTask.java\r
2   \r
3   The file is ANT task to find MSA or FPD file and build them. \r
4  \r
5  Copyright (c) 2006, Intel Corporation\r
6  All rights reserved. This program and the accompanying materials\r
7  are licensed and made available under the terms and conditions of the BSD License\r
8  which accompanies this distribution.  The full text of the license may be found at\r
9  http://opensource.org/licenses/bsd-license.php\r
10 \r
11  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13  **/\r
14 package org.tianocore.build;\r
15 \r
16 import java.io.File;\r
17 import java.io.IOException;\r
18 import java.util.Hashtable;\r
19 import java.util.Iterator;\r
20 import java.util.LinkedHashSet;\r
21 import java.util.Map;\r
22 import java.util.Set;\r
23 \r
24 import org.apache.tools.ant.BuildException;\r
25 import org.apache.tools.ant.Task;\r
26 import org.tianocore.build.exception.AutoGenException;\r
27 import org.tianocore.build.exception.GenBuildException;\r
28 import org.tianocore.build.exception.PcdAutogenException;\r
29 import org.tianocore.build.exception.PlatformPcdPreprocessBuildException;\r
30 import org.tianocore.build.fpd.FpdParserForThread;\r
31 import org.tianocore.build.fpd.FpdParserTask;\r
32 import org.tianocore.build.global.GenBuildLogger;\r
33 import org.tianocore.build.global.GlobalData;\r
34 import org.tianocore.build.toolchain.ConfigReader;\r
35 import org.tianocore.build.toolchain.ToolChainInfo;\r
36 import org.tianocore.common.definitions.ToolDefinitions;\r
37 import org.tianocore.common.exception.EdkException;\r
38 import org.tianocore.common.logger.EdkLog;\r
39 \r
40 /**\r
41   <p>\r
42   <code>FrameworkBuildTask</code> is an Ant task. The main function is finding\r
43   and processing a FPD or MSA file, then building a platform or stand-alone \r
44   module. \r
45   \r
46   <p>\r
47   The task search current directory and find out all MSA and FPD files by file\r
48   extension. Base on ACTIVE_PLATFORM policy, decide to build a platform or a\r
49   stand-alone module. The ACTIVE_PLATFORM policy is: \r
50   \r
51   <pre>\r
52   1. More than one MSA files, report error; \r
53   2. Only one MSA file, but ACTIVE_PLATFORM is not specified, report error;\r
54   3. Only one MSA file, and ACTIVE_PLATFORM is also specified, build this module;\r
55   4. No MSA file, and ACTIVE_PLATFORM is specified, build the active platform;\r
56   5. No MSA file, no ACTIVE_PLATFORM, and no FPD file, report error;\r
57   6. No MSA file, no ACTIVE_PLATFORM, and only one FPD file, build the platform;\r
58   7. No MSA file, no ACTIVE_PLATFORM, and more than one FPD files, Report Error!\r
59   </pre>\r
60   \r
61   <p>\r
62   Framework build task also parse target file [${WORKSPACE_DIR}/Tools/Conf/target.txt].\r
63   And load all system environment variables to Ant properties.  \r
64   \r
65   <p>\r
66   The usage for this task is : \r
67   \r
68   <pre>\r
69   &lt;FrameworkBuild type="cleanall" /&gt;\r
70   </pre>\r
71   \r
72   @since GenBuild 1.0\r
73 **/\r
74 public class FrameworkBuildTask extends Task{\r
75 \r
76     private Set<File> fpdFiles = new LinkedHashSet<File>();\r
77     \r
78     private Set<File> msaFiles = new LinkedHashSet<File>();\r
79     \r
80     ///\r
81     /// This is only for none-multi-thread build to reduce overriding message\r
82     ///\r
83     public static Hashtable<String, String> originalProperties = new Hashtable<String, String>();\r
84     \r
85     String toolsDefFilename = ToolDefinitions.DEFAULT_TOOLS_DEF_FILE_PATH;\r
86     \r
87     String targetFilename = ToolDefinitions.TARGET_FILE_PATH;\r
88     \r
89     String dbFilename = ToolDefinitions.FRAMEWORK_DATABASE_FILE_PATH;\r
90     \r
91     String activePlatform = null;\r
92 \r
93     ///\r
94     /// The flag to present current is multi-thread enabled\r
95     ///\r
96     public static boolean multithread = false;\r
97 \r
98     ///\r
99     /// The concurrent thread number\r
100     ///\r
101     public static int MAX_CONCURRENT_THREAD_NUMBER = 2;\r
102 \r
103     ///\r
104     /// there are three type: all (build), clean and cleanall\r
105     ///\r
106     private String type = "all";\r
107     \r
108     public void execute() throws BuildException {\r
109         //\r
110         // set Logger\r
111         //\r
112         GenBuildLogger logger = new GenBuildLogger(getProject());\r
113         EdkLog.setLogLevel(EdkLog.EDK_DEBUG);\r
114         EdkLog.setLogLevel(getProject().getProperty("env.LOGLEVEL"));\r
115         EdkLog.setLogger(logger);\r
116         \r
117         try {\r
118             processFrameworkBuild();\r
119         }catch (BuildException e) {\r
120             //\r
121             // Add more logic process here\r
122             //\r
123             throw new BuildException(e.getMessage());\r
124         } catch (PcdAutogenException e) {\r
125             //\r
126             // Add more logic process here\r
127             //\r
128             throw new BuildException(e.getMessage());\r
129         } catch (AutoGenException e) {\r
130             //\r
131             // Add more logic process here\r
132             //\r
133             throw new BuildException(e.getMessage());\r
134         } catch (PlatformPcdPreprocessBuildException e) {\r
135             //\r
136             // Add more logic process here\r
137             //\r
138             throw new BuildException(e.getMessage());\r
139         } catch (GenBuildException e) {\r
140             //\r
141             // Add more logic process here\r
142             //\r
143             throw new BuildException(e.getMessage());\r
144         } catch (EdkException e) {\r
145             //\r
146             // Add more logic process here\r
147             //\r
148             throw new BuildException(e.getMessage());\r
149         }\r
150     }\r
151     \r
152     private void processFrameworkBuild() throws EdkException, GenBuildException, AutoGenException, PcdAutogenException, PlatformPcdPreprocessBuildException {\r
153         try {\r
154             //\r
155             // Get current working dir\r
156             //\r
157             File dummyFile = new File(".");\r
158             File cwd = dummyFile.getCanonicalFile();\r
159             File[] files = cwd.listFiles();\r
160             \r
161             //\r
162             // Scan current dir, and find out all .FPD and .MSA files\r
163             //\r
164             for (int i = 0; i < files.length; i++) {\r
165                 if (files[i].isFile()) {\r
166                     if (files[i].getName().endsWith(ToolDefinitions.FPD_EXTENSION)) {\r
167                         //\r
168                         // Found FPD file\r
169                         //\r
170                         fpdFiles.add(files[i]);\r
171                     } else if (files[i].getName().endsWith(ToolDefinitions.MSA_EXTENSION)) {\r
172                         //\r
173                         // Found MSA file\r
174                         //\r
175                         msaFiles.add(files[i]);\r
176                     }\r
177                 }\r
178             }\r
179         } catch (IOException ex) {\r
180             BuildException buildException = new BuildException("Scanning current directory error. \n" + ex.getMessage());\r
181             buildException.setStackTrace(ex.getStackTrace());\r
182             throw buildException;\r
183         }\r
184         \r
185         //\r
186         // Import all system environment variables to ANT properties\r
187         //\r
188         importSystemEnvVariables();\r
189         \r
190         //\r
191         // Read target.txt file\r
192         //\r
193         readTargetFile();\r
194 \r
195         //\r
196         // Global Data initialization\r
197         //\r
198         File workspacePath = new File(getProject().getProperty("WORKSPACE"));\r
199         getProject().setProperty("WORKSPACE_DIR", workspacePath.getPath().replaceAll("(\\\\)", "/"));\r
200         GlobalData.initInfo(getProject(), dbFilename, workspacePath.getPath(), toolsDefFilename);\r
201         \r
202         //\r
203         // If find MSA file and ACTIVE_PLATFORM is set, build the module; \r
204         // else fail build. \r
205         // If without MSA file, and ACTIVE_PLATFORM is set, build the ACTIVE_PLATFORM. \r
206         // If ACTIVE_PLATFORM is not set, and only find one FPD file, build the platform; \r
207         // If find more than one FPD files, report error.  \r
208         //\r
209         File buildFile = null;\r
210         if (msaFiles.size() > 0) {\r
211             if (activePlatform == null) {\r
212                 throw new BuildException("If trying to build a single module, please set ACTIVE_PLATFORM in file [" + targetFilename + "]. ");\r
213             }\r
214             //\r
215             // Build the single module\r
216             //\r
217             buildFile = msaFiles.toArray(new File[1])[0];\r
218         } else if (activePlatform != null) {\r
219             buildFile = new File(GlobalData.getWorkspacePath() + File.separatorChar + activePlatform);\r
220         } else if (fpdFiles.size() == 1) {\r
221             buildFile = fpdFiles.toArray(new File[1])[0];\r
222         } else if (fpdFiles.size() > 1) {\r
223             throw new BuildException("Found " + fpdFiles.size() + " FPD files in current dir. ");\r
224         }\r
225         \r
226         //\r
227         // If there is no build files or FPD files or MSA files, stop build\r
228         //\r
229         else {\r
230             throw new BuildException("Can't find any FPD or MSA files in the current directory. ");\r
231         }\r
232 \r
233         //\r
234         // Build every FPD files (PLATFORM build)\r
235         //\r
236         if (buildFile.getName().endsWith(ToolDefinitions.FPD_EXTENSION)) {\r
237             EdkLog.log(this, "Processing the FPD file [" + buildFile.getPath() + "] ..>> ");\r
238             //\r
239             // Iff for platform build will enable the multi-thread if set in target.txt\r
240             //\r
241             if (multithread && type.equalsIgnoreCase("all")) {\r
242                 EdkLog.log(this, "Multi-thread build is enabled. ");\r
243                 FpdParserForThread fpdParserForThread = new FpdParserForThread();\r
244                 fpdParserForThread.setType(type);\r
245                 fpdParserForThread.setProject(getProject());\r
246                 fpdParserForThread.setFpdFile(buildFile);\r
247                 fpdParserForThread.perform();\r
248                 return ;\r
249             }\r
250             \r
251             FpdParserTask fpdParserTask = new FpdParserTask();\r
252             fpdParserTask.setType(type);\r
253             fpdParserTask.setProject(getProject());\r
254             fpdParserTask.setFpdFile(buildFile);\r
255             fpdParserTask.perform();\r
256             \r
257             //\r
258             // If cleanall delete the Platform_build.xml\r
259             //\r
260             if (type.compareTo("cleanall") == 0) {\r
261                 File platformBuildFile = \r
262                     new File(getProject().getProperty("BUILD_DIR") \r
263                                     + File.separatorChar \r
264                                     + getProject().getProperty("PLATFORM") \r
265                                     + "_build.xml");\r
266                 platformBuildFile.deleteOnExit();\r
267             }\r
268         }\r
269         \r
270         //\r
271         // Build every MSA files (SINGLE MODULE BUILD)\r
272         //\r
273         else if (buildFile.getName().endsWith(ToolDefinitions.MSA_EXTENSION)) {\r
274             if (multithread) {\r
275                 EdkLog.log(this, EdkLog.EDK_WARNING, "Multi-Thead do not take effect on Stand-Alone (Single) module build. ");\r
276                 multithread = false;\r
277             }\r
278             File tmpFile = new File(GlobalData.getWorkspacePath() + File.separatorChar + activePlatform);\r
279             EdkLog.log(this, "Using the FPD file [" + tmpFile.getPath() + "] for the active platform. ");\r
280 \r
281             File[] moduleFiles = msaFiles.toArray(new File[msaFiles.size()]);\r
282             for (int i = 0; i < moduleFiles.length; ++i) {\r
283                 EdkLog.log(this, "Processing the MSA file [" + moduleFiles[i].getPath() + "] ..>> ");\r
284                 GenBuildTask genBuildTask = new GenBuildTask();\r
285                 genBuildTask.setSingleModuleBuild(true);\r
286                 genBuildTask.setType(type);\r
287                 getProject().setProperty("PLATFORM_FILE", activePlatform);\r
288                 if( !multithread) {\r
289                     originalProperties.put("PLATFORM_FILE", activePlatform);\r
290                 }\r
291                 genBuildTask.setProject(getProject());\r
292                 genBuildTask.setMsaFile(moduleFiles[i]);\r
293                 genBuildTask.perform();\r
294             }\r
295         }\r
296     }\r
297     \r
298     /**\r
299       Import system environment variables to ANT properties. If system variable \r
300       already exiests in ANT properties, skip it.\r
301       \r
302     **/\r
303     private void importSystemEnvVariables() {\r
304         Map<String, String> sysProperties = System.getenv();\r
305         Iterator<String> iter = sysProperties.keySet().iterator();\r
306         while (iter.hasNext()) {\r
307             String name = iter.next();\r
308             \r
309             //\r
310             // If system environment variable is not in ANT properties, add it\r
311             //\r
312             if (getProject().getProperty(name) == null) {\r
313                 getProject().setProperty(name, sysProperties.get(name));\r
314             }\r
315         }\r
316         \r
317         Hashtable allProperties = getProject().getProperties();\r
318         Iterator piter = allProperties.keySet().iterator();\r
319         while (piter.hasNext()) {\r
320             String name = (String)piter.next();\r
321             originalProperties.put(new String(name), new String((String)allProperties.get(name)));\r
322         }\r
323     }\r
324 \r
325     public void setType(String type) {\r
326         if (type.equalsIgnoreCase("clean") || type.equalsIgnoreCase("cleanall")) {\r
327             this.type = type.toLowerCase();\r
328         } else {\r
329             this.type = "all";\r
330         }\r
331     }\r
332     \r
333     private void readTargetFile() throws EdkException{\r
334         String targetFile = getProject().getProperty("WORKSPACE_DIR") + File.separatorChar + targetFilename;\r
335         \r
336         String[][] targetFileInfo = ConfigReader.parse(getProject(), targetFile);\r
337         \r
338         //\r
339         // Get ToolChain Info from target.txt\r
340         //\r
341         ToolChainInfo envToolChainInfo = new ToolChainInfo(); \r
342         String str = getValue(ToolDefinitions.TARGET_KEY_TARGET, targetFileInfo);\r
343         if (str == null || str.trim().equals("")) {\r
344             envToolChainInfo.addTargets("*");\r
345         } else {\r
346             envToolChainInfo.addTargets(str);\r
347         }\r
348         str = getValue(ToolDefinitions.TARGET_KEY_TOOLCHAIN, targetFileInfo);\r
349         if (str == null || str.trim().equals("")) {\r
350             envToolChainInfo.addTagnames("*");\r
351         } else {\r
352             envToolChainInfo.addTagnames(str);\r
353         }\r
354         str = getValue(ToolDefinitions.TARGET_KEY_ARCH, targetFileInfo);\r
355         if (str == null || str.trim().equals("")) {\r
356             envToolChainInfo.addArchs("*");\r
357         } else {\r
358             envToolChainInfo.addArchs(str);\r
359         }\r
360         GlobalData.setToolChainEnvInfo(envToolChainInfo);\r
361         \r
362         str = getValue(ToolDefinitions.TARGET_KEY_TOOLS_DEF, targetFileInfo);\r
363         if (str != null && str.trim().length() > 0) {\r
364             toolsDefFilename = str;\r
365         }\r
366         \r
367         str = getValue(ToolDefinitions.TARGET_KEY_ACTIVE_PLATFORM, targetFileInfo);\r
368         if (str != null && ! str.trim().equals("")) {\r
369             if ( ! str.endsWith(".fpd")) {\r
370                 throw new BuildException("FPD file's extension must be \"" + ToolDefinitions.FPD_EXTENSION + "\"!");\r
371             }\r
372             activePlatform = str;\r
373         }\r
374         \r
375         str = getValue(ToolDefinitions.TARGET_KEY_MULTIPLE_THREAD, targetFileInfo);\r
376         if (str != null && str.trim().equalsIgnoreCase("Enable")) {\r
377             multithread = true;\r
378         }\r
379 \r
380         str = getValue(ToolDefinitions.TARGET_KEY_MAX_CONCURRENT_THREAD_NUMBER, targetFileInfo);\r
381         //\r
382         // Need to check the # of threads iff multithread is enabled.\r
383         //\r
384         if ((multithread) && (str != null )) {\r
385             try {\r
386                 int threadNum = Integer.parseInt(str);\r
387                 if (threadNum > 0) {\r
388                     MAX_CONCURRENT_THREAD_NUMBER = threadNum;\r
389                 }\r
390             } catch (Exception ex) {\r
391                 //\r
392                 // Give a warning message, and keep the default value\r
393                 //\r
394                 EdkLog.log(this, EdkLog.EDK_WARNING, "Incorrent number specified for MAX_CONCURRENT_THREAD_NUMBER in file [" + targetFilename + "]");\r
395             }\r
396         }\r
397     }\r
398     \r
399     private String getValue(String key, String[][] map) {\r
400         for (int i = 0; i < map[0].length; i++){\r
401             if (key.equalsIgnoreCase(map[0][i])) {\r
402                 return map[1][i];\r
403             }\r
404         }\r
405         return null;\r
406     }\r
407 }\r