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