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
) throws BuildException
{
309 this.fpdFile
= fpdFile
;
315 @throws BuildException
316 FPD file is not valid.
318 private void parseFpdFile() throws BuildException
{
320 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
322 if (!doc
.validate()) {
323 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] format is invalid!");
326 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
327 map
.put("PlatformSurfaceArea", doc
);
328 SurfaceAreaQuery
.setDoc(map
);
333 platformId
= SurfaceAreaQuery
.getFpdHeader();
334 platformId
.setFpdFile(fpdFile
);
335 getProject().setProperty("PLATFORM", platformId
.getName());
336 getProject().setProperty("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
337 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
338 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
341 // Build mode. User-defined output dir.
343 String buildMode
= SurfaceAreaQuery
.getFpdIntermediateDirectories();
344 String userDefinedOutputDir
= SurfaceAreaQuery
.getFpdOutputDirectory();
346 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
349 // TBD. Deal PCD and BuildOption related Info
351 GlobalData
.setFpdBuildOptions(SurfaceAreaQuery
.getFpdBuildOptions());
353 GlobalData
.setToolChainPlatformInfo(SurfaceAreaQuery
.getFpdToolChainInfo());
356 // Parse all list modules SA
358 parseModuleSAFiles();
361 // TBD. Deal PCD and BuildOption related Info
363 parseToolChainFamilyOptions();
364 parseToolChainOptions();
366 SurfaceAreaQuery
.setDoc(map
);
369 // Pcd Collection. Call CollectPCDAction to collect pcd info.
371 PlatformPcdPreprocessActionForBuilding ca
= new PlatformPcdPreprocessActionForBuilding();
372 ca
.perform(platformId
.getFpdFile().getPath(), ActionMessage
.NULL_MESSAGE_LEVEL
);
373 } catch (Exception e
) {
374 throw new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + e
.getMessage());
379 Parse all modules listed in FPD file.
381 private void parseModuleSAFiles() throws EdkException
{
382 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= SurfaceAreaQuery
.getFpdModules();
385 // For every Module lists in FPD file.
387 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
388 Iterator iter
= keys
.iterator();
389 while (iter
.hasNext()) {
390 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
393 // Judge if Module is existed?
395 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
398 // Put fpdModuleId to the corresponding FV
400 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
401 String fvBinding
= SurfaceAreaQuery
.getModuleFvBindingKeyword();
403 fpdModuleId
.setFvBinding(fvBinding
);
404 updateFvs(fvBinding
, fpdModuleId
);
407 // Prepare for out put file name
409 ModuleIdentification moduleId
= fpdModuleId
.getModule();
411 String baseName
= SurfaceAreaQuery
.getModuleOutputFileBasename();
413 if (baseName
== null) {
414 baseName
= moduleId
.getName();
416 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
417 + moduleId
.getGuid() + "-" + baseName
418 + getSuffix(moduleId
.getModuleType()));
421 // parse module build options, if any
423 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
424 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
425 SurfaceAreaQuery
.pop();
429 private ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
430 String
[][] options
= SurfaceAreaQuery
.getModuleBuildOptions(toolChainFamilyFlag
);
431 if (options
== null || options
.length
== 0) {
432 return new ToolChainMap();
434 return parseOptions(options
);
437 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
438 String
[][] options
= SurfaceAreaQuery
.getPlatformBuildOptions(toolChainFamilyFlag
);
439 if (options
== null || options
.length
== 0) {
440 return new ToolChainMap();
442 return parseOptions(options
);
445 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
446 ToolChainMap map
= new ToolChainMap();
447 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
449 for (int i
= 0; i
< options
.length
; ++i
) {
450 String flagString
= options
[i
][flagIndex
];
451 if (flagString
== null) {
454 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
455 map
.put(options
[i
], flagString
.trim());
461 private void parseToolChainFamilyOptions() throws EdkException
{
462 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
465 private void parseToolChainOptions() throws EdkException
{
466 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
470 Add the current module to corresponding FV.
472 @param fvName current FV name
473 @param moduleName current module identification
475 private void updateFvs(String fvName
, FpdModuleIdentification fpdModuleId
) {
476 if (fvName
== null || fvName
.trim().length() == 0) {
479 String
[] fvNameArray
= fvName
.split("[, \t]+");
480 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
482 // Put module to corresponding fvName
484 if (fvs
.containsKey(fvNameArray
[i
])) {
485 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
486 set
.add(fpdModuleId
);
488 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
489 set
.add(fpdModuleId
);
490 fvs
.put(fvNameArray
[i
], set
);
496 Get the suffix based on module type. Current relationship are listed:
499 <b>ModuleType</b> <b>Suffix</b>
506 DXE_RUNTIME_DRIVER .DXE
511 UEFI_APPLICATION .APP
515 @param moduleType module type
517 @throws BuildException
518 If module type is null
520 public static String
getSuffix(String moduleType
) throws BuildException
{
521 if (moduleType
== null) {
522 throw new BuildException("Module type is not specified.");
525 String
[][] suffix
= EdkDefinitions
.ModuleTypeExtensions
;
527 for (int i
= 0; i
< suffix
.length
; i
++) {
528 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
542 public void addProperty(Property p
) {
543 properties
.addElement(p
);
546 public void setPlatformName(String platformName
) {
547 this.platformName
= platformName
;
550 public void setFpdFile(File fpdFile
) {
551 this.fpdFile
= fpdFile
;
554 public void setType(String type
) {
558 public String
getAllArchForModule(ModuleIdentification moduleId
) {
560 Iterator
<FpdModuleIdentification
> iter
= outfiles
.keySet().iterator();
561 while (iter
.hasNext()) {
562 FpdModuleIdentification fpdModuleId
= iter
.next();
564 if (fpdModuleId
.getModule().equals(moduleId
)) {
565 archs
+= fpdModuleId
.getArch() + " ";