]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - Tools/Source/GenBuild/org/tianocore/build/fpd/FpdParserTask.java
Update GlobalData, SPD, SurfaceAreaQuery to using EdkException.
[mirror_edk2.git] / Tools / Source / GenBuild / org / tianocore / build / fpd / FpdParserTask.java
... / ...
CommitLineData
1/** @file\r
2 This file is ANT task FpdParserTask.\r
3\r
4 FpdParserTask is used to parse FPD (Framework Platform Description) and generate\r
5 build.out.xml. It is for Package or Platform build use.\r
6\r
7 Copyright (c) 2006, Intel Corporation\r
8 All rights reserved. This program and the accompanying materials\r
9 are licensed and made available under the terms and conditions of the BSD License\r
10 which accompanies this distribution. The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15 **/\r
16package org.tianocore.build.fpd;\r
17\r
18import java.io.BufferedWriter;\r
19import java.io.File;\r
20import java.io.FileWriter;\r
21import java.util.HashMap;\r
22import java.util.Iterator;\r
23import java.util.LinkedHashMap;\r
24import java.util.LinkedHashSet;\r
25import java.util.Map;\r
26import java.util.Set;\r
27import java.util.Vector;\r
28\r
29import org.apache.tools.ant.BuildException;\r
30import org.apache.tools.ant.Task;\r
31import org.apache.tools.ant.taskdefs.Ant;\r
32import org.apache.tools.ant.taskdefs.Property;\r
33import org.apache.xmlbeans.XmlObject;\r
34\r
35import org.tianocore.common.definitions.EdkDefinitions;\r
36import org.tianocore.common.exception.EdkException;\r
37import org.tianocore.pcd.action.ActionMessage;\r
38import org.tianocore.build.FrameworkBuildTask;\r
39import org.tianocore.build.global.GlobalData;\r
40import org.tianocore.build.global.OutputManager;\r
41import org.tianocore.build.global.SurfaceAreaQuery;\r
42import org.tianocore.build.id.FpdModuleIdentification;\r
43import org.tianocore.build.id.ModuleIdentification;\r
44import org.tianocore.build.id.PlatformIdentification;\r
45import org.tianocore.build.pcd.action.PlatformPcdPreprocessActionForBuilding;\r
46import org.tianocore.build.toolchain.ToolChainAttribute;\r
47import org.tianocore.build.toolchain.ToolChainElement;\r
48import org.tianocore.build.toolchain.ToolChainMap;\r
49\r
50/**\r
51 <code>FpdParserTask</code> is an ANT task. The main function is parsing Framework\r
52 Platform Descritpion (FPD) XML file and generating its ANT build script for\r
53 corresponding platform.\r
54\r
55 <p>The task sets global properties PLATFORM, PLATFORM_DIR, PLATFORM_RELATIVE_DIR\r
56 and BUILD_DIR. </p>\r
57\r
58 <p>The task generates ${PLATFORM}_build.xml file which will be called by top level\r
59 build.xml. The task also generate Fv.inf files (File is for Tool GenFvImage). </p>\r
60\r
61 <p>FpdParserTask task stores all FPD information to GlobalData. And parse\r
62 tools definition file to set up compiler options for different Target and\r
63 different ToolChainTag. </p>\r
64\r
65 <p>The method parseFpdFile is also prepared for single module build. </p>\r
66\r
67 @since GenBuild 1.0\r
68**/\r
69public class FpdParserTask extends Task {\r
70\r
71 private File fpdFile = null;\r
72\r
73 PlatformIdentification platformId;\r
74\r
75 private String type;\r
76\r
77 ///\r
78 /// Mapping from modules identification to out put file name\r
79 ///\r
80 Map<FpdModuleIdentification, String> outfiles = new LinkedHashMap<FpdModuleIdentification, String>();\r
81\r
82 ///\r
83 /// Mapping from FV name to its modules\r
84 ///\r
85 Map<String, Set<FpdModuleIdentification>> fvs = new HashMap<String, Set<FpdModuleIdentification>>();\r
86\r
87 ///\r
88 /// FpdParserTask can specify some ANT properties.\r
89 ///\r
90 private Vector<Property> properties = new Vector<Property>();\r
91\r
92 SurfaceAreaQuery saq = null;\r
93 \r
94 boolean isUnified = true;\r
95\r
96 /**\r
97 Public construct method. It is necessary for ANT task.\r
98 **/\r
99 public FpdParserTask() {\r
100 }\r
101\r
102 /**\r
103 ANT task's entry method. The main steps is described as following:\r
104\r
105 <ul>\r
106 <li>Initialize global information (Framework DB, SPD files and all MSA files\r
107 listed in SPD). This step will execute only once in whole build process;</li>\r
108 <li>Parse specified FPD file; </li>\r
109 <li>Generate FV.inf files; </li>\r
110 <li>Generate PlatformName_build.xml file for Flatform build; </li>\r
111 <li>Collect PCD information. </li>\r
112 </ul>\r
113\r
114 @throws BuildException\r
115 Surface area is not valid.\r
116 **/\r
117 public void execute() throws BuildException {\r
118 //\r
119 // Parse FPD file\r
120 //\r
121 parseFpdFile();\r
122\r
123 //\r
124 // Prepare BUILD_DIR\r
125 //\r
126 isUnified = OutputManager.getInstance().prepareBuildDir(getProject());\r
127\r
128 //\r
129 // For every Target and ToolChain\r
130 //\r
131 String[] targetList = GlobalData.getToolChainInfo().getTargets();\r
132 for (int i = 0; i < targetList.length; i++) {\r
133 String[] toolchainList = GlobalData.getToolChainInfo().getTagnames();\r
134 for(int j = 0; j < toolchainList.length; j++) {\r
135 //\r
136 // Prepare FV_DIR\r
137 //\r
138 String ffsCommonDir = getProject().getProperty("BUILD_DIR") + File.separatorChar\r
139 + targetList[i] + "_"\r
140 + toolchainList[j];\r
141 File fvDir = new File(ffsCommonDir + File.separatorChar + "FV");\r
142 fvDir.mkdirs();\r
143 getProject().setProperty("FV_DIR", fvDir.getPath().replaceAll("(\\\\)", "/"));\r
144\r
145 //\r
146 // Gen Fv.inf files\r
147 //\r
148 genFvInfFiles(ffsCommonDir);\r
149 }\r
150 }\r
151\r
152 //\r
153 // Gen build.xml\r
154 //\r
155 PlatformBuildFileGenerator fileGenerator = new PlatformBuildFileGenerator(getProject(), outfiles, fvs, isUnified, saq);\r
156 fileGenerator.genBuildFile();\r
157\r
158 //\r
159 // Ant call ${PLATFORM}_build.xml\r
160 //\r
161 Ant ant = new Ant();\r
162 ant.setProject(getProject());\r
163 ant.setAntfile(platformId.getFpdFile().getParent() + File.separatorChar + platformId.getName() + "_build.xml");\r
164 ant.setTarget(type);\r
165 ant.setInheritAll(true);\r
166 ant.init();\r
167 ant.execute();\r
168 }\r
169\r
170 /**\r
171 Generate Fv.inf files. The Fv.inf file is composed with four\r
172 parts: Options, Attributes, Components and Files. The Fv.inf files\r
173 will be under FV_DIR.\r
174\r
175 @throws BuildException\r
176 File write FV.inf files error.\r
177 **/\r
178 void genFvInfFiles(String ffsCommonDir) throws BuildException {\r
179 String[] validFv = saq.getFpdValidImageNames();\r
180 for (int i = 0; i < validFv.length; i++) {\r
181 //\r
182 // Get all global variables from FPD and set them to properties\r
183 //\r
184 String[][] globalVariables = saq.getFpdGlobalVariable();\r
185 for (int j = 0; j < globalVariables.length; j++) {\r
186 getProject().setProperty(globalVariables[j][0], globalVariables[j][1]);\r
187 }\r
188\r
189 getProject().setProperty("FV_FILENAME", validFv[i]);\r
190\r
191 File fvFile = new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File.separatorChar + validFv[i] + ".inf"));\r
192 fvFile.getParentFile().mkdirs();\r
193\r
194 try {\r
195 FileWriter fw = new FileWriter(fvFile);\r
196 BufferedWriter bw = new BufferedWriter(fw);\r
197\r
198 //\r
199 // Options\r
200 //\r
201 String[][] options = saq.getFpdOptions(validFv[i]);\r
202 if (options.length > 0) {\r
203 bw.write("[options]");\r
204 bw.newLine();\r
205 for (int j = 0; j < options.length; j++) {\r
206 StringBuffer str = new StringBuffer(100);\r
207 str.append(options[j][0]);\r
208 while (str.length() < 40) {\r
209 str.append(' ');\r
210 }\r
211 str.append("= ");\r
212 str.append(options[j][1]);\r
213 bw.write(getProject().replaceProperties(str.toString()));\r
214 bw.newLine();\r
215 }\r
216 bw.newLine();\r
217 }\r
218\r
219 //\r
220 // Attributes;\r
221 //\r
222 String[][] attributes = saq.getFpdAttributes(validFv[i]);\r
223 if (attributes.length > 0) {\r
224 bw.write("[attributes]");\r
225 bw.newLine();\r
226 for (int j = 0; j < attributes.length; j++) {\r
227 StringBuffer str = new StringBuffer(100);\r
228 str.append(attributes[j][0]);\r
229 while (str.length() < 40) {\r
230 str.append(' ');\r
231 }\r
232 str.append("= ");\r
233 str.append(attributes[j][1]);\r
234 bw.write(getProject().replaceProperties(str.toString()));\r
235 bw.newLine();\r
236 }\r
237 bw.newLine();\r
238 }\r
239\r
240 //\r
241 // Components\r
242 //\r
243 String[][] components = saq.getFpdComponents(validFv[i]);\r
244 if (components.length > 0) {\r
245 bw.write("[components]");\r
246 bw.newLine();\r
247 for (int j = 0; j < components.length; j++) {\r
248 StringBuffer str = new StringBuffer(100);\r
249 str.append(components[j][0]);\r
250 while (str.length() < 40) {\r
251 str.append(' ');\r
252 }\r
253 str.append("= ");\r
254 str.append(components[j][1]);\r
255 bw.write(getProject().replaceProperties(str.toString()));\r
256 bw.newLine();\r
257 }\r
258 bw.newLine();\r
259 }\r
260\r
261 //\r
262 // Files\r
263 //\r
264 Set<FpdModuleIdentification> filesSet = fvs.get(validFv[i]);\r
265 if (filesSet != null) {\r
266 FpdModuleIdentification[] files = filesSet.toArray(new FpdModuleIdentification[filesSet.size()]);\r
267 bw.write("[files]");\r
268 bw.newLine();\r
269 for (int j = 0; j < files.length; j++) {\r
270 String str = ffsCommonDir + File.separatorChar + outfiles.get(files[j]);\r
271 bw.write(getProject().replaceProperties("EFI_FILE_NAME = " + str));\r
272 bw.newLine();\r
273 }\r
274 }\r
275 bw.flush();\r
276 bw.close();\r
277 fw.close();\r
278 } catch (Exception e) {\r
279 throw new BuildException("Generation of the FV file [" + fvFile.getPath() + "] failed!\n" + e.getMessage());\r
280 }\r
281 }\r
282 }\r
283 /**\r
284 This method is used for Single Module Build.\r
285\r
286\r
287 @throws BuildException\r
288 FPD file is not valid.\r
289 **/\r
290 public void parseFpdFile(File fpdFile) throws BuildException {\r
291 this.fpdFile = fpdFile;\r
292 parseFpdFile();\r
293 }\r
294\r
295 /**\r
296 Parse FPD file.\r
297\r
298 @throws BuildException\r
299 FPD file is not valid.\r
300 **/\r
301 void parseFpdFile() throws BuildException {\r
302 try {\r
303 XmlObject doc = XmlObject.Factory.parse(fpdFile);\r
304\r
305 if (!doc.validate()) {\r
306 throw new BuildException("Platform Surface Area file [" + fpdFile.getPath() + "] format is invalid!");\r
307 }\r
308\r
309 Map<String, XmlObject> map = new HashMap<String, XmlObject>();\r
310 map.put("PlatformSurfaceArea", doc);\r
311 saq = new SurfaceAreaQuery(map);\r
312\r
313 //\r
314 // Initialize\r
315 //\r
316 platformId = saq.getFpdHeader();\r
317 platformId.setFpdFile(fpdFile);\r
318 getProject().setProperty("PLATFORM", platformId.getName());\r
319 getProject().setProperty("PLATFORM_FILE", platformId.getRelativeFpdFile().replaceAll("(\\\\)", "/"));\r
320 getProject().setProperty("PLATFORM_DIR", platformId.getFpdFile().getParent().replaceAll("(\\\\)", "/"));\r
321 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));\r
322 \r
323 if( !FrameworkBuildTask.multithread) {\r
324 FrameworkBuildTask.originalProperties.put("PLATFORM", platformId.getName());\r
325 FrameworkBuildTask.originalProperties.put("PLATFORM_FILE", platformId.getRelativeFpdFile().replaceAll("(\\\\)", "/"));\r
326 FrameworkBuildTask.originalProperties.put("PLATFORM_DIR", platformId.getFpdFile().getParent().replaceAll("(\\\\)", "/"));\r
327 FrameworkBuildTask.originalProperties.put("PLATFORM_RELATIVE_DIR", platformId.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));\r
328 }\r
329\r
330 //\r
331 // Build mode. User-defined output dir.\r
332 //\r
333 String buildMode = saq.getFpdIntermediateDirectories();\r
334 String userDefinedOutputDir = saq.getFpdOutputDirectory();\r
335\r
336 OutputManager.getInstance().setup(userDefinedOutputDir, buildMode);\r
337\r
338 //\r
339 // TBD. Deal PCD and BuildOption related Info\r
340 //\r
341 GlobalData.setFpdBuildOptions(saq.getFpdBuildOptions());\r
342\r
343 GlobalData.setToolChainPlatformInfo(saq.getFpdToolChainInfo());\r
344\r
345 //\r
346 // Parse all list modules SA\r
347 //\r
348 parseModuleSAFiles();\r
349\r
350 //\r
351 // TBD. Deal PCD and BuildOption related Info\r
352 //\r
353 parseToolChainFamilyOptions();\r
354 parseToolChainOptions();\r
355\r
356 saq.push(map);\r
357\r
358 //\r
359 // Pcd Collection. Call CollectPCDAction to collect pcd info.\r
360 //\r
361 PlatformPcdPreprocessActionForBuilding ca = new PlatformPcdPreprocessActionForBuilding();\r
362 ca.perform(platformId.getFpdFile().getPath(), ActionMessage.NULL_MESSAGE_LEVEL);\r
363 } catch (Exception e) {\r
364 throw new BuildException("Parsing of the FPD file [" + fpdFile.getPath() + "] failed!\n" + e.getMessage());\r
365 }\r
366 }\r
367\r
368 /**\r
369 Parse all modules listed in FPD file.\r
370 **/\r
371 void parseModuleSAFiles() throws EdkException{\r
372 Map<FpdModuleIdentification, Map<String, XmlObject>> moduleSAs = saq.getFpdModules();\r
373\r
374 //\r
375 // For every Module lists in FPD file.\r
376 //\r
377 Set<FpdModuleIdentification> keys = moduleSAs.keySet();\r
378 Iterator iter = keys.iterator();\r
379 while (iter.hasNext()) {\r
380 FpdModuleIdentification fpdModuleId = (FpdModuleIdentification) iter.next();\r
381\r
382 //\r
383 // Judge if Module is existed?\r
384 // TBD\r
385 GlobalData.registerFpdModuleSA(fpdModuleId, moduleSAs.get(fpdModuleId));\r
386\r
387 //\r
388 // Put fpdModuleId to the corresponding FV\r
389 //\r
390 saq.push(GlobalData.getDoc(fpdModuleId));\r
391 String fvBinding = saq.getModuleFvBindingKeyword();\r
392\r
393 fpdModuleId.setFvBinding(fvBinding);\r
394 updateFvs(fvBinding, fpdModuleId);\r
395\r
396 //\r
397 // Prepare for out put file name\r
398 //\r
399 ModuleIdentification moduleId = fpdModuleId.getModule();\r
400\r
401 String baseName = saq.getModuleOutputFileBasename();\r
402 \r
403 if (baseName == null) {\r
404 baseName = moduleId.getName();\r
405 }\r
406 outfiles.put(fpdModuleId, fpdModuleId.getArch() + File.separatorChar\r
407 + moduleId.getGuid() + "-" + baseName\r
408 + getSuffix(moduleId.getModuleType()));\r
409\r
410 //\r
411 // parse module build options, if any\r
412 //\r
413 GlobalData.addModuleToolChainOption(fpdModuleId, parseModuleBuildOptions(false));\r
414 GlobalData.addModuleToolChainFamilyOption(fpdModuleId, parseModuleBuildOptions(true));\r
415 saq.pop();\r
416 }\r
417 }\r
418\r
419 ToolChainMap parseModuleBuildOptions(boolean toolChainFamilyFlag) throws EdkException {\r
420 String[][] options = saq.getModuleBuildOptions(toolChainFamilyFlag);\r
421 if (options == null || options.length == 0) {\r
422 return new ToolChainMap();\r
423 }\r
424 return parseOptions(options);\r
425 }\r
426\r
427 private ToolChainMap parsePlatformBuildOptions(boolean toolChainFamilyFlag) throws EdkException {\r
428 String[][] options = saq.getPlatformBuildOptions(toolChainFamilyFlag);\r
429 if (options == null || options.length == 0) {\r
430 return new ToolChainMap();\r
431 }\r
432 return parseOptions(options);\r
433 }\r
434\r
435 private ToolChainMap parseOptions(String[][] options) throws EdkException {\r
436 ToolChainMap map = new ToolChainMap();\r
437 int flagIndex = ToolChainElement.ATTRIBUTE.value;\r
438\r
439 for (int i = 0; i < options.length; ++i) {\r
440 String flagString = options[i][flagIndex];\r
441 if (flagString == null) {\r
442 flagString = "";\r
443 }\r
444 options[i][flagIndex] = ToolChainAttribute.FLAGS + "";\r
445 map.put(options[i], flagString.trim());\r
446 }\r
447\r
448 return map;\r
449 }\r
450\r
451 private void parseToolChainFamilyOptions() throws EdkException {\r
452 GlobalData.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));\r
453 }\r
454\r
455 private void parseToolChainOptions() throws EdkException {\r
456 GlobalData.setPlatformToolChainOption(parsePlatformBuildOptions(false));\r
457 }\r
458\r
459 /**\r
460 Add the current module to corresponding FV.\r
461\r
462 @param fvName current FV name\r
463 @param moduleName current module identification\r
464 **/\r
465 void updateFvs(String fvName, FpdModuleIdentification fpdModuleId) {\r
466 if (fvName == null || fvName.trim().length() == 0) {\r
467 fvName = "NULL";\r
468 }\r
469 String[] fvNameArray = fvName.split("[, \t]+");\r
470 for (int i = 0; i < fvNameArray.length; i++) {\r
471 //\r
472 // Put module to corresponding fvName\r
473 //\r
474 if (fvs.containsKey(fvNameArray[i])) {\r
475 Set<FpdModuleIdentification> set = fvs.get(fvNameArray[i]);\r
476 set.add(fpdModuleId);\r
477 } else {\r
478 Set<FpdModuleIdentification> set = new LinkedHashSet<FpdModuleIdentification>();\r
479 set.add(fpdModuleId);\r
480 fvs.put(fvNameArray[i], set);\r
481 }\r
482 }\r
483 }\r
484\r
485 /**\r
486 Get the suffix based on module type. Current relationship are listed:\r
487\r
488 <pre>\r
489 <b>ModuleType</b> <b>Suffix</b>\r
490 BASE .FFS\r
491 SEC .SEC\r
492 PEI_CORE .PEI\r
493 PEIM .PEI\r
494 DXE_CORE .DXE\r
495 DXE_DRIVER .DXE\r
496 DXE_RUNTIME_DRIVER .DXE\r
497 DXE_SAL_DRIVER .DXE\r
498 DXE_SMM_DRIVER .DXE\r
499 TOOL .FFS\r
500 UEFI_DRIVER .DXE\r
501 UEFI_APPLICATION .APP\r
502 USER_DEFINED .FFS\r
503 </pre>\r
504\r
505 @param moduleType module type\r
506 @return\r
507 @throws BuildException\r
508 If module type is null\r
509 **/\r
510 public static String getSuffix(String moduleType) throws BuildException {\r
511 if (moduleType == null) {\r
512 throw new BuildException("Module type is not specified.");\r
513 }\r
514\r
515 String[][] suffix = EdkDefinitions.ModuleTypeExtensions;\r
516\r
517 for (int i = 0; i < suffix.length; i++) {\r
518 if (suffix[i][0].equalsIgnoreCase(moduleType)) {\r
519 return suffix[i][1];\r
520 }\r
521 }\r
522 //\r
523 // Default is '.FFS'\r
524 //\r
525 return ".FFS";\r
526 }\r
527 /**\r
528 Add a property.\r
529\r
530 @param p property\r
531 **/\r
532 public void addProperty(Property p) {\r
533 properties.addElement(p);\r
534 }\r
535\r
536 public void setFpdFile(File fpdFile) {\r
537 this.fpdFile = fpdFile;\r
538 }\r
539\r
540 public void setType(String type) {\r
541 this.type = type;\r
542 }\r
543 \r
544 public String getAllArchForModule(ModuleIdentification moduleId) {\r
545 String archs = "";\r
546 Iterator<FpdModuleIdentification> iter = outfiles.keySet().iterator();\r
547 while (iter.hasNext()) {\r
548 FpdModuleIdentification fpdModuleId = iter.next();\r
549 \r
550 if (fpdModuleId.getModule().equals(moduleId)) {\r
551 archs += fpdModuleId.getArch() + " ";\r
552 }\r
553 }\r
554 \r
555 return archs;\r
556 }\r
557}\r