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
;
28 import java
.util
.TreeMap
;
30 import org
.apache
.tools
.ant
.BuildException
;
31 import org
.apache
.tools
.ant
.Task
;
32 import org
.apache
.tools
.ant
.taskdefs
.Ant
;
33 import org
.apache
.tools
.ant
.taskdefs
.Property
;
34 import org
.apache
.xmlbeans
.XmlObject
;
36 import org
.tianocore
.build
.global
.GlobalData
;
37 import org
.tianocore
.build
.global
.OutputManager
;
38 import org
.tianocore
.build
.global
.SurfaceAreaQuery
;
39 import org
.tianocore
.build
.id
.FpdModuleIdentification
;
40 import org
.tianocore
.build
.id
.ModuleIdentification
;
41 import org
.tianocore
.build
.id
.PlatformIdentification
;
42 import org
.tianocore
.build
.pcd
.action
.ActionMessage
;
43 import org
.tianocore
.build
.pcd
.action
.CollectPCDAction
;
44 import org
.tianocore
.build
.toolchain
.ToolChainAttribute
;
45 import org
.tianocore
.build
.toolchain
.ToolChainElement
;
46 import org
.tianocore
.build
.toolchain
.ToolChainMap
;
47 import org
.tianocore
.exception
.EdkException
;
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)
59 and flash definition file (File is for Tool FlashMap) if necessary. </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" />
73 <p>The task will initialize all information through parsing Framework Database,
74 SPD, Tool chain configuration files. </p>
78 public class FpdParserTask
extends Task
{
80 private String platformName
;
82 private File fpdFile
= null;
84 private PlatformIdentification platformId
;
92 /// Mapping from modules identification to out put file name
94 private Map
<FpdModuleIdentification
, String
> outfiles
= new LinkedHashMap
<FpdModuleIdentification
, String
>();
97 /// Mapping from FV name to its modules
99 private Map
<String
, Set
<FpdModuleIdentification
>> fvs
= new HashMap
<String
, Set
<FpdModuleIdentification
>>();
102 /// Mapping from sequence number to FV names
104 private Map
<String
, Set
<String
>> sequences
= new TreeMap
<String
, Set
<String
>>();
107 /// FpdParserTask can specify some ANT properties.
109 private Vector
<Property
> properties
= new Vector
<Property
>();
111 private boolean isUnified
= true;
115 Public construct method. It is necessary for ANT task.
117 public FpdParserTask() {
121 ANT task's entry method. The main steps is described as following:
124 <li>Initialize global information (Framework DB, SPD files and all MSA files
125 listed in SPD). This step will execute only once in whole build process;</li>
126 <li>Parse specified FPD file; </li>
127 <li>Generate FV.inf files; </li>
128 <li>Generate PlatformName_build.xml file for Flatform build; </li>
129 <li>Collect PCD information. </li>
132 @throws BuildException
133 Surface area is not valid.
135 public void execute() throws BuildException
{
137 if ( fpdFile
== null) {
138 if (platformName
== null) {
139 throw new BuildException("FpdParserTask parameter error. Please specify platform name or FPD file. ");
141 platformId
= GlobalData
.getPlatformByName(platformName
);
142 fpdFile
= platformId
.getFpdFile();
153 isUnified
= OutputManager
.getInstance().prepareBuildDir(getProject());
156 // Generate FDF (Flash Definition File) file
160 // For every Target and ToolChain
162 String
[] targetList
= GlobalData
.getToolChainInfo().getTargets();
163 for (int i
= 0; i
< targetList
.length
; i
++){
164 String
[] toolchainList
= GlobalData
.getToolChainInfo().getTagnames();
165 for(int j
= 0; j
< toolchainList
.length
; j
++){
169 String ffsCommonDir
= getProject().getProperty("BUILD_DIR") + File
.separatorChar
170 + targetList
[i
] + File
.separatorChar
172 File fvDir
= new File(ffsCommonDir
+ File
.separatorChar
+ "FV");
174 getProject().setProperty("FV_DIR", fvDir
.getPath().replaceAll("(\\\\)", "/"));
179 genFvInfFiles(ffsCommonDir
);
186 PlatformBuildFileGenerator fileGenerator
= new PlatformBuildFileGenerator(getProject(), outfiles
, fvs
, sequences
, isUnified
);
187 fileGenerator
.genBuildFile();
190 // Ant call ${PLATFORM}_build.xml
194 ant
.setProject(getProject());
195 ant
.setAntfile(platformId
.getFpdFile().getParent() + File
.separatorChar
+ platformId
.getName() + "_build.xml");
197 ant
.setInheritAll(true);
201 // GlobalData.log.info("Fpd build end. ");
205 Generate Fv.inf files. The Fv.inf file is composed with four
206 parts: Options, Attributes, Components and Files. The Fv.inf files
207 will be under FV_DIR.
209 @throws BuildException
210 File write FV.inf files error.
212 private void genFvInfFiles(String ffsCommonDir
) throws BuildException
{
213 String
[] validFv
= SurfaceAreaQuery
.getFpdValidImageNames();
214 for (int i
= 0; i
< validFv
.length
; i
++) {
216 // Get all global variables from FPD and set them to properties
218 String
[][] globalVariables
= SurfaceAreaQuery
.getFpdGlobalVariable();
219 for (int j
= 0; j
< globalVariables
.length
; j
++) {
220 getProject().setProperty(globalVariables
[j
][0], globalVariables
[j
][1]);
223 getProject().setProperty("FV_FILENAME", validFv
[i
].toUpperCase());
225 File fvFile
= new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File
.separatorChar
+ validFv
[i
].toUpperCase() + ".inf"));
226 fvFile
.getParentFile().mkdirs();
229 FileWriter fw
= new FileWriter(fvFile
);
230 BufferedWriter bw
= new BufferedWriter(fw
);
235 String
[][] options
= SurfaceAreaQuery
.getFpdOptions(validFv
[i
]);
236 if (options
.length
> 0) {
237 bw
.write("[options]");
239 for (int j
= 0; j
< options
.length
; j
++) {
240 StringBuffer str
= new StringBuffer(100);
241 str
.append(options
[j
][0]);
242 while (str
.length() < 40) {
246 str
.append(options
[j
][1]);
247 bw
.write(getProject().replaceProperties(str
.toString()));
256 String
[][] attributes
= SurfaceAreaQuery
.getFpdAttributes(validFv
[i
]);
257 if (attributes
.length
> 0) {
258 bw
.write("[attributes]");
260 for (int j
= 0; j
< attributes
.length
; j
++) {
261 StringBuffer str
= new StringBuffer(100);
262 str
.append(attributes
[j
][0]);
263 while (str
.length() < 40) {
267 str
.append(attributes
[j
][1]);
268 bw
.write(getProject().replaceProperties(str
.toString()));
277 String
[][] components
= SurfaceAreaQuery
.getFpdComponents(validFv
[i
]);
278 if (components
.length
> 0) {
279 bw
.write("[components]");
281 for (int j
= 0; j
< components
.length
; j
++) {
282 StringBuffer str
= new StringBuffer(100);
283 str
.append(components
[j
][0]);
284 while (str
.length() < 40) {
288 str
.append(components
[j
][1]);
289 bw
.write(getProject().replaceProperties(str
.toString()));
298 Set
<FpdModuleIdentification
> filesSet
= fvs
.get(validFv
[i
].toUpperCase());
299 if (filesSet
!= null) {
300 FpdModuleIdentification
[] files
= filesSet
.toArray(new FpdModuleIdentification
[filesSet
.size()]);
303 for (int j
= 0; j
< files
.length
; j
++) {
304 String str
= ffsCommonDir
+ File
.separatorChar
+ outfiles
.get(files
[j
]);
305 bw
.write(getProject().replaceProperties("EFI_FILE_NAME = " + str
));
312 } catch (Exception e
) {
313 throw new BuildException("Generate FV file [" + fvFile
.getPath() + "] failed. \n" + e
.getMessage());
318 This method is used for Single Module Build.
321 @throws BuildException
322 FPD file is not valid.
324 public void parseFpdFile(File fpdFile
) throws BuildException
{
325 this.fpdFile
= fpdFile
;
332 @throws BuildException
333 FPD file is not valid.
335 private void parseFpdFile() throws BuildException
{
337 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
339 if (!doc
.validate()) {
340 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] is invalid.");
343 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
344 map
.put("PlatformSurfaceArea", doc
);
345 SurfaceAreaQuery
.setDoc(map
);
350 platformId
= SurfaceAreaQuery
.getFpdHeader();
351 platformId
.setFpdFile(fpdFile
);
352 getProject().setProperty("PLATFORM", platformId
.getName());
353 getProject().setProperty("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
354 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
355 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
358 // Build mode. User-defined output dir.
360 String buildMode
= SurfaceAreaQuery
.getFpdIntermediateDirectories();
361 String userDefinedOutputDir
= SurfaceAreaQuery
.getFpdOutputDirectory();
363 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
366 // TBD. Deal PCD and BuildOption related Info
368 GlobalData
.setFpdBuildOptions(SurfaceAreaQuery
.getFpdBuildOptions());
370 GlobalData
.setToolChainPlatformInfo(SurfaceAreaQuery
.getFpdToolChainInfo());
373 // Parse all list modules SA
375 parseModuleSAFiles();
378 // TBD. Deal PCD and BuildOption related Info
380 parseToolChainFamilyOptions();
381 parseToolChainOptions();
383 SurfaceAreaQuery
.setDoc(map
);
386 // Pcd Collection. Call CollectPCDAction to collect pcd info.
389 CollectPCDAction ca
= new CollectPCDAction();
390 ca
.perform(GlobalData
.getWorkspacePath(),platformId
.getFpdFile().getPath(),ActionMessage
.NULL_MESSAGE_LEVEL
);
391 } catch (Exception e
){
392 throw new BuildException(e
.getMessage());
394 } catch (Exception e
) {
395 throw new BuildException("Load FPD file [" + fpdFile
.getPath() + "] error. \n" + e
.getMessage());
402 Parse all modules listed in FPD file.
404 private void parseModuleSAFiles() throws EdkException
{
405 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= SurfaceAreaQuery
.getFpdModules();
408 // For every Module lists in FPD file.
410 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
411 Iterator iter
= keys
.iterator();
412 while (iter
.hasNext()) {
413 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
416 // Judge if Module is existed?
419 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
422 // Put fpdModuleId to the corresponding FV
424 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
425 String fvBinding
= SurfaceAreaQuery
.getModuleFvBindingKeyword();
426 SurfaceAreaQuery
.pop();
428 fpdModuleId
.setFvBinding(fvBinding
);
429 String fvSequence
= fpdModuleId
.getSequence();
430 updateFvs(fvSequence
, fvBinding
, fpdModuleId
);
433 // Prepare for out put file name
435 ModuleIdentification moduleId
= fpdModuleId
.getModule();
436 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
437 String baseName
= SurfaceAreaQuery
.getModuleOutputFileBasename();
438 SurfaceAreaQuery
.pop();
439 if (baseName
== null) {
440 baseName
= moduleId
.getName();
442 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
443 + moduleId
.getGuid() + "-" + baseName
444 + getSuffix(moduleId
.getModuleType()));
447 // parse module build options, if any
449 SurfaceAreaQuery
.push(GlobalData
.getDoc(fpdModuleId
));
450 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
451 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
452 SurfaceAreaQuery
.pop();
456 private ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
457 String
[][] options
= SurfaceAreaQuery
.getModuleBuildOptions(toolChainFamilyFlag
);
458 if (options
== null || options
.length
== 0) {
461 return parseOptions(options
);
464 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
465 String
[][] options
= SurfaceAreaQuery
.getPlatformBuildOptions(toolChainFamilyFlag
);
466 if (options
== null || options
.length
== 0) {
469 return parseOptions(options
);
472 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
473 ToolChainMap map
= new ToolChainMap();
474 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
476 for (int i
= 0; i
< options
.length
; ++i
) {
477 String flagString
= options
[i
][flagIndex
];
478 if (flagString
== null) {
481 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
482 map
.put(options
[i
], flagString
.trim());
488 private void parseToolChainFamilyOptions() throws EdkException
{
489 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
492 private void parseToolChainOptions() throws EdkException
{
493 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
497 Add the current module to corresponding FV.
499 @param fvName current FV name
500 @param moduleName current module identification
502 private void updateFvs(String fvSequence
, String fvName
, FpdModuleIdentification fpdModuleId
) {
503 if (fvName
== null || fvName
.trim().length() == 0) {
506 String upcaseFvName
= fvName
.toUpperCase();
507 String
[] fvNameArray
= upcaseFvName
.split("[, \t]+");
508 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
510 // Put module to corresponding fvName
512 if (fvs
.containsKey(fvNameArray
[i
])) {
513 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
514 set
.add(fpdModuleId
);
517 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
518 set
.add(fpdModuleId
);
519 fvs
.put(fvNameArray
[i
], set
);
523 // Put fvName to corresponding fvSequence
525 if (sequences
.containsKey(fvSequence
)) {
526 Set
<String
> set
= sequences
.get(fvSequence
);
527 set
.add(fvNameArray
[i
]);
530 Set
<String
> set
= new LinkedHashSet
<String
>();
531 set
.add(fvNameArray
[i
]);
532 sequences
.put(fvSequence
, set
);
538 Get the suffix based on module type. Current relationship are listed:
541 <b>ModuleType</b> <b>Suffix</b>
548 DXE_RUNTIME_DRIVER .DXE
553 UEFI_APPLICATION .APP
557 @param moduleType module type
559 @throws BuildException
560 If module type is null
562 public static String
getSuffix(String moduleType
) throws BuildException
{
563 if (moduleType
== null) {
564 throw new BuildException("Module type is not specified.");
567 String
[][] suffix
= { { "BASE", ".FFS"},
568 { "SEC", ".SEC" }, { "PEI_CORE", ".PEI" },
569 { "PEIM", ".PEI" }, { "DXE_CORE", ".DXE" },
570 { "DXE_DRIVER", ".DXE" }, { "DXE_RUNTIME_DRIVER", ".DXE" },
571 { "DXE_SAL_DRIVER", ".DXE" }, { "DXE_SMM_DRIVER", ".DXE" },
572 { "TOOL", ".FFS" }, { "UEFI_DRIVER", ".DXE" },
573 { "UEFI_APPLICATION", ".APP" }, { "USER_DEFINED", ".FFS" } };
575 for (int i
= 0; i
< suffix
.length
; i
++) {
576 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
590 public void addProperty(Property p
) {
591 properties
.addElement(p
);
594 public void setPlatformName(String platformName
) {
595 this.platformName
= platformName
;
598 public void setFpdFile(File fpdFile
) {
599 this.fpdFile
= fpdFile
;
602 public void setType(String type
) {