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
.getPlatformByName(platformName
);
143 fpdFile
= platformId
.getFpdFile();
154 isUnified
= OutputManager
.getInstance().prepareBuildDir(getProject());
157 // Generate FDF (Flash Definition File) file
161 // For every Target and ToolChain
163 String
[] targetList
= GlobalData
.getToolChainInfo().getTargets();
164 for (int i
= 0; i
< targetList
.length
; i
++){
165 String
[] toolchainList
= GlobalData
.getToolChainInfo().getTagnames();
166 for(int j
= 0; j
< toolchainList
.length
; j
++){
170 String ffsCommonDir
= getProject().getProperty("BUILD_DIR") + File
.separatorChar
171 + targetList
[i
] + File
.separatorChar
173 File fvDir
= new File(ffsCommonDir
+ File
.separatorChar
+ "FV");
175 getProject().setProperty("FV_DIR", fvDir
.getPath().replaceAll("(\\\\)", "/"));
180 genFvInfFiles(ffsCommonDir
);
187 PlatformBuildFileGenerator fileGenerator
= new PlatformBuildFileGenerator(getProject(), outfiles
, fvs
, sequences
, isUnified
);
188 fileGenerator
.genBuildFile();
191 // Ant call ${PLATFORM}_build.xml
195 ant
.setProject(getProject());
196 ant
.setAntfile(platformId
.getFpdFile().getParent() + File
.separatorChar
+ platformId
.getName() + "_build.xml");
198 ant
.setInheritAll(true);
202 // GlobalData.log.info("Fpd build end. ");
206 Generate Fv.inf files. The Fv.inf file is composed with four
207 parts: Options, Attributes, Components and Files. The Fv.inf files
208 will be under FV_DIR.
210 @throws BuildException
211 File write FV.inf files error.
213 private void genFvInfFiles(String ffsCommonDir
) throws BuildException
{
214 String
[] validFv
= SurfaceAreaQuery
.getFpdValidImageNames();
215 for (int i
= 0; i
< validFv
.length
; i
++) {
217 // Get all global variables from FPD and set them to properties
219 String
[][] globalVariables
= SurfaceAreaQuery
.getFpdGlobalVariable();
220 for (int j
= 0; j
< globalVariables
.length
; j
++) {
221 getProject().setProperty(globalVariables
[j
][0], globalVariables
[j
][1]);
224 getProject().setProperty("FV_FILENAME", validFv
[i
].toUpperCase());
226 File fvFile
= new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File
.separatorChar
+ validFv
[i
].toUpperCase() + ".inf"));
227 fvFile
.getParentFile().mkdirs();
230 FileWriter fw
= new FileWriter(fvFile
);
231 BufferedWriter bw
= new BufferedWriter(fw
);
236 String
[][] options
= SurfaceAreaQuery
.getFpdOptions(validFv
[i
]);
237 if (options
.length
> 0) {
238 bw
.write("[options]");
240 for (int j
= 0; j
< options
.length
; j
++) {
241 StringBuffer str
= new StringBuffer(100);
242 str
.append(options
[j
][0]);
243 while (str
.length() < 40) {
247 str
.append(options
[j
][1]);
248 bw
.write(getProject().replaceProperties(str
.toString()));
257 String
[][] attributes
= SurfaceAreaQuery
.getFpdAttributes(validFv
[i
]);
258 if (attributes
.length
> 0) {
259 bw
.write("[attributes]");
261 for (int j
= 0; j
< attributes
.length
; j
++) {
262 StringBuffer str
= new StringBuffer(100);
263 str
.append(attributes
[j
][0]);
264 while (str
.length() < 40) {
268 str
.append(attributes
[j
][1]);
269 bw
.write(getProject().replaceProperties(str
.toString()));
278 String
[][] components
= SurfaceAreaQuery
.getFpdComponents(validFv
[i
]);
279 if (components
.length
> 0) {
280 bw
.write("[components]");
282 for (int j
= 0; j
< components
.length
; j
++) {
283 StringBuffer str
= new StringBuffer(100);
284 str
.append(components
[j
][0]);
285 while (str
.length() < 40) {
289 str
.append(components
[j
][1]);
290 bw
.write(getProject().replaceProperties(str
.toString()));
299 Set
<FpdModuleIdentification
> filesSet
= fvs
.get(validFv
[i
].toUpperCase());
300 if (filesSet
!= null) {
301 FpdModuleIdentification
[] files
= filesSet
.toArray(new FpdModuleIdentification
[filesSet
.size()]);
304 for (int j
= 0; j
< files
.length
; j
++) {
305 String str
= ffsCommonDir
+ File
.separatorChar
+ outfiles
.get(files
[j
]);
306 bw
.write(getProject().replaceProperties("EFI_FILE_NAME = " + str
));
313 } catch (Exception e
) {
315 throw new BuildException("Generate FV file [" + fvFile
.getPath() + "] failed. \n" + e
.getMessage());
320 This method is used for Single Module Build.
323 @throws BuildException
324 FPD file is not valid.
326 public void parseFpdFile(File fpdFile
) throws BuildException
{
327 this.fpdFile
= fpdFile
;
334 @throws BuildException
335 FPD file is not valid.
337 private void parseFpdFile() throws BuildException
{
339 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
341 if (!doc
.validate()) {
342 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] is invalid.");
345 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
346 map
.put("PlatformSurfaceArea", doc
);
347 SurfaceAreaQuery
.setDoc(map
);
348 SurfaceAreaQuery
.getFpdUserExtension();
352 platformId
= SurfaceAreaQuery
.getFpdHeader();
353 platformId
.setFpdFile(fpdFile
);
354 getProject().setProperty("PLATFORM", platformId
.getName());
355 getProject().setProperty("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
356 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
357 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
360 // Build mode. User-defined output dir.
362 String buildMode
= SurfaceAreaQuery
.getFpdIntermediateDirectories();
363 String userDefinedOutputDir
= SurfaceAreaQuery
.getFpdOutputDirectory();
365 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
368 // TBD. Deal PCD and BuildOption related Info
370 GlobalData
.setFpdBuildOptions(SurfaceAreaQuery
.getFpdBuildOptions());
372 GlobalData
.setToolChainPlatformInfo(SurfaceAreaQuery
.getFpdToolChainInfo());
375 // Parse all list modules SA
377 parseModuleSAFiles();
380 // TBD. Deal PCD and BuildOption related Info
382 parseToolChainFamilyOptions();
383 parseToolChainOptions();
385 SurfaceAreaQuery
.setDoc(map
);
388 // Pcd Collection. Call CollectPCDAction to collect pcd info.
391 CollectPCDAction ca
= new CollectPCDAction();
392 ca
.perform(GlobalData
.getWorkspacePath(),platformId
.getFpdFile().getPath(),ActionMessage
.NULL_MESSAGE_LEVEL
);
393 } catch (Exception e
){
394 throw new BuildException(e
.getMessage());
396 } catch (Exception e
) {
398 throw new BuildException("Load FPD file [" + fpdFile
.getPath() + "] error. \n" + e
.getMessage());
405 Parse all modules listed in FPD file.
407 private void parseModuleSAFiles() throws EdkException
{
408 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= SurfaceAreaQuery
.getFpdModules();
411 // For every Module lists in FPD file.
413 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
414 Iterator iter
= keys
.iterator();
415 while (iter
.hasNext()) {
416 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
419 // Judge if Module is existed?
422 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
425 // Put fpdModuleId to the corresponding FV
427 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
428 String fvBinding
= SurfaceAreaQuery
.getModuleFvBindingKeyword();
429 SurfaceAreaQuery
.pop();
431 fpdModuleId
.setFvBinding(fvBinding
);
432 String fvSequence
= fpdModuleId
.getSequence();
433 updateFvs(fvSequence
, fvBinding
, fpdModuleId
);
436 // Prepare for out put file name
438 ModuleIdentification moduleId
= fpdModuleId
.getModule();
439 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
440 String baseName
= SurfaceAreaQuery
.getModuleOutputFileBasename();
441 SurfaceAreaQuery
.pop();
442 if (baseName
== null) {
443 baseName
= moduleId
.getName();
445 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
446 + moduleId
.getGuid() + "-" + baseName
447 + getSuffix(moduleId
.getModuleType()));
450 // parse module build options, if any
452 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
453 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
454 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
455 SurfaceAreaQuery
.pop();
459 private ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
460 String
[][] options
= SurfaceAreaQuery
.getModuleBuildOptions(toolChainFamilyFlag
);
461 if (options
== null || options
.length
== 0) {
464 return parseOptions(options
);
467 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
468 String
[][] options
= SurfaceAreaQuery
.getPlatformBuildOptions(toolChainFamilyFlag
);
469 if (options
== null || options
.length
== 0) {
472 return parseOptions(options
);
475 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
476 ToolChainMap map
= new ToolChainMap();
477 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
479 for (int i
= 0; i
< options
.length
; ++i
) {
480 String flagString
= options
[i
][flagIndex
];
481 if (flagString
== null) {
484 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
485 map
.put(options
[i
], flagString
.trim());
491 private void parseToolChainFamilyOptions() throws EdkException
{
492 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
495 private void parseToolChainOptions() throws EdkException
{
496 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
500 Add the current module to corresponding FV.
502 @param fvName current FV name
503 @param moduleName current module identification
505 private void updateFvs(String fvSequence
, String fvName
, FpdModuleIdentification fpdModuleId
) {
506 String upcaseFvName
= fvName
.toUpperCase();
507 String
[] fvNameArray
= upcaseFvName
.split("[, \t]+");
508 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
510 // Put module to corresponding fvName
512 if (fvs
.containsKey(fvNameArray
[i
])) {
513 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
514 set
.add(fpdModuleId
);
517 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
518 set
.add(fpdModuleId
);
519 fvs
.put(fvNameArray
[i
], set
);
523 // Put fvName to corresponding fvSequence
525 if (sequences
.containsKey(fvSequence
)) {
526 Set
<String
> set
= sequences
.get(fvSequence
);
527 set
.add(fvNameArray
[i
]);
530 Set
<String
> set
= new LinkedHashSet
<String
>();
531 set
.add(fvNameArray
[i
]);
532 sequences
.put(fvSequence
, set
);
538 Get the suffix based on module type. Current relationship are listed:
541 <b>ModuleType</b> <b>Suffix</b>
548 DXE_RUNTIME_DRIVER .DXE
553 UEFI_APPLICATION .APP
557 @param moduleType module type
559 @throws BuildException
560 If module type is null
562 public static String
getSuffix(String moduleType
) throws BuildException
{
563 if (moduleType
== null) {
564 throw new BuildException("Module type is not specified.");
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" } };
575 for (int i
= 0; i
< suffix
.length
; i
++) {
576 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
590 public void addProperty(Property p
) {
591 properties
.addElement(p
);
594 public void setPlatformName(String platformName
) {
595 this.platformName
= platformName
;
598 public void setFpdFile(File fpdFile
) {
599 this.fpdFile
= fpdFile
;
602 public void setType(String type
) {