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
.FrameworkBuildTask
;
39 import org
.tianocore
.build
.global
.GlobalData
;
40 import org
.tianocore
.build
.global
.OutputManager
;
41 import org
.tianocore
.build
.global
.SurfaceAreaQuery
;
42 import org
.tianocore
.build
.id
.FpdModuleIdentification
;
43 import org
.tianocore
.build
.id
.ModuleIdentification
;
44 import org
.tianocore
.build
.id
.PlatformIdentification
;
45 import org
.tianocore
.build
.pcd
.action
.PlatformPcdPreprocessActionForBuilding
;
46 import org
.tianocore
.build
.toolchain
.ToolChainAttribute
;
47 import org
.tianocore
.build
.toolchain
.ToolChainElement
;
48 import org
.tianocore
.build
.toolchain
.ToolChainMap
;
51 <code>FpdParserTask</code> is an ANT task. The main function is parsing Framework
52 Platform Descritpion (FPD) XML file and generating its ANT build script for
53 corresponding platform.
55 <p>The task sets global properties PLATFORM, PLATFORM_DIR, PLATFORM_RELATIVE_DIR
58 <p>The task generates ${PLATFORM}_build.xml file which will be called by top level
59 build.xml. The task also generate Fv.inf files (File is for Tool GenFvImage). </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>
69 public class FpdParserTask
extends Task
{
71 private File fpdFile
= null;
73 PlatformIdentification platformId
;
78 /// Mapping from modules identification to out put file name
80 Map
<FpdModuleIdentification
, String
> outfiles
= new LinkedHashMap
<FpdModuleIdentification
, String
>();
83 /// Mapping from FV name to its modules
85 Map
<String
, Set
<FpdModuleIdentification
>> fvs
= new HashMap
<String
, Set
<FpdModuleIdentification
>>();
88 /// FpdParserTask can specify some ANT properties.
90 private Vector
<Property
> properties
= new Vector
<Property
>();
92 SurfaceAreaQuery saq
= null;
94 boolean isUnified
= true;
97 Public construct method. It is necessary for ANT task.
99 public FpdParserTask() {
103 ANT task's entry method. The main steps is described as following:
106 <li>Initialize global information (Framework DB, SPD files and all MSA files
107 listed in SPD). This step will execute only once in whole build process;</li>
108 <li>Parse specified FPD file; </li>
109 <li>Generate FV.inf files; </li>
110 <li>Generate PlatformName_build.xml file for Flatform build; </li>
111 <li>Collect PCD information. </li>
114 @throws BuildException
115 Surface area is not valid.
117 public void execute() throws BuildException
{
126 isUnified
= OutputManager
.getInstance().prepareBuildDir(getProject());
128 String buildDir
= getProject().getProperty("BUILD_DIR");
130 // For every Target and ToolChain
132 String
[] targetList
= GlobalData
.getToolChainInfo().getTargets();
133 for (int i
= 0; i
< targetList
.length
; i
++) {
134 String
[] toolchainList
= GlobalData
.getToolChainInfo().getTagnames();
135 for(int j
= 0; j
< toolchainList
.length
; j
++) {
139 String ffsCommonDir
= buildDir
+ File
.separatorChar
140 + targetList
[i
] + "_"
142 File fvDir
= new File(ffsCommonDir
+ File
.separatorChar
+ "FV");
144 getProject().setProperty("FV_DIR", fvDir
.getPath().replaceAll("(\\\\)", "/"));
149 genFvInfFiles(ffsCommonDir
);
156 String platformBuildFile
= buildDir
+ File
.separatorChar
+ platformId
.getName() + "_build.xml";
157 PlatformBuildFileGenerator fileGenerator
= new PlatformBuildFileGenerator(getProject(), outfiles
, fvs
, isUnified
, saq
, platformBuildFile
);
158 fileGenerator
.genBuildFile();
161 // Ant call ${PLATFORM}_build.xml
164 ant
.setProject(getProject());
165 ant
.setAntfile(platformBuildFile
);
167 ant
.setInheritAll(true);
173 Generate Fv.inf files. The Fv.inf file is composed with four
174 parts: Options, Attributes, Components and Files. The Fv.inf files
175 will be under FV_DIR.
177 @throws BuildException
178 File write FV.inf files error.
180 void genFvInfFiles(String ffsCommonDir
) throws BuildException
{
181 String
[] validFv
= saq
.getFpdValidImageNames();
182 for (int i
= 0; i
< validFv
.length
; i
++) {
184 // Get all global variables from FPD and set them to properties
186 String
[][] globalVariables
= saq
.getFpdGlobalVariable();
187 for (int j
= 0; j
< globalVariables
.length
; j
++) {
188 getProject().setProperty(globalVariables
[j
][0], globalVariables
[j
][1]);
191 getProject().setProperty("FV_FILENAME", validFv
[i
]);
193 File fvFile
= new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File
.separatorChar
+ validFv
[i
] + ".inf"));
194 fvFile
.getParentFile().mkdirs();
197 FileWriter fw
= new FileWriter(fvFile
);
198 BufferedWriter bw
= new BufferedWriter(fw
);
203 String
[][] options
= saq
.getFpdOptions(validFv
[i
]);
204 if (options
.length
> 0) {
205 bw
.write("[options]");
207 for (int j
= 0; j
< options
.length
; j
++) {
208 StringBuffer str
= new StringBuffer(100);
209 str
.append(options
[j
][0]);
210 while (str
.length() < 40) {
214 str
.append(options
[j
][1]);
215 bw
.write(getProject().replaceProperties(str
.toString()));
224 String
[][] attributes
= saq
.getFpdAttributes(validFv
[i
]);
225 if (attributes
.length
> 0) {
226 bw
.write("[attributes]");
228 for (int j
= 0; j
< attributes
.length
; j
++) {
229 StringBuffer str
= new StringBuffer(100);
230 str
.append(attributes
[j
][0]);
231 while (str
.length() < 40) {
235 str
.append(attributes
[j
][1]);
236 bw
.write(getProject().replaceProperties(str
.toString()));
245 String
[][] components
= saq
.getFpdComponents(validFv
[i
]);
246 if (components
.length
> 0) {
247 bw
.write("[components]");
249 for (int j
= 0; j
< components
.length
; j
++) {
250 StringBuffer str
= new StringBuffer(100);
251 str
.append(components
[j
][0]);
252 while (str
.length() < 40) {
256 str
.append(components
[j
][1]);
257 bw
.write(getProject().replaceProperties(str
.toString()));
266 Set
<FpdModuleIdentification
> filesSet
= fvs
.get(validFv
[i
]);
267 if (filesSet
!= null) {
268 FpdModuleIdentification
[] files
= filesSet
.toArray(new FpdModuleIdentification
[filesSet
.size()]);
271 for (int j
= 0; j
< files
.length
; j
++) {
272 String str
= ffsCommonDir
+ File
.separatorChar
+ outfiles
.get(files
[j
]);
273 bw
.write(getProject().replaceProperties("EFI_FILE_NAME = " + str
));
280 } catch (Exception e
) {
281 throw new BuildException("Generation of the FV file [" + fvFile
.getPath() + "] failed!\n" + e
.getMessage());
286 This method is used for Single Module Build.
289 @throws BuildException
290 FPD file is not valid.
292 public void parseFpdFile(File fpdFile
) throws BuildException
{
293 this.fpdFile
= fpdFile
;
300 @throws BuildException
301 FPD file is not valid.
303 void parseFpdFile() throws BuildException
{
305 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
307 if (!doc
.validate()) {
308 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] format is invalid!");
311 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
312 map
.put("PlatformSurfaceArea", doc
);
313 saq
= new SurfaceAreaQuery(map
);
318 platformId
= saq
.getFpdHeader();
319 platformId
.setFpdFile(fpdFile
);
320 getProject().setProperty("PLATFORM", platformId
.getName());
321 getProject().setProperty("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
322 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
323 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
325 if( !FrameworkBuildTask
.multithread
) {
326 FrameworkBuildTask
.originalProperties
.put("PLATFORM", platformId
.getName());
327 FrameworkBuildTask
.originalProperties
.put("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
328 FrameworkBuildTask
.originalProperties
.put("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
329 FrameworkBuildTask
.originalProperties
.put("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
333 // Build mode. User-defined output dir.
335 String buildMode
= saq
.getFpdIntermediateDirectories();
336 String userDefinedOutputDir
= saq
.getFpdOutputDirectory();
338 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
341 // TBD. Deal PCD and BuildOption related Info
343 GlobalData
.setFpdBuildOptions(saq
.getFpdBuildOptions());
345 GlobalData
.setToolChainPlatformInfo(saq
.getFpdToolChainInfo());
348 // Parse all list modules SA
350 parseModuleSAFiles();
353 // TBD. Deal PCD and BuildOption related Info
355 parseToolChainFamilyOptions();
356 parseToolChainOptions();
361 // Pcd Collection. Call CollectPCDAction to collect pcd info.
363 PlatformPcdPreprocessActionForBuilding ca
= new PlatformPcdPreprocessActionForBuilding();
364 ca
.perform(platformId
.getFpdFile().getPath(), ActionMessage
.NULL_MESSAGE_LEVEL
);
365 } catch (Exception e
) {
366 throw new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + e
.getMessage());
371 Parse all modules listed in FPD file.
373 void parseModuleSAFiles() throws EdkException
{
374 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= saq
.getFpdModules();
377 // For every Module lists in FPD file.
379 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
380 Iterator iter
= keys
.iterator();
381 while (iter
.hasNext()) {
382 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
385 // Judge if Module is existed?
387 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
390 // Put fpdModuleId to the corresponding FV
392 saq
.push(GlobalData
.getDoc(fpdModuleId
));
393 String fvBinding
= saq
.getModuleFvBindingKeyword();
395 fpdModuleId
.setFvBinding(fvBinding
);
396 updateFvs(fvBinding
, fpdModuleId
);
399 // Prepare for out put file name
401 ModuleIdentification moduleId
= fpdModuleId
.getModule();
403 String baseName
= saq
.getModuleOutputFileBasename();
405 if (baseName
== null) {
406 baseName
= moduleId
.getName();
408 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
409 + moduleId
.getGuid() + "-" + baseName
410 + getSuffix(moduleId
.getModuleType()));
413 // parse module build options, if any
415 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
416 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
421 ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
422 String
[][] options
= saq
.getModuleBuildOptions(toolChainFamilyFlag
);
423 if (options
== null || options
.length
== 0) {
424 return new ToolChainMap();
426 return parseOptions(options
);
429 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
430 String
[][] options
= saq
.getPlatformBuildOptions(toolChainFamilyFlag
);
431 if (options
== null || options
.length
== 0) {
432 return new ToolChainMap();
434 return parseOptions(options
);
437 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
438 ToolChainMap map
= new ToolChainMap();
439 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
441 for (int i
= 0; i
< options
.length
; ++i
) {
442 String flagString
= options
[i
][flagIndex
];
443 if (flagString
== null) {
446 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
447 map
.put(options
[i
], flagString
.trim());
453 private void parseToolChainFamilyOptions() throws EdkException
{
454 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
457 private void parseToolChainOptions() throws EdkException
{
458 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
462 Add the current module to corresponding FV.
464 @param fvName current FV name
465 @param moduleName current module identification
467 void updateFvs(String fvName
, FpdModuleIdentification fpdModuleId
) {
468 if (fvName
== null || fvName
.trim().length() == 0) {
471 String
[] fvNameArray
= fvName
.split("[, \t]+");
472 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
474 // Put module to corresponding fvName
476 if (fvs
.containsKey(fvNameArray
[i
])) {
477 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
478 set
.add(fpdModuleId
);
480 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
481 set
.add(fpdModuleId
);
482 fvs
.put(fvNameArray
[i
], set
);
488 Get the suffix based on module type. Current relationship are listed:
491 <b>ModuleType</b> <b>Suffix</b>
498 DXE_RUNTIME_DRIVER .DXE
503 UEFI_APPLICATION .APP
507 @param moduleType module type
509 @throws BuildException
510 If module type is null
512 public static String
getSuffix(String moduleType
) throws BuildException
{
513 if (moduleType
== null) {
514 throw new BuildException("Module type is not specified.");
517 String
[][] suffix
= EdkDefinitions
.ModuleTypeExtensions
;
519 for (int i
= 0; i
< suffix
.length
; i
++) {
520 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
534 public void addProperty(Property p
) {
535 properties
.addElement(p
);
538 public void setFpdFile(File fpdFile
) {
539 this.fpdFile
= fpdFile
;
542 public void setType(String type
) {
546 public String
getAllArchForModule(ModuleIdentification moduleId
) {
548 Iterator
<FpdModuleIdentification
> iter
= outfiles
.keySet().iterator();
549 while (iter
.hasNext()) {
550 FpdModuleIdentification fpdModuleId
= iter
.next();
552 if (fpdModuleId
.getModule().equals(moduleId
)) {
553 archs
+= fpdModuleId
.getArch() + " ";