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
;
29 import org
.apache
.tools
.ant
.BuildException
;
30 import org
.apache
.tools
.ant
.Task
;
31 import org
.apache
.tools
.ant
.taskdefs
.Ant
;
32 import org
.apache
.tools
.ant
.taskdefs
.Property
;
33 import org
.apache
.xmlbeans
.XmlObject
;
35 import org
.tianocore
.common
.exception
.EdkException
;
36 import org
.tianocore
.pcd
.action
.ActionMessage
;
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
.pcd
.action
.PlatformPcdPreprocessActionForBuilding
;
44 import org
.tianocore
.build
.toolchain
.ToolChainAttribute
;
45 import org
.tianocore
.build
.toolchain
.ToolChainElement
;
46 import org
.tianocore
.build
.toolchain
.ToolChainMap
;
49 <code>FpdParserTask</code> is an ANT task. The main function is parsing Framework
50 Platform Descritpion (FPD) XML file and generating its ANT build script for
51 corresponding platform.
53 <p>The task sets global properties PLATFORM, PLATFORM_DIR, PLATFORM_RELATIVE_DIR
56 <p>The task generates ${PLATFORM}_build.xml file which will be called by top level
57 build.xml. The task also generate Fv.inf files (File is for Tool GenFvImage)
58 and flash definition file (File is for Tool FlashMap) if necessary. </p>
60 <p>FpdParserTask task stores all FPD information to GlobalData. And parse
61 tools definition file to set up compiler options for different Target and
62 different ToolChainTag. </p>
64 <p>The method parseFpdFile is also prepared for single module build. </p>
66 <p>The usage is (take NT32 Platform for example):</p>
69 <FPDParser platformName="Nt32" />
72 <p>The task will initialize all information through parsing Framework Database,
73 SPD, Tool chain configuration files. </p>
77 public class FpdParserTask
extends Task
{
79 private String platformName
;
81 private File fpdFile
= null;
83 private PlatformIdentification platformId
;
88 /// Mapping from modules identification to out put file name
90 private Map
<FpdModuleIdentification
, String
> outfiles
= new LinkedHashMap
<FpdModuleIdentification
, String
>();
93 /// Mapping from FV name to its modules
95 private Map
<String
, Set
<FpdModuleIdentification
>> fvs
= new HashMap
<String
, Set
<FpdModuleIdentification
>>();
98 /// FpdParserTask can specify some ANT properties.
100 private Vector
<Property
> properties
= new Vector
<Property
>();
102 private boolean isUnified
= true;
106 Public construct method. It is necessary for ANT task.
108 public FpdParserTask() {
112 ANT task's entry method. The main steps is described as following:
115 <li>Initialize global information (Framework DB, SPD files and all MSA files
116 listed in SPD). This step will execute only once in whole build process;</li>
117 <li>Parse specified FPD file; </li>
118 <li>Generate FV.inf files; </li>
119 <li>Generate PlatformName_build.xml file for Flatform build; </li>
120 <li>Collect PCD information. </li>
123 @throws BuildException
124 Surface area is not valid.
126 public void execute() throws BuildException
{
128 // If fpdFile is not specified,
129 // then try to get FPD file by platformName
131 if ( fpdFile
== null) {
132 if (platformName
== null) {
133 throw new BuildException("FpdParserTask parameter error. Please specify either the platform name or FPD file!");
135 platformId
= GlobalData
.getPlatformByName(platformName
);
136 fpdFile
= platformId
.getFpdFile();
147 isUnified
= OutputManager
.getInstance().prepareBuildDir(getProject());
150 // For every Target and ToolChain
152 String
[] targetList
= GlobalData
.getToolChainInfo().getTargets();
153 for (int i
= 0; i
< targetList
.length
; i
++) {
154 String
[] toolchainList
= GlobalData
.getToolChainInfo().getTagnames();
155 for(int j
= 0; j
< toolchainList
.length
; j
++) {
159 String ffsCommonDir
= getProject().getProperty("BUILD_DIR") + File
.separatorChar
160 + targetList
[i
] + File
.separatorChar
162 File fvDir
= new File(ffsCommonDir
+ File
.separatorChar
+ "FV");
164 getProject().setProperty("FV_DIR", fvDir
.getPath().replaceAll("(\\\\)", "/"));
169 genFvInfFiles(ffsCommonDir
);
176 PlatformBuildFileGenerator fileGenerator
= new PlatformBuildFileGenerator(getProject(), outfiles
, isUnified
);
177 fileGenerator
.genBuildFile();
180 // Ant call ${PLATFORM}_build.xml
184 ant
.setProject(getProject());
185 ant
.setAntfile(platformId
.getFpdFile().getParent() + File
.separatorChar
+ platformId
.getName() + "_build.xml");
187 ant
.setInheritAll(true);
193 Generate Fv.inf files. The Fv.inf file is composed with four
194 parts: Options, Attributes, Components and Files. The Fv.inf files
195 will be under FV_DIR.
197 @throws BuildException
198 File write FV.inf files error.
200 private void genFvInfFiles(String ffsCommonDir
) throws BuildException
{
201 String
[] validFv
= SurfaceAreaQuery
.getFpdValidImageNames();
202 for (int i
= 0; i
< validFv
.length
; i
++) {
204 // Get all global variables from FPD and set them to properties
206 String
[][] globalVariables
= SurfaceAreaQuery
.getFpdGlobalVariable();
207 for (int j
= 0; j
< globalVariables
.length
; j
++) {
208 getProject().setProperty(globalVariables
[j
][0], globalVariables
[j
][1]);
211 getProject().setProperty("FV_FILENAME", validFv
[i
]);
213 File fvFile
= new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File
.separatorChar
+ validFv
[i
] + ".inf"));
214 fvFile
.getParentFile().mkdirs();
217 FileWriter fw
= new FileWriter(fvFile
);
218 BufferedWriter bw
= new BufferedWriter(fw
);
223 String
[][] options
= SurfaceAreaQuery
.getFpdOptions(validFv
[i
]);
224 if (options
.length
> 0) {
225 bw
.write("[options]");
227 for (int j
= 0; j
< options
.length
; j
++) {
228 StringBuffer str
= new StringBuffer(100);
229 str
.append(options
[j
][0]);
230 while (str
.length() < 40) {
234 str
.append(options
[j
][1]);
235 bw
.write(getProject().replaceProperties(str
.toString()));
244 String
[][] attributes
= SurfaceAreaQuery
.getFpdAttributes(validFv
[i
]);
245 if (attributes
.length
> 0) {
246 bw
.write("[attributes]");
248 for (int j
= 0; j
< attributes
.length
; j
++) {
249 StringBuffer str
= new StringBuffer(100);
250 str
.append(attributes
[j
][0]);
251 while (str
.length() < 40) {
255 str
.append(attributes
[j
][1]);
256 bw
.write(getProject().replaceProperties(str
.toString()));
265 String
[][] components
= SurfaceAreaQuery
.getFpdComponents(validFv
[i
]);
266 if (components
.length
> 0) {
267 bw
.write("[components]");
269 for (int j
= 0; j
< components
.length
; j
++) {
270 StringBuffer str
= new StringBuffer(100);
271 str
.append(components
[j
][0]);
272 while (str
.length() < 40) {
276 str
.append(components
[j
][1]);
277 bw
.write(getProject().replaceProperties(str
.toString()));
286 Set
<FpdModuleIdentification
> filesSet
= fvs
.get(validFv
[i
]);
287 if (filesSet
!= null) {
288 FpdModuleIdentification
[] files
= filesSet
.toArray(new FpdModuleIdentification
[filesSet
.size()]);
291 for (int j
= 0; j
< files
.length
; j
++) {
292 String str
= ffsCommonDir
+ File
.separatorChar
+ outfiles
.get(files
[j
]);
293 bw
.write(getProject().replaceProperties("EFI_FILE_NAME = " + str
));
300 } catch (Exception e
) {
301 throw new BuildException("Generation of the FV file [" + fvFile
.getPath() + "] failed!\n" + e
.getMessage());
306 This method is used for Single Module Build.
309 @throws BuildException
310 FPD file is not valid.
312 public void parseFpdFile(File fpdFile
) throws BuildException
{
313 this.fpdFile
= fpdFile
;
320 @throws BuildException
321 FPD file is not valid.
323 private void parseFpdFile() throws BuildException
{
325 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
327 if (!doc
.validate()) {
328 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] format is invalid!");
331 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
332 map
.put("PlatformSurfaceArea", doc
);
333 SurfaceAreaQuery
.setDoc(map
);
338 platformId
= SurfaceAreaQuery
.getFpdHeader();
339 platformId
.setFpdFile(fpdFile
);
340 getProject().setProperty("PLATFORM", platformId
.getName());
341 getProject().setProperty("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
342 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
343 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
346 // Build mode. User-defined output dir.
348 String buildMode
= SurfaceAreaQuery
.getFpdIntermediateDirectories();
349 String userDefinedOutputDir
= SurfaceAreaQuery
.getFpdOutputDirectory();
351 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
354 // TBD. Deal PCD and BuildOption related Info
356 GlobalData
.setFpdBuildOptions(SurfaceAreaQuery
.getFpdBuildOptions());
358 GlobalData
.setToolChainPlatformInfo(SurfaceAreaQuery
.getFpdToolChainInfo());
361 // Parse all list modules SA
363 parseModuleSAFiles();
366 // TBD. Deal PCD and BuildOption related Info
368 parseToolChainFamilyOptions();
369 parseToolChainOptions();
371 SurfaceAreaQuery
.setDoc(map
);
374 // Pcd Collection. Call CollectPCDAction to collect pcd info.
376 PlatformPcdPreprocessActionForBuilding ca
= new PlatformPcdPreprocessActionForBuilding();
377 ca
.perform(platformId
.getFpdFile().getPath(), ActionMessage
.NULL_MESSAGE_LEVEL
);
378 } catch (Exception e
) {
379 throw new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + e
.getMessage());
386 Parse all modules listed in FPD file.
388 private void parseModuleSAFiles() throws EdkException
{
389 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= SurfaceAreaQuery
.getFpdModules();
392 // For every Module lists in FPD file.
394 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
395 Iterator iter
= keys
.iterator();
396 while (iter
.hasNext()) {
397 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
400 // Judge if Module is existed?
403 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
406 // Put fpdModuleId to the corresponding FV
408 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
409 String fvBinding
= SurfaceAreaQuery
.getModuleFvBindingKeyword();
411 fpdModuleId
.setFvBinding(fvBinding
);
412 updateFvs(fvBinding
, fpdModuleId
);
415 // Prepare for out put file name
417 ModuleIdentification moduleId
= fpdModuleId
.getModule();
419 String baseName
= SurfaceAreaQuery
.getModuleOutputFileBasename();
421 if (baseName
== null) {
422 baseName
= moduleId
.getName();
424 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
425 + moduleId
.getGuid() + "-" + baseName
426 + getSuffix(moduleId
.getModuleType()));
429 // parse module build options, if any
431 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
432 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
433 SurfaceAreaQuery
.pop();
437 private ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
438 String
[][] options
= SurfaceAreaQuery
.getModuleBuildOptions(toolChainFamilyFlag
);
439 if (options
== null || options
.length
== 0) {
442 return parseOptions(options
);
445 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
446 String
[][] options
= SurfaceAreaQuery
.getPlatformBuildOptions(toolChainFamilyFlag
);
447 if (options
== null || options
.length
== 0) {
450 return parseOptions(options
);
453 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
454 ToolChainMap map
= new ToolChainMap();
455 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
457 for (int i
= 0; i
< options
.length
; ++i
) {
458 String flagString
= options
[i
][flagIndex
];
459 if (flagString
== null) {
462 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
463 map
.put(options
[i
], flagString
.trim());
469 private void parseToolChainFamilyOptions() throws EdkException
{
470 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
473 private void parseToolChainOptions() throws EdkException
{
474 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
478 Add the current module to corresponding FV.
480 @param fvName current FV name
481 @param moduleName current module identification
483 private void updateFvs(String fvName
, FpdModuleIdentification fpdModuleId
) {
484 if (fvName
== null || fvName
.trim().length() == 0) {
487 String
[] fvNameArray
= fvName
.split("[, \t]+");
488 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
490 // Put module to corresponding fvName
492 if (fvs
.containsKey(fvNameArray
[i
])) {
493 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
494 set
.add(fpdModuleId
);
496 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
497 set
.add(fpdModuleId
);
498 fvs
.put(fvNameArray
[i
], set
);
504 Get the suffix based on module type. Current relationship are listed:
507 <b>ModuleType</b> <b>Suffix</b>
514 DXE_RUNTIME_DRIVER .DXE
519 UEFI_APPLICATION .APP
523 @param moduleType module type
525 @throws BuildException
526 If module type is null
528 public static String
getSuffix(String moduleType
) throws BuildException
{
529 if (moduleType
== null) {
530 throw new BuildException("Module type is not specified.");
533 String
[][] suffix
= { { "BASE", ".FFS"},
534 { "SEC", ".SEC" }, { "PEI_CORE", ".PEI" },
535 { "PEIM", ".PEI" }, { "DXE_CORE", ".DXE" },
536 { "DXE_DRIVER", ".DXE" }, { "DXE_RUNTIME_DRIVER", ".DXE" },
537 { "DXE_SAL_DRIVER", ".DXE" }, { "DXE_SMM_DRIVER", ".DXE" },
538 { "TOOL", ".FFS" }, { "UEFI_DRIVER", ".DXE" },
539 { "UEFI_APPLICATION", ".APP" }, { "USER_DEFINED", ".FFS" } };
541 for (int i
= 0; i
< suffix
.length
; i
++) {
542 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
556 public void addProperty(Property p
) {
557 properties
.addElement(p
);
560 public void setPlatformName(String platformName
) {
561 this.platformName
= platformName
;
564 public void setFpdFile(File fpdFile
) {
565 this.fpdFile
= fpdFile
;
568 public void setType(String type
) {