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
.io
.IOException
;
22 import java
.util
.HashMap
;
23 import java
.util
.Iterator
;
24 import java
.util
.LinkedHashMap
;
25 import java
.util
.LinkedHashSet
;
28 import java
.util
.Vector
;
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
.XmlException
;
35 import org
.apache
.xmlbeans
.XmlObject
;
37 import org
.tianocore
.common
.definitions
.EdkDefinitions
;
38 import org
.tianocore
.common
.exception
.EdkException
;
39 import org
.tianocore
.pcd
.action
.ActionMessage
;
40 import org
.tianocore
.build
.FrameworkBuildTask
;
41 import org
.tianocore
.build
.global
.GlobalData
;
42 import org
.tianocore
.build
.global
.OutputManager
;
43 import org
.tianocore
.build
.global
.SurfaceAreaQuery
;
44 import org
.tianocore
.build
.id
.FpdModuleIdentification
;
45 import org
.tianocore
.build
.id
.ModuleIdentification
;
46 import org
.tianocore
.build
.id
.PlatformIdentification
;
47 import org
.tianocore
.build
.pcd
.action
.PlatformPcdPreprocessActionForBuilding
;
48 import org
.tianocore
.build
.toolchain
.ToolChainAttribute
;
49 import org
.tianocore
.build
.toolchain
.ToolChainElement
;
50 import org
.tianocore
.build
.toolchain
.ToolChainMap
;
53 <code>FpdParserTask</code> is an ANT task. The main function is parsing Framework
54 Platform Descritpion (FPD) XML file and generating its ANT build script for
55 corresponding platform.
57 <p>The task sets global properties PLATFORM, PLATFORM_DIR, PLATFORM_RELATIVE_DIR
60 <p>The task generates ${PLATFORM}_build.xml file which will be called by top level
61 build.xml. The task also generate Fv.inf files (File is for Tool GenFvImage). </p>
63 <p>FpdParserTask task stores all FPD information to GlobalData. And parse
64 tools definition file to set up compiler options for different Target and
65 different ToolChainTag. </p>
67 <p>The method parseFpdFile is also prepared for single module build. </p>
71 public class FpdParserTask
extends Task
{
73 private File fpdFile
= null;
75 PlatformIdentification platformId
;
80 /// Mapping from modules identification to out put file name
82 Map
<FpdModuleIdentification
, String
> outfiles
= new LinkedHashMap
<FpdModuleIdentification
, String
>();
85 /// Mapping from FV name to its modules
87 Map
<String
, Set
<FpdModuleIdentification
>> fvs
= new HashMap
<String
, Set
<FpdModuleIdentification
>>();
90 /// FpdParserTask can specify some ANT properties.
92 private Vector
<Property
> properties
= new Vector
<Property
>();
94 SurfaceAreaQuery saq
= null;
96 boolean isUnified
= true;
99 Public construct method. It is necessary for ANT task.
101 public FpdParserTask() {
105 ANT task's entry method. The main steps is described as following:
108 <li>Initialize global information (Framework DB, SPD files and all MSA files
109 listed in SPD). This step will execute only once in whole build process;</li>
110 <li>Parse specified FPD file; </li>
111 <li>Generate FV.inf files; </li>
112 <li>Generate PlatformName_build.xml file for Flatform build; </li>
113 <li>Collect PCD information. </li>
116 @throws BuildException
117 Surface area is not valid.
119 public void execute() throws BuildException
{
128 isUnified
= OutputManager
.getInstance().prepareBuildDir(getProject());
130 String buildDir
= getProject().getProperty("BUILD_DIR");
132 // For every Target and ToolChain
134 String
[] targetList
= GlobalData
.getToolChainInfo().getTargets();
135 for (int i
= 0; i
< targetList
.length
; i
++) {
136 String
[] toolchainList
= GlobalData
.getToolChainInfo().getTagnames();
137 for(int j
= 0; j
< toolchainList
.length
; j
++) {
141 String ffsCommonDir
= buildDir
+ File
.separatorChar
142 + targetList
[i
] + "_"
144 File fvDir
= new File(ffsCommonDir
+ File
.separatorChar
+ "FV");
146 getProject().setProperty("FV_DIR", fvDir
.getPath().replaceAll("(\\\\)", "/"));
151 genFvInfFiles(ffsCommonDir
);
158 String platformBuildFile
= buildDir
+ File
.separatorChar
+ platformId
.getName() + "_build.xml";
159 PlatformBuildFileGenerator fileGenerator
= new PlatformBuildFileGenerator(getProject(), outfiles
, fvs
, isUnified
, saq
, platformBuildFile
);
160 fileGenerator
.genBuildFile();
163 // Ant call ${PLATFORM}_build.xml
166 ant
.setProject(getProject());
167 ant
.setAntfile(platformBuildFile
);
169 ant
.setInheritAll(true);
175 Generate Fv.inf files. The Fv.inf file is composed with four
176 parts: Options, Attributes, Components and Files. The Fv.inf files
177 will be under FV_DIR.
179 @throws BuildException
180 File write FV.inf files error.
182 void genFvInfFiles(String ffsCommonDir
) throws BuildException
{
183 String
[] validFv
= saq
.getFpdValidImageNames();
184 for (int i
= 0; i
< validFv
.length
; i
++) {
186 // Get all global variables from FPD and set them to properties
188 String
[][] globalVariables
= saq
.getFpdGlobalVariable();
189 for (int j
= 0; j
< globalVariables
.length
; j
++) {
190 getProject().setProperty(globalVariables
[j
][0], globalVariables
[j
][1]);
193 getProject().setProperty("FV_FILENAME", validFv
[i
]);
195 File fvFile
= new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File
.separatorChar
+ validFv
[i
] + ".inf"));
196 if (fvFile
.exists() && (fvFile
.lastModified() >= fpdFile
.lastModified())) {
198 // don't re-generate FV.inf if fpd has not been changed
202 fvFile
.getParentFile().mkdirs();
205 FileWriter fw
= new FileWriter(fvFile
);
206 BufferedWriter bw
= new BufferedWriter(fw
);
211 String
[][] options
= saq
.getFpdOptions(validFv
[i
]);
212 if (options
.length
> 0) {
213 bw
.write("[options]");
215 for (int j
= 0; j
< options
.length
; j
++) {
216 StringBuffer str
= new StringBuffer(100);
217 str
.append(options
[j
][0]);
218 while (str
.length() < 40) {
222 str
.append(options
[j
][1]);
223 bw
.write(getProject().replaceProperties(str
.toString()));
232 String
[][] attributes
= saq
.getFpdAttributes(validFv
[i
]);
233 if (attributes
.length
> 0) {
234 bw
.write("[attributes]");
236 for (int j
= 0; j
< attributes
.length
; j
++) {
237 StringBuffer str
= new StringBuffer(100);
238 str
.append(attributes
[j
][0]);
239 while (str
.length() < 40) {
243 str
.append(attributes
[j
][1]);
244 bw
.write(getProject().replaceProperties(str
.toString()));
253 String
[][] components
= saq
.getFpdComponents(validFv
[i
]);
254 if (components
.length
> 0) {
255 bw
.write("[components]");
257 for (int j
= 0; j
< components
.length
; j
++) {
258 StringBuffer str
= new StringBuffer(100);
259 str
.append(components
[j
][0]);
260 while (str
.length() < 40) {
264 str
.append(components
[j
][1]);
265 bw
.write(getProject().replaceProperties(str
.toString()));
274 Set
<FpdModuleIdentification
> filesSet
= fvs
.get(validFv
[i
]);
275 if (filesSet
!= null) {
276 FpdModuleIdentification
[] files
= filesSet
.toArray(new FpdModuleIdentification
[filesSet
.size()]);
279 for (int j
= 0; j
< files
.length
; j
++) {
280 String str
= ffsCommonDir
+ File
.separatorChar
+ outfiles
.get(files
[j
]);
281 bw
.write(getProject().replaceProperties("EFI_FILE_NAME = " + str
));
288 } catch (IOException ex
) {
289 BuildException buildException
= new BuildException("Generation of the FV file [" + fvFile
.getPath() + "] failed!\n" + ex
.getMessage());
290 buildException
.setStackTrace(ex
.getStackTrace());
291 throw buildException
;
296 This method is used for Single Module Build.
299 @throws BuildException
300 FPD file is not valid.
302 public void parseFpdFile(File fpdFile
) throws BuildException
, EdkException
{
303 this.fpdFile
= fpdFile
;
307 // Call Platform_build.xml prebuild firstly in stand-alone build
310 isUnified
= OutputManager
.getInstance().prepareBuildDir(getProject());
312 String buildDir
= getProject().getProperty("BUILD_DIR");
314 // For every Target and ToolChain
316 String
[] targetList
= GlobalData
.getToolChainInfo().getTargets();
317 for (int i
= 0; i
< targetList
.length
; i
++) {
318 String
[] toolchainList
= GlobalData
.getToolChainInfo().getTagnames();
319 for(int j
= 0; j
< toolchainList
.length
; j
++) {
323 String ffsCommonDir
= buildDir
+ File
.separatorChar
324 + targetList
[i
] + "_"
326 File fvDir
= new File(ffsCommonDir
+ File
.separatorChar
+ "FV");
331 String platformBuildFile
= buildDir
+ File
.separatorChar
+ platformId
.getName() + "_build.xml";
332 PlatformBuildFileGenerator fileGenerator
= new PlatformBuildFileGenerator(getProject(), outfiles
, fvs
, isUnified
, saq
, platformBuildFile
);
333 fileGenerator
.genBuildFile();
336 ant
.setProject(getProject());
337 ant
.setAntfile(platformBuildFile
);
338 ant
.setTarget("prebuild");
339 ant
.setInheritAll(true);
347 @throws BuildException
348 FPD file is not valid.
350 void parseFpdFile() throws BuildException
{
352 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
354 if (!doc
.validate()) {
355 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] format is invalid!");
358 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
359 map
.put("PlatformSurfaceArea", doc
);
360 saq
= new SurfaceAreaQuery(map
);
365 platformId
= saq
.getFpdHeader();
366 platformId
.setFpdFile(fpdFile
);
367 getProject().setProperty("PLATFORM", platformId
.getName());
368 getProject().setProperty("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
369 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
370 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
372 if( !FrameworkBuildTask
.multithread
) {
373 FrameworkBuildTask
.originalProperties
.put("PLATFORM", platformId
.getName());
374 FrameworkBuildTask
.originalProperties
.put("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
375 FrameworkBuildTask
.originalProperties
.put("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
376 FrameworkBuildTask
.originalProperties
.put("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
380 // Build mode. User-defined output dir.
382 String buildMode
= saq
.getFpdIntermediateDirectories();
383 String userDefinedOutputDir
= saq
.getFpdOutputDirectory();
385 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
388 // TBD. Deal PCD and BuildOption related Info
390 GlobalData
.setFpdBuildOptions(saq
.getFpdBuildOptions());
392 GlobalData
.setToolChainPlatformInfo(saq
.getFpdToolChainInfo());
395 // Parse all list modules SA
397 parseModuleSAFiles();
400 // TBD. Deal PCD and BuildOption related Info
402 parseToolChainFamilyOptions();
403 parseToolChainOptions();
408 // Pcd Collection. Call CollectPCDAction to collect pcd info.
410 PlatformPcdPreprocessActionForBuilding ca
= new PlatformPcdPreprocessActionForBuilding();
411 ca
.perform(platformId
.getFpdFile().getPath(), ActionMessage
.NULL_MESSAGE_LEVEL
);
412 } catch (IOException ex
) {
413 BuildException buildException
= new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + ex
.getMessage());
414 buildException
.setStackTrace(ex
.getStackTrace());
415 throw buildException
;
416 } catch (XmlException ex
) {
417 BuildException buildException
= new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + ex
.getMessage());
418 buildException
.setStackTrace(ex
.getStackTrace());
419 throw buildException
;
420 } catch (EdkException ex
) {
421 BuildException buildException
= new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + ex
.getMessage());
422 buildException
.setStackTrace(ex
.getStackTrace());
423 throw buildException
;
428 Parse all modules listed in FPD file.
430 void parseModuleSAFiles() throws EdkException
{
431 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= saq
.getFpdModules();
434 // For every Module lists in FPD file.
436 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
437 Iterator iter
= keys
.iterator();
438 while (iter
.hasNext()) {
439 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
442 // Judge if Module is existed?
444 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
447 // Put fpdModuleId to the corresponding FV
449 saq
.push(GlobalData
.getDoc(fpdModuleId
));
450 String fvBinding
= saq
.getModuleFvBindingKeyword();
452 fpdModuleId
.setFvBinding(fvBinding
);
453 updateFvs(fvBinding
, fpdModuleId
);
456 // Prepare for out put file name
458 ModuleIdentification moduleId
= fpdModuleId
.getModule();
460 String baseName
= saq
.getModuleOutputFileBasename();
462 if (baseName
== null) {
463 baseName
= moduleId
.getName();
465 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
466 + moduleId
.getGuid() + "-" + baseName
467 + getSuffix(moduleId
.getModuleType()));
470 // parse module build options, if any
472 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
473 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
478 ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
479 String
[][] options
= saq
.getModuleBuildOptions(toolChainFamilyFlag
);
480 if (options
== null || options
.length
== 0) {
481 return new ToolChainMap();
483 return parseOptions(options
);
486 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
487 String
[][] options
= saq
.getPlatformBuildOptions(toolChainFamilyFlag
);
488 if (options
== null || options
.length
== 0) {
489 return new ToolChainMap();
491 return parseOptions(options
);
494 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
495 ToolChainMap map
= new ToolChainMap();
496 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
498 for (int i
= 0; i
< options
.length
; ++i
) {
499 String flagString
= options
[i
][flagIndex
];
500 if (flagString
== null) {
503 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
504 map
.put(options
[i
], flagString
.trim());
510 private void parseToolChainFamilyOptions() throws EdkException
{
511 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
514 private void parseToolChainOptions() throws EdkException
{
515 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
519 Add the current module to corresponding FV.
521 @param fvName current FV name
522 @param moduleName current module identification
524 void updateFvs(String fvName
, FpdModuleIdentification fpdModuleId
) {
525 if (fvName
== null || fvName
.trim().length() == 0) {
528 String
[] fvNameArray
= fvName
.split("[, \t]+");
529 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
531 // Put module to corresponding fvName
533 if (fvs
.containsKey(fvNameArray
[i
])) {
534 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
535 set
.add(fpdModuleId
);
537 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
538 set
.add(fpdModuleId
);
539 fvs
.put(fvNameArray
[i
], set
);
545 Get the suffix based on module type. Current relationship are listed:
548 <b>ModuleType</b> <b>Suffix</b>
555 DXE_RUNTIME_DRIVER .DXE
560 UEFI_APPLICATION .APP
564 @param moduleType module type
566 @throws BuildException
567 If module type is null
569 public static String
getSuffix(String moduleType
) throws BuildException
{
570 if (moduleType
== null) {
571 throw new BuildException("Module type is not specified.");
574 String
[][] suffix
= EdkDefinitions
.ModuleTypeExtensions
;
576 for (int i
= 0; i
< suffix
.length
; i
++) {
577 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
591 public void addProperty(Property p
) {
592 properties
.addElement(p
);
595 public void setFpdFile(File fpdFile
) {
596 this.fpdFile
= fpdFile
;
599 public void setType(String type
) {
603 public String
getAllArchForModule(ModuleIdentification moduleId
) {
605 Iterator
<FpdModuleIdentification
> iter
= outfiles
.keySet().iterator();
606 while (iter
.hasNext()) {
607 FpdModuleIdentification fpdModuleId
= iter
.next();
609 if (fpdModuleId
.getModule().equals(moduleId
)) {
610 archs
+= fpdModuleId
.getArch() + " ";