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
] + File
.separatorChar
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
;
316 @throws BuildException
317 FPD file is not valid.
319 private void parseFpdFile() throws BuildException
{
321 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
323 if (!doc
.validate()) {
324 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] format is invalid!");
327 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
328 map
.put("PlatformSurfaceArea", doc
);
329 SurfaceAreaQuery
.setDoc(map
);
334 platformId
= SurfaceAreaQuery
.getFpdHeader();
335 platformId
.setFpdFile(fpdFile
);
336 getProject().setProperty("PLATFORM", platformId
.getName());
337 getProject().setProperty("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
338 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
339 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
342 // Build mode. User-defined output dir.
344 String buildMode
= SurfaceAreaQuery
.getFpdIntermediateDirectories();
345 String userDefinedOutputDir
= SurfaceAreaQuery
.getFpdOutputDirectory();
347 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
350 // TBD. Deal PCD and BuildOption related Info
352 GlobalData
.setFpdBuildOptions(SurfaceAreaQuery
.getFpdBuildOptions());
354 GlobalData
.setToolChainPlatformInfo(SurfaceAreaQuery
.getFpdToolChainInfo());
357 // Parse all list modules SA
359 parseModuleSAFiles();
362 // TBD. Deal PCD and BuildOption related Info
364 parseToolChainFamilyOptions();
365 parseToolChainOptions();
367 SurfaceAreaQuery
.setDoc(map
);
370 // Pcd Collection. Call CollectPCDAction to collect pcd info.
372 PlatformPcdPreprocessActionForBuilding ca
= new PlatformPcdPreprocessActionForBuilding();
373 ca
.perform(platformId
.getFpdFile().getPath(), ActionMessage
.NULL_MESSAGE_LEVEL
);
374 } catch (Exception e
) {
375 throw new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + e
.getMessage());
382 Parse all modules listed in FPD file.
384 private void parseModuleSAFiles() throws EdkException
{
385 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= SurfaceAreaQuery
.getFpdModules();
388 // For every Module lists in FPD file.
390 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
391 Iterator iter
= keys
.iterator();
392 while (iter
.hasNext()) {
393 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
396 // Judge if Module is existed?
399 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
402 // Put fpdModuleId to the corresponding FV
404 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
405 String fvBinding
= SurfaceAreaQuery
.getModuleFvBindingKeyword();
407 fpdModuleId
.setFvBinding(fvBinding
);
408 updateFvs(fvBinding
, fpdModuleId
);
411 // Prepare for out put file name
413 ModuleIdentification moduleId
= fpdModuleId
.getModule();
415 String baseName
= SurfaceAreaQuery
.getModuleOutputFileBasename();
417 if (baseName
== null) {
418 baseName
= moduleId
.getName();
420 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
421 + moduleId
.getGuid() + "-" + baseName
422 + getSuffix(moduleId
.getModuleType()));
425 // parse module build options, if any
427 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
428 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
429 SurfaceAreaQuery
.pop();
433 private ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
434 String
[][] options
= SurfaceAreaQuery
.getModuleBuildOptions(toolChainFamilyFlag
);
435 if (options
== null || options
.length
== 0) {
438 return parseOptions(options
);
441 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
442 String
[][] options
= SurfaceAreaQuery
.getPlatformBuildOptions(toolChainFamilyFlag
);
443 if (options
== null || options
.length
== 0) {
446 return parseOptions(options
);
449 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
450 ToolChainMap map
= new ToolChainMap();
451 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
453 for (int i
= 0; i
< options
.length
; ++i
) {
454 String flagString
= options
[i
][flagIndex
];
455 if (flagString
== null) {
458 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
459 map
.put(options
[i
], flagString
.trim());
465 private void parseToolChainFamilyOptions() throws EdkException
{
466 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
469 private void parseToolChainOptions() throws EdkException
{
470 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
474 Add the current module to corresponding FV.
476 @param fvName current FV name
477 @param moduleName current module identification
479 private void updateFvs(String fvName
, FpdModuleIdentification fpdModuleId
) {
480 if (fvName
== null || fvName
.trim().length() == 0) {
483 String
[] fvNameArray
= fvName
.split("[, \t]+");
484 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
486 // Put module to corresponding fvName
488 if (fvs
.containsKey(fvNameArray
[i
])) {
489 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
490 set
.add(fpdModuleId
);
492 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
493 set
.add(fpdModuleId
);
494 fvs
.put(fvNameArray
[i
], set
);
500 Get the suffix based on module type. Current relationship are listed:
503 <b>ModuleType</b> <b>Suffix</b>
510 DXE_RUNTIME_DRIVER .DXE
515 UEFI_APPLICATION .APP
519 @param moduleType module type
521 @throws BuildException
522 If module type is null
524 public static String
getSuffix(String moduleType
) throws BuildException
{
525 if (moduleType
== null) {
526 throw new BuildException("Module type is not specified.");
529 String
[][] suffix
= EdkDefinitions
.ModuleTypeExtensions
;
531 for (int i
= 0; i
< suffix
.length
; i
++) {
532 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
546 public void addProperty(Property p
) {
547 properties
.addElement(p
);
550 public void setPlatformName(String platformName
) {
551 this.platformName
= platformName
;
554 public void setFpdFile(File fpdFile
) {
555 this.fpdFile
= fpdFile
;
558 public void setType(String type
) {