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>
67 <p>The usage is (take NT32 Platform for example):</p>
70 <FPDParser platformName="Nt32" />
75 public class FpdParserTask
extends Task
{
77 private String platformName
;
79 private File fpdFile
= null;
81 PlatformIdentification platformId
;
86 /// Mapping from modules identification to out put file name
88 Map
<FpdModuleIdentification
, String
> outfiles
= new LinkedHashMap
<FpdModuleIdentification
, String
>();
91 /// Mapping from FV name to its modules
93 Map
<String
, Set
<FpdModuleIdentification
>> fvs
= new HashMap
<String
, Set
<FpdModuleIdentification
>>();
96 /// FpdParserTask can specify some ANT properties.
98 private Vector
<Property
> properties
= new Vector
<Property
>();
100 SurfaceAreaQuery saq
= null;
102 boolean isUnified
= true;
105 Public construct method. It is necessary for ANT task.
107 public FpdParserTask() {
111 ANT task's entry method. The main steps is described as following:
114 <li>Initialize global information (Framework DB, SPD files and all MSA files
115 listed in SPD). This step will execute only once in whole build process;</li>
116 <li>Parse specified FPD file; </li>
117 <li>Generate FV.inf files; </li>
118 <li>Generate PlatformName_build.xml file for Flatform build; </li>
119 <li>Collect PCD information. </li>
122 @throws BuildException
123 Surface area is not valid.
125 public void execute() throws BuildException
{
127 // If fpdFile is not specified,
128 // then try to get FPD file by platformName
130 if ( fpdFile
== null) {
131 if (platformName
== null) {
132 throw new BuildException("FpdParserTask parameter error. Please specify either the platform name or FPD file!");
134 platformId
= GlobalData
.getPlatformByName(platformName
);
135 fpdFile
= platformId
.getFpdFile();
146 isUnified
= OutputManager
.getInstance().prepareBuildDir(getProject());
149 // For every Target and ToolChain
151 String
[] targetList
= GlobalData
.getToolChainInfo().getTargets();
152 for (int i
= 0; i
< targetList
.length
; i
++) {
153 String
[] toolchainList
= GlobalData
.getToolChainInfo().getTagnames();
154 for(int j
= 0; j
< toolchainList
.length
; j
++) {
158 String ffsCommonDir
= getProject().getProperty("BUILD_DIR") + File
.separatorChar
159 + targetList
[i
] + "_"
161 File fvDir
= new File(ffsCommonDir
+ File
.separatorChar
+ "FV");
163 getProject().setProperty("FV_DIR", fvDir
.getPath().replaceAll("(\\\\)", "/"));
168 genFvInfFiles(ffsCommonDir
);
175 PlatformBuildFileGenerator fileGenerator
= new PlatformBuildFileGenerator(getProject(), outfiles
, fvs
, isUnified
, saq
);
176 fileGenerator
.genBuildFile();
179 // Ant call ${PLATFORM}_build.xml
183 ant
.setProject(getProject());
184 ant
.setAntfile(platformId
.getFpdFile().getParent() + File
.separatorChar
+ platformId
.getName() + "_build.xml");
186 ant
.setInheritAll(true);
192 Generate Fv.inf files. The Fv.inf file is composed with four
193 parts: Options, Attributes, Components and Files. The Fv.inf files
194 will be under FV_DIR.
196 @throws BuildException
197 File write FV.inf files error.
199 void genFvInfFiles(String ffsCommonDir
) throws BuildException
{
200 String
[] validFv
= saq
.getFpdValidImageNames();
201 for (int i
= 0; i
< validFv
.length
; i
++) {
203 // Get all global variables from FPD and set them to properties
205 String
[][] globalVariables
= saq
.getFpdGlobalVariable();
206 for (int j
= 0; j
< globalVariables
.length
; j
++) {
207 getProject().setProperty(globalVariables
[j
][0], globalVariables
[j
][1]);
210 getProject().setProperty("FV_FILENAME", validFv
[i
]);
212 File fvFile
= new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File
.separatorChar
+ validFv
[i
] + ".inf"));
213 fvFile
.getParentFile().mkdirs();
216 FileWriter fw
= new FileWriter(fvFile
);
217 BufferedWriter bw
= new BufferedWriter(fw
);
222 String
[][] options
= saq
.getFpdOptions(validFv
[i
]);
223 if (options
.length
> 0) {
224 bw
.write("[options]");
226 for (int j
= 0; j
< options
.length
; j
++) {
227 StringBuffer str
= new StringBuffer(100);
228 str
.append(options
[j
][0]);
229 while (str
.length() < 40) {
233 str
.append(options
[j
][1]);
234 bw
.write(getProject().replaceProperties(str
.toString()));
243 String
[][] attributes
= saq
.getFpdAttributes(validFv
[i
]);
244 if (attributes
.length
> 0) {
245 bw
.write("[attributes]");
247 for (int j
= 0; j
< attributes
.length
; j
++) {
248 StringBuffer str
= new StringBuffer(100);
249 str
.append(attributes
[j
][0]);
250 while (str
.length() < 40) {
254 str
.append(attributes
[j
][1]);
255 bw
.write(getProject().replaceProperties(str
.toString()));
264 String
[][] components
= saq
.getFpdComponents(validFv
[i
]);
265 if (components
.length
> 0) {
266 bw
.write("[components]");
268 for (int j
= 0; j
< components
.length
; j
++) {
269 StringBuffer str
= new StringBuffer(100);
270 str
.append(components
[j
][0]);
271 while (str
.length() < 40) {
275 str
.append(components
[j
][1]);
276 bw
.write(getProject().replaceProperties(str
.toString()));
285 Set
<FpdModuleIdentification
> filesSet
= fvs
.get(validFv
[i
]);
286 if (filesSet
!= null) {
287 FpdModuleIdentification
[] files
= filesSet
.toArray(new FpdModuleIdentification
[filesSet
.size()]);
290 for (int j
= 0; j
< files
.length
; j
++) {
291 String str
= ffsCommonDir
+ File
.separatorChar
+ outfiles
.get(files
[j
]);
292 bw
.write(getProject().replaceProperties("EFI_FILE_NAME = " + str
));
299 } catch (Exception e
) {
300 throw new BuildException("Generation of the FV file [" + fvFile
.getPath() + "] failed!\n" + e
.getMessage());
305 This method is used for Single Module Build.
308 @throws BuildException
309 FPD file is not valid.
311 public void parseFpdFile(File fpdFile
) throws BuildException
{
312 this.fpdFile
= fpdFile
;
319 @throws BuildException
320 FPD file is not valid.
322 void parseFpdFile() 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 saq
= new SurfaceAreaQuery(map
);
337 platformId
= saq
.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("(\\\\)", "/"));
344 if( !FrameworkBuildTask
.multithread
) {
345 FrameworkBuildTask
.originalProperties
.put("PLATFORM", platformId
.getName());
346 FrameworkBuildTask
.originalProperties
.put("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
347 FrameworkBuildTask
.originalProperties
.put("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
348 FrameworkBuildTask
.originalProperties
.put("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
352 // Build mode. User-defined output dir.
354 String buildMode
= saq
.getFpdIntermediateDirectories();
355 String userDefinedOutputDir
= saq
.getFpdOutputDirectory();
357 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
360 // TBD. Deal PCD and BuildOption related Info
362 GlobalData
.setFpdBuildOptions(saq
.getFpdBuildOptions());
364 GlobalData
.setToolChainPlatformInfo(saq
.getFpdToolChainInfo());
367 // Parse all list modules SA
369 parseModuleSAFiles();
372 // TBD. Deal PCD and BuildOption related Info
374 parseToolChainFamilyOptions();
375 parseToolChainOptions();
380 // Pcd Collection. Call CollectPCDAction to collect pcd info.
382 PlatformPcdPreprocessActionForBuilding ca
= new PlatformPcdPreprocessActionForBuilding();
383 ca
.perform(platformId
.getFpdFile().getPath(), ActionMessage
.NULL_MESSAGE_LEVEL
);
384 } catch (Exception e
) {
385 throw new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + e
.getMessage());
390 Parse all modules listed in FPD file.
392 void parseModuleSAFiles() throws EdkException
{
393 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= saq
.getFpdModules();
396 // For every Module lists in FPD file.
398 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
399 Iterator iter
= keys
.iterator();
400 while (iter
.hasNext()) {
401 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
404 // Judge if Module is existed?
406 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
409 // Put fpdModuleId to the corresponding FV
411 saq
.push(GlobalData
.getDoc(fpdModuleId
));
412 String fvBinding
= saq
.getModuleFvBindingKeyword();
414 fpdModuleId
.setFvBinding(fvBinding
);
415 updateFvs(fvBinding
, fpdModuleId
);
418 // Prepare for out put file name
420 ModuleIdentification moduleId
= fpdModuleId
.getModule();
422 String baseName
= saq
.getModuleOutputFileBasename();
424 if (baseName
== null) {
425 baseName
= moduleId
.getName();
427 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
428 + moduleId
.getGuid() + "-" + baseName
429 + getSuffix(moduleId
.getModuleType()));
432 // parse module build options, if any
434 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
435 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
440 ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
441 String
[][] options
= saq
.getModuleBuildOptions(toolChainFamilyFlag
);
442 if (options
== null || options
.length
== 0) {
443 return new ToolChainMap();
445 return parseOptions(options
);
448 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
449 String
[][] options
= saq
.getPlatformBuildOptions(toolChainFamilyFlag
);
450 if (options
== null || options
.length
== 0) {
451 return new ToolChainMap();
453 return parseOptions(options
);
456 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
457 ToolChainMap map
= new ToolChainMap();
458 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
460 for (int i
= 0; i
< options
.length
; ++i
) {
461 String flagString
= options
[i
][flagIndex
];
462 if (flagString
== null) {
465 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
466 map
.put(options
[i
], flagString
.trim());
472 private void parseToolChainFamilyOptions() throws EdkException
{
473 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
476 private void parseToolChainOptions() throws EdkException
{
477 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
481 Add the current module to corresponding FV.
483 @param fvName current FV name
484 @param moduleName current module identification
486 void updateFvs(String fvName
, FpdModuleIdentification fpdModuleId
) {
487 if (fvName
== null || fvName
.trim().length() == 0) {
490 String
[] fvNameArray
= fvName
.split("[, \t]+");
491 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
493 // Put module to corresponding fvName
495 if (fvs
.containsKey(fvNameArray
[i
])) {
496 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
497 set
.add(fpdModuleId
);
499 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
500 set
.add(fpdModuleId
);
501 fvs
.put(fvNameArray
[i
], set
);
507 Get the suffix based on module type. Current relationship are listed:
510 <b>ModuleType</b> <b>Suffix</b>
517 DXE_RUNTIME_DRIVER .DXE
522 UEFI_APPLICATION .APP
526 @param moduleType module type
528 @throws BuildException
529 If module type is null
531 public static String
getSuffix(String moduleType
) throws BuildException
{
532 if (moduleType
== null) {
533 throw new BuildException("Module type is not specified.");
536 String
[][] suffix
= EdkDefinitions
.ModuleTypeExtensions
;
538 for (int i
= 0; i
< suffix
.length
; i
++) {
539 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
553 public void addProperty(Property p
) {
554 properties
.addElement(p
);
557 public void setPlatformName(String platformName
) {
558 this.platformName
= platformName
;
561 public void setFpdFile(File fpdFile
) {
562 this.fpdFile
= fpdFile
;
565 public void setType(String type
) {
569 public String
getAllArchForModule(ModuleIdentification moduleId
) {
571 Iterator
<FpdModuleIdentification
> iter
= outfiles
.keySet().iterator();
572 while (iter
.hasNext()) {
573 FpdModuleIdentification fpdModuleId
= iter
.next();
575 if (fpdModuleId
.getModule().equals(moduleId
)) {
576 archs
+= fpdModuleId
.getArch() + " ";