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