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