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