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
.definitions
.EdkDefinitions
;
36 import org
.tianocore
.common
.exception
.EdkException
;
37 import org
.tianocore
.pcd
.action
.ActionMessage
;
38 import org
.tianocore
.build
.global
.GlobalData
;
39 import org
.tianocore
.build
.global
.OutputManager
;
40 import org
.tianocore
.build
.global
.SurfaceAreaQuery
;
41 import org
.tianocore
.build
.id
.FpdModuleIdentification
;
42 import org
.tianocore
.build
.id
.ModuleIdentification
;
43 import org
.tianocore
.build
.id
.PlatformIdentification
;
44 import org
.tianocore
.build
.pcd
.action
.PlatformPcdPreprocessActionForBuilding
;
45 import org
.tianocore
.build
.toolchain
.ToolChainAttribute
;
46 import org
.tianocore
.build
.toolchain
.ToolChainElement
;
47 import org
.tianocore
.build
.toolchain
.ToolChainMap
;
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.
54 <p>The task sets global properties PLATFORM, PLATFORM_DIR, PLATFORM_RELATIVE_DIR
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>
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>
65 <p>The method parseFpdFile is also prepared for single module build. </p>
67 <p>The usage is (take NT32 Platform for example):</p>
70 <FPDParser platformName="Nt32" />
73 <p>The task will initialize all information through parsing Framework Database,
74 SPD, Tool chain configuration files. </p>
78 public class FpdParserTask
extends Task
{
80 private String platformName
;
82 private File fpdFile
= null;
84 private PlatformIdentification platformId
;
89 /// Mapping from modules identification to out put file name
91 private Map
<FpdModuleIdentification
, String
> outfiles
= new LinkedHashMap
<FpdModuleIdentification
, String
>();
94 /// Mapping from FV name to its modules
96 private Map
<String
, Set
<FpdModuleIdentification
>> fvs
= new HashMap
<String
, Set
<FpdModuleIdentification
>>();
99 /// FpdParserTask can specify some ANT properties.
101 private Vector
<Property
> properties
= new Vector
<Property
>();
103 private boolean isUnified
= true;
107 Public construct method. It is necessary for ANT task.
109 public FpdParserTask() {
113 ANT task's entry method. The main steps is described as following:
116 <li>Initialize global information (Framework DB, SPD files and all MSA files
117 listed in SPD). This step will execute only once in whole build process;</li>
118 <li>Parse specified FPD file; </li>
119 <li>Generate FV.inf files; </li>
120 <li>Generate PlatformName_build.xml file for Flatform build; </li>
121 <li>Collect PCD information. </li>
124 @throws BuildException
125 Surface area is not valid.
127 public void execute() throws BuildException
{
129 // If fpdFile is not specified,
130 // then try to get FPD file by platformName
132 if ( fpdFile
== null) {
133 if (platformName
== null) {
134 throw new BuildException("FpdParserTask parameter error. Please specify either the platform name or FPD file!");
136 platformId
= GlobalData
.getPlatformByName(platformName
);
137 fpdFile
= platformId
.getFpdFile();
148 isUnified
= OutputManager
.getInstance().prepareBuildDir(getProject());
151 // For every Target and ToolChain
153 String
[] targetList
= GlobalData
.getToolChainInfo().getTargets();
154 for (int i
= 0; i
< targetList
.length
; i
++) {
155 String
[] toolchainList
= GlobalData
.getToolChainInfo().getTagnames();
156 for(int j
= 0; j
< toolchainList
.length
; j
++) {
160 String ffsCommonDir
= getProject().getProperty("BUILD_DIR") + File
.separatorChar
161 + targetList
[i
] + File
.separatorChar
163 File fvDir
= new File(ffsCommonDir
+ File
.separatorChar
+ "FV");
165 getProject().setProperty("FV_DIR", fvDir
.getPath().replaceAll("(\\\\)", "/"));
170 genFvInfFiles(ffsCommonDir
);
177 PlatformBuildFileGenerator fileGenerator
= new PlatformBuildFileGenerator(getProject(), outfiles
, isUnified
);
178 fileGenerator
.genBuildFile();
181 // Ant call ${PLATFORM}_build.xml
185 ant
.setProject(getProject());
186 ant
.setAntfile(platformId
.getFpdFile().getParent() + File
.separatorChar
+ platformId
.getName() + "_build.xml");
188 ant
.setInheritAll(true);
194 Generate Fv.inf files. The Fv.inf file is composed with four
195 parts: Options, Attributes, Components and Files. The Fv.inf files
196 will be under FV_DIR.
198 @throws BuildException
199 File write FV.inf files error.
201 private void genFvInfFiles(String ffsCommonDir
) throws BuildException
{
202 String
[] validFv
= SurfaceAreaQuery
.getFpdValidImageNames();
203 for (int i
= 0; i
< validFv
.length
; i
++) {
205 // Get all global variables from FPD and set them to properties
207 String
[][] globalVariables
= SurfaceAreaQuery
.getFpdGlobalVariable();
208 for (int j
= 0; j
< globalVariables
.length
; j
++) {
209 getProject().setProperty(globalVariables
[j
][0], globalVariables
[j
][1]);
212 getProject().setProperty("FV_FILENAME", validFv
[i
]);
214 File fvFile
= new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File
.separatorChar
+ validFv
[i
] + ".inf"));
215 fvFile
.getParentFile().mkdirs();
218 FileWriter fw
= new FileWriter(fvFile
);
219 BufferedWriter bw
= new BufferedWriter(fw
);
224 String
[][] options
= SurfaceAreaQuery
.getFpdOptions(validFv
[i
]);
225 if (options
.length
> 0) {
226 bw
.write("[options]");
228 for (int j
= 0; j
< options
.length
; j
++) {
229 StringBuffer str
= new StringBuffer(100);
230 str
.append(options
[j
][0]);
231 while (str
.length() < 40) {
235 str
.append(options
[j
][1]);
236 bw
.write(getProject().replaceProperties(str
.toString()));
245 String
[][] attributes
= SurfaceAreaQuery
.getFpdAttributes(validFv
[i
]);
246 if (attributes
.length
> 0) {
247 bw
.write("[attributes]");
249 for (int j
= 0; j
< attributes
.length
; j
++) {
250 StringBuffer str
= new StringBuffer(100);
251 str
.append(attributes
[j
][0]);
252 while (str
.length() < 40) {
256 str
.append(attributes
[j
][1]);
257 bw
.write(getProject().replaceProperties(str
.toString()));
266 String
[][] components
= SurfaceAreaQuery
.getFpdComponents(validFv
[i
]);
267 if (components
.length
> 0) {
268 bw
.write("[components]");
270 for (int j
= 0; j
< components
.length
; j
++) {
271 StringBuffer str
= new StringBuffer(100);
272 str
.append(components
[j
][0]);
273 while (str
.length() < 40) {
277 str
.append(components
[j
][1]);
278 bw
.write(getProject().replaceProperties(str
.toString()));
287 Set
<FpdModuleIdentification
> filesSet
= fvs
.get(validFv
[i
]);
288 if (filesSet
!= null) {
289 FpdModuleIdentification
[] files
= filesSet
.toArray(new FpdModuleIdentification
[filesSet
.size()]);
292 for (int j
= 0; j
< files
.length
; j
++) {
293 String str
= ffsCommonDir
+ File
.separatorChar
+ outfiles
.get(files
[j
]);
294 bw
.write(getProject().replaceProperties("EFI_FILE_NAME = " + str
));
301 } catch (Exception e
) {
302 throw new BuildException("Generation of the FV file [" + fvFile
.getPath() + "] failed!\n" + e
.getMessage());
307 This method is used for Single Module Build.
310 @throws BuildException
311 FPD file is not valid.
313 public void parseFpdFile(File fpdFile
) throws BuildException
{
314 this.fpdFile
= fpdFile
;
321 @throws BuildException
322 FPD file is not valid.
324 private void parseFpdFile() throws BuildException
{
326 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
328 if (!doc
.validate()) {
329 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] format is invalid!");
332 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
333 map
.put("PlatformSurfaceArea", doc
);
334 SurfaceAreaQuery
.setDoc(map
);
339 platformId
= SurfaceAreaQuery
.getFpdHeader();
340 platformId
.setFpdFile(fpdFile
);
341 getProject().setProperty("PLATFORM", platformId
.getName());
342 getProject().setProperty("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
343 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
344 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
347 // Build mode. User-defined output dir.
349 String buildMode
= SurfaceAreaQuery
.getFpdIntermediateDirectories();
350 String userDefinedOutputDir
= SurfaceAreaQuery
.getFpdOutputDirectory();
352 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
355 // TBD. Deal PCD and BuildOption related Info
357 GlobalData
.setFpdBuildOptions(SurfaceAreaQuery
.getFpdBuildOptions());
359 GlobalData
.setToolChainPlatformInfo(SurfaceAreaQuery
.getFpdToolChainInfo());
362 // Parse all list modules SA
364 parseModuleSAFiles();
367 // TBD. Deal PCD and BuildOption related Info
369 parseToolChainFamilyOptions();
370 parseToolChainOptions();
372 SurfaceAreaQuery
.setDoc(map
);
375 // Pcd Collection. Call CollectPCDAction to collect pcd info.
377 PlatformPcdPreprocessActionForBuilding ca
= new PlatformPcdPreprocessActionForBuilding();
378 ca
.perform(platformId
.getFpdFile().getPath(), ActionMessage
.NULL_MESSAGE_LEVEL
);
379 } catch (Exception e
) {
380 throw new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + e
.getMessage());
387 Parse all modules listed in FPD file.
389 private void parseModuleSAFiles() throws EdkException
{
390 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= SurfaceAreaQuery
.getFpdModules();
393 // For every Module lists in FPD file.
395 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
396 Iterator iter
= keys
.iterator();
397 while (iter
.hasNext()) {
398 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
401 // Judge if Module is existed?
404 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
407 // Put fpdModuleId to the corresponding FV
409 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
410 String fvBinding
= SurfaceAreaQuery
.getModuleFvBindingKeyword();
412 fpdModuleId
.setFvBinding(fvBinding
);
413 updateFvs(fvBinding
, fpdModuleId
);
416 // Prepare for out put file name
418 ModuleIdentification moduleId
= fpdModuleId
.getModule();
420 String baseName
= SurfaceAreaQuery
.getModuleOutputFileBasename();
422 if (baseName
== null) {
423 baseName
= moduleId
.getName();
425 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
426 + moduleId
.getGuid() + "-" + baseName
427 + getSuffix(moduleId
.getModuleType()));
430 // parse module build options, if any
432 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
433 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
434 SurfaceAreaQuery
.pop();
438 private ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
439 String
[][] options
= SurfaceAreaQuery
.getModuleBuildOptions(toolChainFamilyFlag
);
440 if (options
== null || options
.length
== 0) {
443 return parseOptions(options
);
446 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
447 String
[][] options
= SurfaceAreaQuery
.getPlatformBuildOptions(toolChainFamilyFlag
);
448 if (options
== null || options
.length
== 0) {
451 return parseOptions(options
);
454 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
455 ToolChainMap map
= new ToolChainMap();
456 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
458 for (int i
= 0; i
< options
.length
; ++i
) {
459 String flagString
= options
[i
][flagIndex
];
460 if (flagString
== null) {
463 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
464 map
.put(options
[i
], flagString
.trim());
470 private void parseToolChainFamilyOptions() throws EdkException
{
471 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
474 private void parseToolChainOptions() throws EdkException
{
475 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
479 Add the current module to corresponding FV.
481 @param fvName current FV name
482 @param moduleName current module identification
484 private void updateFvs(String fvName
, FpdModuleIdentification fpdModuleId
) {
485 if (fvName
== null || fvName
.trim().length() == 0) {
488 String
[] fvNameArray
= fvName
.split("[, \t]+");
489 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
491 // Put module to corresponding fvName
493 if (fvs
.containsKey(fvNameArray
[i
])) {
494 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
495 set
.add(fpdModuleId
);
497 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
498 set
.add(fpdModuleId
);
499 fvs
.put(fvNameArray
[i
], set
);
505 Get the suffix based on module type. Current relationship are listed:
508 <b>ModuleType</b> <b>Suffix</b>
515 DXE_RUNTIME_DRIVER .DXE
520 UEFI_APPLICATION .APP
524 @param moduleType module type
526 @throws BuildException
527 If module type is null
529 public static String
getSuffix(String moduleType
) throws BuildException
{
530 if (moduleType
== null) {
531 throw new BuildException("Module type is not specified.");
534 String
[][] suffix
= EdkDefinitions
.ModuleTypeExtensions
;
536 for (int i
= 0; i
< suffix
.length
; i
++) {
537 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
551 public void addProperty(Property p
) {
552 properties
.addElement(p
);
555 public void setPlatformName(String platformName
) {
556 this.platformName
= platformName
;
559 public void setFpdFile(File fpdFile
) {
560 this.fpdFile
= fpdFile
;
563 public void setType(String type
) {