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