2 This file is ANT task FpdParserTask.
4 FpdParserTask is used to parse FPD (Framework Platform Description) and generate
5 build.out.xml. It is for Package or Platform build use.
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
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.
16 package org
.tianocore
.build
.fpd
;
18 import java
.io
.BufferedWriter
;
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
;
27 import java
.util
.Vector
;
28 import java
.util
.TreeMap
;
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
;
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
;
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.
55 <p>The task sets global properties PLATFORM, PLATFORM_DIR, PLATFORM_RELATIVE_DIR
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>
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>
66 <p>The method parseFpdFile is also prepared for single module build. </p>
68 <p>The usage is (take NT32 Platform for example):</p>
71 <FPDParser platformName="Nt32" />
74 <p>The task will initialize all information through parsing Framework Database,
75 SPD, Tool chain configuration files. </p>
79 public class FpdParserTask
extends Task
{
81 private String platformName
;
83 private File fpdFile
= null;
85 private PlatformIdentification platformId
;
93 /// Mapping from modules identification to out put file name
95 private Map
<FpdModuleIdentification
, String
> outfiles
= new LinkedHashMap
<FpdModuleIdentification
, String
>();
98 /// Mapping from FV name to its modules
100 private Map
<String
, Set
<FpdModuleIdentification
>> fvs
= new HashMap
<String
, Set
<FpdModuleIdentification
>>();
103 /// Mapping from sequence number to FV names
105 private Map
<String
, Set
<String
>> sequences
= new TreeMap
<String
, Set
<String
>>();
108 /// FpdParserTask can specify some ANT properties.
110 private Vector
<Property
> properties
= new Vector
<Property
>();
112 private boolean isUnified
= true;
116 Public construct method. It is necessary for ANT task.
118 public FpdParserTask() {
122 ANT task's entry method. The main steps is described as following:
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>
133 @throws BuildException
134 Surface area is not valid.
136 public void execute() throws BuildException
{
138 if ( fpdFile
== null) {
139 if (platformName
== null) {
140 throw new BuildException("FpdParserTask parameter error. Please specify platform name or FPD file. ");
142 platformId
= GlobalData
.getPlatform(platformName
);
143 fpdFile
= platformId
.getFpdFile();
152 // Pcd Collection. Call CollectPCDAction to collect pcd info.
155 CollectPCDAction ca
= new CollectPCDAction();
156 ca
.perform(GlobalData
.getWorkspacePath(),platformId
.getFpdFile().getPath(),ActionMessage
.NULL_MESSAGE_LEVEL
);
157 } catch (Exception e
){
158 throw new BuildException(e
.getMessage());
164 isUnified
= OutputManager
.getInstance().prepareBuildDir(getProject());
167 // Generate FDF (Flash Definition File) file
171 // For every Target and ToolChain
173 String
[] targetList
= GlobalData
.getToolChainInfo().getTargets();
174 for (int i
= 0; i
< targetList
.length
; i
++){
175 String
[] toolchainList
= GlobalData
.getToolChainInfo().getTagnames();
176 for(int j
= 0; j
< toolchainList
.length
; j
++){
180 String ffsCommonDir
= getProject().getProperty("BUILD_DIR") + File
.separatorChar
181 + targetList
[i
] + File
.separatorChar
183 File fvDir
= new File(ffsCommonDir
+ File
.separatorChar
+ "FV");
185 getProject().setProperty("FV_DIR", fvDir
.getPath().replaceAll("(\\\\)", "/"));
190 genFvInfFiles(ffsCommonDir
);
197 PlatformBuildFileGenerator fileGenerator
= new PlatformBuildFileGenerator(getProject(), outfiles
, fvs
, sequences
, isUnified
);
198 fileGenerator
.genBuildFile();
201 // Ant call ${PLATFORM}_build.xml
205 ant
.setProject(getProject());
206 ant
.setAntfile(platformId
.getFpdFile().getParent() + File
.separatorChar
+ platformId
.getName() + "_build.xml");
208 ant
.setInheritAll(true);
212 // GlobalData.log.info("Fpd build end. ");
216 Generate Fv.inf files. The Fv.inf file is composed with four
217 parts: Options, Attributes, Components and Files. The Fv.inf files
218 will be under FV_DIR.
220 @throws BuildException
221 File write FV.inf files error.
223 private void genFvInfFiles(String ffsCommonDir
) throws BuildException
{
224 String
[] validFv
= SurfaceAreaQuery
.getFpdValidImageNames();
225 for (int i
= 0; i
< validFv
.length
; i
++) {
227 // Get all global variables from FPD and set them to properties
229 String
[][] globalVariables
= SurfaceAreaQuery
.getFpdGlobalVariable();
230 for (int j
= 0; j
< globalVariables
.length
; j
++) {
231 getProject().setProperty(globalVariables
[j
][0], globalVariables
[j
][1]);
234 getProject().setProperty("FV_FILENAME", validFv
[i
].toUpperCase());
236 File fvFile
= new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File
.separatorChar
+ validFv
[i
].toUpperCase() + ".inf"));
237 fvFile
.getParentFile().mkdirs();
240 FileWriter fw
= new FileWriter(fvFile
);
241 BufferedWriter bw
= new BufferedWriter(fw
);
246 String
[][] options
= SurfaceAreaQuery
.getFpdOptions(validFv
[i
]);
247 if (options
.length
> 0) {
248 bw
.write("[options]");
250 for (int j
= 0; j
< options
.length
; j
++) {
251 StringBuffer str
= new StringBuffer(100);
252 str
.append(options
[j
][0]);
253 while (str
.length() < 40) {
257 str
.append(options
[j
][1]);
258 bw
.write(getProject().replaceProperties(str
.toString()));
267 String
[][] attributes
= SurfaceAreaQuery
.getFpdAttributes(validFv
[i
]);
268 if (attributes
.length
> 0) {
269 bw
.write("[attributes]");
271 for (int j
= 0; j
< attributes
.length
; j
++) {
272 StringBuffer str
= new StringBuffer(100);
273 str
.append(attributes
[j
][0]);
274 while (str
.length() < 40) {
278 str
.append(attributes
[j
][1]);
279 bw
.write(getProject().replaceProperties(str
.toString()));
288 String
[][] components
= SurfaceAreaQuery
.getFpdComponents(validFv
[i
]);
289 if (components
.length
> 0) {
290 bw
.write("[components]");
292 for (int j
= 0; j
< components
.length
; j
++) {
293 StringBuffer str
= new StringBuffer(100);
294 str
.append(components
[j
][0]);
295 while (str
.length() < 40) {
299 str
.append(components
[j
][1]);
300 bw
.write(getProject().replaceProperties(str
.toString()));
309 Set
<FpdModuleIdentification
> filesSet
= fvs
.get(validFv
[i
].toUpperCase());
310 if (filesSet
!= null) {
311 FpdModuleIdentification
[] files
= filesSet
.toArray(new FpdModuleIdentification
[filesSet
.size()]);
314 for (int j
= 0; j
< files
.length
; j
++) {
315 String str
= ffsCommonDir
+ File
.separatorChar
+ outfiles
.get(files
[j
]);
316 bw
.write(getProject().replaceProperties("EFI_FILE_NAME = " + str
));
323 } catch (Exception e
) {
325 throw new BuildException("Generate FV file [" + fvFile
.getPath() + "] failed. \n" + e
.getMessage());
330 This method is used for Single Module Build.
333 @throws BuildException
334 FPD file is not valid.
336 public void parseFpdFile(File fpdFile
) throws BuildException
{
337 this.fpdFile
= fpdFile
;
344 @throws BuildException
345 FPD file is not valid.
347 private void parseFpdFile() throws BuildException
{
349 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
351 if (!doc
.validate()) {
352 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] is invalid.");
355 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
356 map
.put("PlatformSurfaceArea", doc
);
357 SurfaceAreaQuery
.setDoc(map
);
362 platformId
= SurfaceAreaQuery
.getFpdHeader();
363 platformId
.setFpdFile(fpdFile
);
364 getProject().setProperty("PLATFORM", platformId
.getName());
365 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
366 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
369 // Build mode. User-defined output dir.
371 String buildMode
= SurfaceAreaQuery
.getFpdIntermediateDirectories();
372 String userDefinedOutputDir
= SurfaceAreaQuery
.getFpdOutputDirectory();
374 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
377 // TBD. Deal PCD and BuildOption related Info
379 GlobalData
.setFpdBuildOptions(SurfaceAreaQuery
.getFpdBuildOptions());
381 GlobalData
.setToolChainPlatformInfo(SurfaceAreaQuery
.getFpdToolChainInfo());
384 // Parse all list modules SA
386 parseModuleSAFiles();
389 // TBD. Deal PCD and BuildOption related Info
391 parseToolChainFamilyOptions();
392 parseToolChainOptions();
394 SurfaceAreaQuery
.setDoc(map
);
395 } catch (Exception e
) {
397 throw new BuildException("Load FPD file [" + fpdFile
.getPath() + "] error. \n" + e
.getMessage());
404 Parse all modules listed in FPD file.
406 private void parseModuleSAFiles() throws EdkException
{
407 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= SurfaceAreaQuery
.getFpdModules();
410 // For every Module lists in FPD file.
412 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
413 Iterator iter
= keys
.iterator();
414 while (iter
.hasNext()) {
415 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
418 // Judge if Module is existed?
421 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
424 // Put fpdModuleId to the corresponding FV
426 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
427 String fvBinding
= SurfaceAreaQuery
.getModuleFvBindingKeyword();
428 SurfaceAreaQuery
.pop();
430 fpdModuleId
.setFvBinding(fvBinding
);
431 String fvSequence
= fpdModuleId
.getSequence();
432 updateFvs(fvSequence
, fvBinding
, fpdModuleId
);
435 // Prepare for out put file name
437 ModuleIdentification moduleId
= fpdModuleId
.getModule();
438 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
439 String baseName
= SurfaceAreaQuery
.getModuleOutputFileBasename();
440 SurfaceAreaQuery
.pop();
441 if (baseName
== null) {
442 baseName
= moduleId
.getName();
444 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
445 + moduleId
.getGuid() + "-" + baseName
446 + getSuffix(moduleId
.getModuleType()));
449 // parse module build options, if any
451 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
452 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
453 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
454 SurfaceAreaQuery
.pop();
458 private ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
459 String
[][] options
= SurfaceAreaQuery
.getModuleBuildOptions(toolChainFamilyFlag
);
460 if (options
== null || options
.length
== 0) {
463 return parseOptions(options
);
466 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
467 String
[][] options
= SurfaceAreaQuery
.getPlatformBuildOptions(toolChainFamilyFlag
);
468 if (options
== null || options
.length
== 0) {
471 return parseOptions(options
);
474 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
475 ToolChainMap map
= new ToolChainMap();
476 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
478 for (int i
= 0; i
< options
.length
; ++i
) {
479 String flagString
= options
[i
][flagIndex
];
480 if (flagString
== null) {
483 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
484 map
.put(options
[i
], flagString
.trim());
490 private void parseToolChainFamilyOptions() throws EdkException
{
491 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
494 private void parseToolChainOptions() throws EdkException
{
495 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
499 Add the current module to corresponding FV.
501 @param fvName current FV name
502 @param moduleName current module identification
504 private void updateFvs(String fvSequence
, String fvName
, FpdModuleIdentification fpdModuleId
) {
505 String upcaseFvName
= fvName
.toUpperCase();
506 String
[] fvNameArray
= upcaseFvName
.split("[, \t]+");
507 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
509 // Put module to corresponding fvName
511 if (fvs
.containsKey(fvNameArray
[i
])) {
512 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
513 set
.add(fpdModuleId
);
516 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
517 set
.add(fpdModuleId
);
518 fvs
.put(fvNameArray
[i
], set
);
522 // Put fvName to corresponding fvSequence
524 if (sequences
.containsKey(fvSequence
)) {
525 Set
<String
> set
= sequences
.get(fvSequence
);
526 set
.add(fvNameArray
[i
]);
529 Set
<String
> set
= new LinkedHashSet
<String
>();
530 set
.add(fvNameArray
[i
]);
531 sequences
.put(fvSequence
, set
);
537 Get the suffix based on module type. Current relationship are listed:
540 <b>ModuleType</b> <b>Suffix</b>
547 DXE_RUNTIME_DRIVER .DXE
552 UEFI_APPLICATION .APP
556 @param moduleType module type
558 @throws BuildException
559 If module type is null
561 public static String
getSuffix(String moduleType
) throws BuildException
{
562 if (moduleType
== null) {
563 throw new BuildException("Module type is not specified.");
566 String
[][] suffix
= { { "BASE", ".FFS"},
567 { "SEC", ".SEC" }, { "PEI_CORE", ".PEI" },
568 { "PEIM", ".PEI" }, { "DXE_CORE", ".DXE" },
569 { "DXE_DRIVER", ".DXE" }, { "DXE_RUNTIME_DRIVER", ".DXE" },
570 { "DXE_SAL_DRIVER", ".DXE" }, { "DXE_SMM_DRIVER", ".DXE" },
571 { "TOOL", ".FFS" }, { "UEFI_DRIVER", ".DXE" },
572 { "UEFI_APPLICATION", ".APP" }, { "USER_DEFINED", ".FFS" } };
574 for (int i
= 0; i
< suffix
.length
; i
++) {
575 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
589 public void addProperty(Property p
) {
590 properties
.addElement(p
);
593 public void setPlatformName(String platformName
) {
594 this.platformName
= platformName
;
597 public void setFpdFile(File fpdFile
) {
598 this.fpdFile
= fpdFile
;
601 public void setType(String type
) {