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). </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" />
74 public class FpdParserTask
extends Task
{
76 private String platformName
;
78 private File fpdFile
= null;
80 private PlatformIdentification platformId
;
85 /// Mapping from modules identification to out put file name
87 private Map
<FpdModuleIdentification
, String
> outfiles
= new LinkedHashMap
<FpdModuleIdentification
, String
>();
90 /// Mapping from FV name to its modules
92 private Map
<String
, Set
<FpdModuleIdentification
>> fvs
= new HashMap
<String
, Set
<FpdModuleIdentification
>>();
95 /// FpdParserTask can specify some ANT properties.
97 private Vector
<Property
> properties
= new Vector
<Property
>();
99 private boolean isUnified
= true;
102 Public construct method. It is necessary for ANT task.
104 public FpdParserTask() {
108 ANT task's entry method. The main steps is described as following:
111 <li>Initialize global information (Framework DB, SPD files and all MSA files
112 listed in SPD). This step will execute only once in whole build process;</li>
113 <li>Parse specified FPD file; </li>
114 <li>Generate FV.inf files; </li>
115 <li>Generate PlatformName_build.xml file for Flatform build; </li>
116 <li>Collect PCD information. </li>
119 @throws BuildException
120 Surface area is not valid.
122 public void execute() throws BuildException
{
124 // If fpdFile is not specified,
125 // then try to get FPD file by platformName
127 if ( fpdFile
== null) {
128 if (platformName
== null) {
129 throw new BuildException("FpdParserTask parameter error. Please specify either the platform name or FPD file!");
131 platformId
= GlobalData
.getPlatformByName(platformName
);
132 fpdFile
= platformId
.getFpdFile();
143 isUnified
= OutputManager
.getInstance().prepareBuildDir(getProject());
146 // For every Target and ToolChain
148 String
[] targetList
= GlobalData
.getToolChainInfo().getTargets();
149 for (int i
= 0; i
< targetList
.length
; i
++) {
150 String
[] toolchainList
= GlobalData
.getToolChainInfo().getTagnames();
151 for(int j
= 0; j
< toolchainList
.length
; j
++) {
155 String ffsCommonDir
= getProject().getProperty("BUILD_DIR") + File
.separatorChar
156 + targetList
[i
] + "_"
158 File fvDir
= new File(ffsCommonDir
+ File
.separatorChar
+ "FV");
160 getProject().setProperty("FV_DIR", fvDir
.getPath().replaceAll("(\\\\)", "/"));
165 genFvInfFiles(ffsCommonDir
);
172 PlatformBuildFileGenerator fileGenerator
= new PlatformBuildFileGenerator(getProject(), outfiles
, fvs
, isUnified
);
173 fileGenerator
.genBuildFile();
176 // Ant call ${PLATFORM}_build.xml
180 ant
.setProject(getProject());
181 ant
.setAntfile(platformId
.getFpdFile().getParent() + File
.separatorChar
+ platformId
.getName() + "_build.xml");
183 ant
.setInheritAll(true);
189 Generate Fv.inf files. The Fv.inf file is composed with four
190 parts: Options, Attributes, Components and Files. The Fv.inf files
191 will be under FV_DIR.
193 @throws BuildException
194 File write FV.inf files error.
196 private void genFvInfFiles(String ffsCommonDir
) throws BuildException
{
197 String
[] validFv
= SurfaceAreaQuery
.getFpdValidImageNames();
198 for (int i
= 0; i
< validFv
.length
; i
++) {
200 // Get all global variables from FPD and set them to properties
202 String
[][] globalVariables
= SurfaceAreaQuery
.getFpdGlobalVariable();
203 for (int j
= 0; j
< globalVariables
.length
; j
++) {
204 getProject().setProperty(globalVariables
[j
][0], globalVariables
[j
][1]);
207 getProject().setProperty("FV_FILENAME", validFv
[i
]);
209 File fvFile
= new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File
.separatorChar
+ validFv
[i
] + ".inf"));
210 fvFile
.getParentFile().mkdirs();
213 FileWriter fw
= new FileWriter(fvFile
);
214 BufferedWriter bw
= new BufferedWriter(fw
);
219 String
[][] options
= SurfaceAreaQuery
.getFpdOptions(validFv
[i
]);
220 if (options
.length
> 0) {
221 bw
.write("[options]");
223 for (int j
= 0; j
< options
.length
; j
++) {
224 StringBuffer str
= new StringBuffer(100);
225 str
.append(options
[j
][0]);
226 while (str
.length() < 40) {
230 str
.append(options
[j
][1]);
231 bw
.write(getProject().replaceProperties(str
.toString()));
240 String
[][] attributes
= SurfaceAreaQuery
.getFpdAttributes(validFv
[i
]);
241 if (attributes
.length
> 0) {
242 bw
.write("[attributes]");
244 for (int j
= 0; j
< attributes
.length
; j
++) {
245 StringBuffer str
= new StringBuffer(100);
246 str
.append(attributes
[j
][0]);
247 while (str
.length() < 40) {
251 str
.append(attributes
[j
][1]);
252 bw
.write(getProject().replaceProperties(str
.toString()));
261 String
[][] components
= SurfaceAreaQuery
.getFpdComponents(validFv
[i
]);
262 if (components
.length
> 0) {
263 bw
.write("[components]");
265 for (int j
= 0; j
< components
.length
; j
++) {
266 StringBuffer str
= new StringBuffer(100);
267 str
.append(components
[j
][0]);
268 while (str
.length() < 40) {
272 str
.append(components
[j
][1]);
273 bw
.write(getProject().replaceProperties(str
.toString()));
282 Set
<FpdModuleIdentification
> filesSet
= fvs
.get(validFv
[i
]);
283 if (filesSet
!= null) {
284 FpdModuleIdentification
[] files
= filesSet
.toArray(new FpdModuleIdentification
[filesSet
.size()]);
287 for (int j
= 0; j
< files
.length
; j
++) {
288 String str
= ffsCommonDir
+ File
.separatorChar
+ outfiles
.get(files
[j
]);
289 bw
.write(getProject().replaceProperties("EFI_FILE_NAME = " + str
));
296 } catch (Exception e
) {
297 throw new BuildException("Generation of the FV file [" + fvFile
.getPath() + "] failed!\n" + e
.getMessage());
302 This method is used for Single Module Build.
305 @throws BuildException
306 FPD file is not valid.
308 public void parseFpdFile(File fpdFile
, ModuleIdentification singleModuleId
) throws BuildException
{
309 this.fpdFile
= fpdFile
;
310 parseFpdFile(singleModuleId
);
313 private void parseFpdFile() throws BuildException
{
319 @throws BuildException
320 FPD file is not valid.
322 private void parseFpdFile(ModuleIdentification singleModuleId
) throws BuildException
{
324 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
326 if (!doc
.validate()) {
327 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] format is invalid!");
330 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
331 map
.put("PlatformSurfaceArea", doc
);
332 SurfaceAreaQuery
.setDoc(map
);
337 platformId
= SurfaceAreaQuery
.getFpdHeader();
338 platformId
.setFpdFile(fpdFile
);
339 getProject().setProperty("PLATFORM", platformId
.getName());
340 getProject().setProperty("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
341 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
342 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
345 // Build mode. User-defined output dir.
347 String buildMode
= SurfaceAreaQuery
.getFpdIntermediateDirectories();
348 String userDefinedOutputDir
= SurfaceAreaQuery
.getFpdOutputDirectory();
350 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
353 // TBD. Deal PCD and BuildOption related Info
355 GlobalData
.setFpdBuildOptions(SurfaceAreaQuery
.getFpdBuildOptions());
357 GlobalData
.setToolChainPlatformInfo(SurfaceAreaQuery
.getFpdToolChainInfo());
360 // Parse all list modules SA
362 parseModuleSAFiles(singleModuleId
);
365 // TBD. Deal PCD and BuildOption related Info
367 parseToolChainFamilyOptions();
368 parseToolChainOptions();
370 SurfaceAreaQuery
.setDoc(map
);
373 // Pcd Collection. Call CollectPCDAction to collect pcd info.
375 PlatformPcdPreprocessActionForBuilding ca
= new PlatformPcdPreprocessActionForBuilding();
376 ca
.perform(platformId
.getFpdFile().getPath(), ActionMessage
.NULL_MESSAGE_LEVEL
);
377 } catch (Exception e
) {
378 throw new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + e
.getMessage());
385 Parse all modules listed in FPD file.
387 private void parseModuleSAFiles(ModuleIdentification singleModuleId
) throws EdkException
{
388 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= SurfaceAreaQuery
.getFpdModules();
391 // For every Module lists in FPD file.
393 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
394 Iterator iter
= keys
.iterator();
395 while (iter
.hasNext()) {
396 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
399 // If is stand-alone module build, just parse this module, pass others
401 if (singleModuleId
!= null) {
403 // pass others modules
405 if ( ! fpdModuleId
.getModule().equals(singleModuleId
)) {
411 // Judge if Module is existed?
413 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
416 // Put fpdModuleId to the corresponding FV
418 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
419 String fvBinding
= SurfaceAreaQuery
.getModuleFvBindingKeyword();
421 fpdModuleId
.setFvBinding(fvBinding
);
422 updateFvs(fvBinding
, fpdModuleId
);
425 // Prepare for out put file name
427 ModuleIdentification moduleId
= fpdModuleId
.getModule();
429 String baseName
= SurfaceAreaQuery
.getModuleOutputFileBasename();
431 if (baseName
== null) {
432 baseName
= moduleId
.getName();
434 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
435 + moduleId
.getGuid() + "-" + baseName
436 + getSuffix(moduleId
.getModuleType()));
439 // parse module build options, if any
441 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
442 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
443 SurfaceAreaQuery
.pop();
447 private ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
448 String
[][] options
= SurfaceAreaQuery
.getModuleBuildOptions(toolChainFamilyFlag
);
449 if (options
== null || options
.length
== 0) {
450 return new ToolChainMap();
452 return parseOptions(options
);
455 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
456 String
[][] options
= SurfaceAreaQuery
.getPlatformBuildOptions(toolChainFamilyFlag
);
457 if (options
== null || options
.length
== 0) {
458 return new ToolChainMap();
460 return parseOptions(options
);
463 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
464 ToolChainMap map
= new ToolChainMap();
465 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
467 for (int i
= 0; i
< options
.length
; ++i
) {
468 String flagString
= options
[i
][flagIndex
];
469 if (flagString
== null) {
472 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
473 map
.put(options
[i
], flagString
.trim());
479 private void parseToolChainFamilyOptions() throws EdkException
{
480 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
483 private void parseToolChainOptions() throws EdkException
{
484 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
488 Add the current module to corresponding FV.
490 @param fvName current FV name
491 @param moduleName current module identification
493 private void updateFvs(String fvName
, FpdModuleIdentification fpdModuleId
) {
494 if (fvName
== null || fvName
.trim().length() == 0) {
497 String
[] fvNameArray
= fvName
.split("[, \t]+");
498 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
500 // Put module to corresponding fvName
502 if (fvs
.containsKey(fvNameArray
[i
])) {
503 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
504 set
.add(fpdModuleId
);
506 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
507 set
.add(fpdModuleId
);
508 fvs
.put(fvNameArray
[i
], set
);
514 Get the suffix based on module type. Current relationship are listed:
517 <b>ModuleType</b> <b>Suffix</b>
524 DXE_RUNTIME_DRIVER .DXE
529 UEFI_APPLICATION .APP
533 @param moduleType module type
535 @throws BuildException
536 If module type is null
538 public static String
getSuffix(String moduleType
) throws BuildException
{
539 if (moduleType
== null) {
540 throw new BuildException("Module type is not specified.");
543 String
[][] suffix
= EdkDefinitions
.ModuleTypeExtensions
;
545 for (int i
= 0; i
< suffix
.length
; i
++) {
546 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
560 public void addProperty(Property p
) {
561 properties
.addElement(p
);
564 public void setPlatformName(String platformName
) {
565 this.platformName
= platformName
;
568 public void setFpdFile(File fpdFile
) {
569 this.fpdFile
= fpdFile
;
572 public void setType(String type
) {
576 public String
getAllArchForModule(ModuleIdentification moduleId
) {
578 Iterator
<FpdModuleIdentification
> iter
= outfiles
.keySet().iterator();
579 while (iter
.hasNext()) {
580 FpdModuleIdentification fpdModuleId
= iter
.next();
582 if (fpdModuleId
.getModule().equals(moduleId
)) {
583 archs
+= fpdModuleId
.getArch() + " ";