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 SurfaceAreaQuery saq
= null;
101 private boolean isUnified
= true;
104 Public construct method. It is necessary for ANT task.
106 public FpdParserTask() {
110 ANT task's entry method. The main steps is described as following:
113 <li>Initialize global information (Framework DB, SPD files and all MSA files
114 listed in SPD). This step will execute only once in whole build process;</li>
115 <li>Parse specified FPD file; </li>
116 <li>Generate FV.inf files; </li>
117 <li>Generate PlatformName_build.xml file for Flatform build; </li>
118 <li>Collect PCD information. </li>
121 @throws BuildException
122 Surface area is not valid.
124 public void execute() throws BuildException
{
126 // If fpdFile is not specified,
127 // then try to get FPD file by platformName
129 if ( fpdFile
== null) {
130 if (platformName
== null) {
131 throw new BuildException("FpdParserTask parameter error. Please specify either the platform name or FPD file!");
133 platformId
= GlobalData
.getPlatformByName(platformName
);
134 fpdFile
= platformId
.getFpdFile();
145 isUnified
= OutputManager
.getInstance().prepareBuildDir(getProject());
148 // For every Target and ToolChain
150 String
[] targetList
= GlobalData
.getToolChainInfo().getTargets();
151 for (int i
= 0; i
< targetList
.length
; i
++) {
152 String
[] toolchainList
= GlobalData
.getToolChainInfo().getTagnames();
153 for(int j
= 0; j
< toolchainList
.length
; j
++) {
157 String ffsCommonDir
= getProject().getProperty("BUILD_DIR") + File
.separatorChar
158 + targetList
[i
] + "_"
160 File fvDir
= new File(ffsCommonDir
+ File
.separatorChar
+ "FV");
162 getProject().setProperty("FV_DIR", fvDir
.getPath().replaceAll("(\\\\)", "/"));
167 genFvInfFiles(ffsCommonDir
);
174 PlatformBuildFileGenerator fileGenerator
= new PlatformBuildFileGenerator(getProject(), outfiles
, fvs
, isUnified
, saq
);
175 fileGenerator
.genBuildFile();
178 // Ant call ${PLATFORM}_build.xml
182 ant
.setProject(getProject());
183 ant
.setAntfile(platformId
.getFpdFile().getParent() + File
.separatorChar
+ platformId
.getName() + "_build.xml");
185 ant
.setInheritAll(true);
191 Generate Fv.inf files. The Fv.inf file is composed with four
192 parts: Options, Attributes, Components and Files. The Fv.inf files
193 will be under FV_DIR.
195 @throws BuildException
196 File write FV.inf files error.
198 private void genFvInfFiles(String ffsCommonDir
) throws BuildException
{
199 String
[] validFv
= saq
.getFpdValidImageNames();
200 for (int i
= 0; i
< validFv
.length
; i
++) {
202 // Get all global variables from FPD and set them to properties
204 String
[][] globalVariables
= saq
.getFpdGlobalVariable();
205 for (int j
= 0; j
< globalVariables
.length
; j
++) {
206 getProject().setProperty(globalVariables
[j
][0], globalVariables
[j
][1]);
209 getProject().setProperty("FV_FILENAME", validFv
[i
]);
211 File fvFile
= new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File
.separatorChar
+ validFv
[i
] + ".inf"));
212 fvFile
.getParentFile().mkdirs();
215 FileWriter fw
= new FileWriter(fvFile
);
216 BufferedWriter bw
= new BufferedWriter(fw
);
221 String
[][] options
= saq
.getFpdOptions(validFv
[i
]);
222 if (options
.length
> 0) {
223 bw
.write("[options]");
225 for (int j
= 0; j
< options
.length
; j
++) {
226 StringBuffer str
= new StringBuffer(100);
227 str
.append(options
[j
][0]);
228 while (str
.length() < 40) {
232 str
.append(options
[j
][1]);
233 bw
.write(getProject().replaceProperties(str
.toString()));
242 String
[][] attributes
= saq
.getFpdAttributes(validFv
[i
]);
243 if (attributes
.length
> 0) {
244 bw
.write("[attributes]");
246 for (int j
= 0; j
< attributes
.length
; j
++) {
247 StringBuffer str
= new StringBuffer(100);
248 str
.append(attributes
[j
][0]);
249 while (str
.length() < 40) {
253 str
.append(attributes
[j
][1]);
254 bw
.write(getProject().replaceProperties(str
.toString()));
263 String
[][] components
= saq
.getFpdComponents(validFv
[i
]);
264 if (components
.length
> 0) {
265 bw
.write("[components]");
267 for (int j
= 0; j
< components
.length
; j
++) {
268 StringBuffer str
= new StringBuffer(100);
269 str
.append(components
[j
][0]);
270 while (str
.length() < 40) {
274 str
.append(components
[j
][1]);
275 bw
.write(getProject().replaceProperties(str
.toString()));
284 Set
<FpdModuleIdentification
> filesSet
= fvs
.get(validFv
[i
]);
285 if (filesSet
!= null) {
286 FpdModuleIdentification
[] files
= filesSet
.toArray(new FpdModuleIdentification
[filesSet
.size()]);
289 for (int j
= 0; j
< files
.length
; j
++) {
290 String str
= ffsCommonDir
+ File
.separatorChar
+ outfiles
.get(files
[j
]);
291 bw
.write(getProject().replaceProperties("EFI_FILE_NAME = " + str
));
298 } catch (Exception e
) {
299 throw new BuildException("Generation of the FV file [" + fvFile
.getPath() + "] failed!\n" + e
.getMessage());
304 This method is used for Single Module Build.
307 @throws BuildException
308 FPD file is not valid.
310 public void parseFpdFile(File fpdFile
) throws BuildException
{
311 this.fpdFile
= fpdFile
;
317 @throws BuildException
318 FPD file is not valid.
320 private void parseFpdFile() throws BuildException
{
322 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
324 if (!doc
.validate()) {
325 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] format is invalid!");
328 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
329 map
.put("PlatformSurfaceArea", doc
);
330 saq
= new SurfaceAreaQuery(map
);
335 platformId
= saq
.getFpdHeader();
336 platformId
.setFpdFile(fpdFile
);
337 getProject().setProperty("PLATFORM", platformId
.getName());
338 getProject().setProperty("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
339 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
340 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
343 // Build mode. User-defined output dir.
345 String buildMode
= saq
.getFpdIntermediateDirectories();
346 String userDefinedOutputDir
= saq
.getFpdOutputDirectory();
348 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
351 // TBD. Deal PCD and BuildOption related Info
353 GlobalData
.setFpdBuildOptions(saq
.getFpdBuildOptions());
355 GlobalData
.setToolChainPlatformInfo(saq
.getFpdToolChainInfo());
358 // Parse all list modules SA
360 parseModuleSAFiles();
363 // TBD. Deal PCD and BuildOption related Info
365 parseToolChainFamilyOptions();
366 parseToolChainOptions();
371 // Pcd Collection. Call CollectPCDAction to collect pcd info.
373 PlatformPcdPreprocessActionForBuilding ca
= new PlatformPcdPreprocessActionForBuilding();
374 ca
.perform(platformId
.getFpdFile().getPath(), ActionMessage
.NULL_MESSAGE_LEVEL
);
375 } catch (Exception e
) {
376 throw new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + e
.getMessage());
381 Parse all modules listed in FPD file.
383 private void parseModuleSAFiles() throws EdkException
{
384 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= saq
.getFpdModules();
387 // For every Module lists in FPD file.
389 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
390 Iterator iter
= keys
.iterator();
391 while (iter
.hasNext()) {
392 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
395 // Judge if Module is existed?
397 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
400 // Put fpdModuleId to the corresponding FV
402 saq
.push(GlobalData
.getDoc(fpdModuleId
));
403 String fvBinding
= saq
.getModuleFvBindingKeyword();
405 fpdModuleId
.setFvBinding(fvBinding
);
406 updateFvs(fvBinding
, fpdModuleId
);
409 // Prepare for out put file name
411 ModuleIdentification moduleId
= fpdModuleId
.getModule();
413 String baseName
= saq
.getModuleOutputFileBasename();
415 if (baseName
== null) {
416 baseName
= moduleId
.getName();
418 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
419 + moduleId
.getGuid() + "-" + baseName
420 + getSuffix(moduleId
.getModuleType()));
423 // parse module build options, if any
425 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
426 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
431 private ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
432 String
[][] options
= saq
.getModuleBuildOptions(toolChainFamilyFlag
);
433 if (options
== null || options
.length
== 0) {
434 return new ToolChainMap();
436 return parseOptions(options
);
439 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
440 String
[][] options
= saq
.getPlatformBuildOptions(toolChainFamilyFlag
);
441 if (options
== null || options
.length
== 0) {
442 return new ToolChainMap();
444 return parseOptions(options
);
447 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
448 ToolChainMap map
= new ToolChainMap();
449 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
451 for (int i
= 0; i
< options
.length
; ++i
) {
452 String flagString
= options
[i
][flagIndex
];
453 if (flagString
== null) {
456 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
457 map
.put(options
[i
], flagString
.trim());
463 private void parseToolChainFamilyOptions() throws EdkException
{
464 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
467 private void parseToolChainOptions() throws EdkException
{
468 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
472 Add the current module to corresponding FV.
474 @param fvName current FV name
475 @param moduleName current module identification
477 private void updateFvs(String fvName
, FpdModuleIdentification fpdModuleId
) {
478 if (fvName
== null || fvName
.trim().length() == 0) {
481 String
[] fvNameArray
= fvName
.split("[, \t]+");
482 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
484 // Put module to corresponding fvName
486 if (fvs
.containsKey(fvNameArray
[i
])) {
487 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
488 set
.add(fpdModuleId
);
490 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
491 set
.add(fpdModuleId
);
492 fvs
.put(fvNameArray
[i
], set
);
498 Get the suffix based on module type. Current relationship are listed:
501 <b>ModuleType</b> <b>Suffix</b>
508 DXE_RUNTIME_DRIVER .DXE
513 UEFI_APPLICATION .APP
517 @param moduleType module type
519 @throws BuildException
520 If module type is null
522 public static String
getSuffix(String moduleType
) throws BuildException
{
523 if (moduleType
== null) {
524 throw new BuildException("Module type is not specified.");
527 String
[][] suffix
= EdkDefinitions
.ModuleTypeExtensions
;
529 for (int i
= 0; i
< suffix
.length
; i
++) {
530 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
544 public void addProperty(Property p
) {
545 properties
.addElement(p
);
548 public void setPlatformName(String platformName
) {
549 this.platformName
= platformName
;
552 public void setFpdFile(File fpdFile
) {
553 this.fpdFile
= fpdFile
;
556 public void setType(String type
) {
560 public String
getAllArchForModule(ModuleIdentification moduleId
) {
562 Iterator
<FpdModuleIdentification
> iter
= outfiles
.keySet().iterator();
563 while (iter
.hasNext()) {
564 FpdModuleIdentification fpdModuleId
= iter
.next();
566 if (fpdModuleId
.getModule().equals(moduleId
)) {
567 archs
+= fpdModuleId
.getArch() + " ";