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 fvFile
.getParentFile().mkdirs();
199 FileWriter fw
= new FileWriter(fvFile
);
200 BufferedWriter bw
= new BufferedWriter(fw
);
205 String
[][] options
= saq
.getFpdOptions(validFv
[i
]);
206 if (options
.length
> 0) {
207 bw
.write("[options]");
209 for (int j
= 0; j
< options
.length
; j
++) {
210 StringBuffer str
= new StringBuffer(100);
211 str
.append(options
[j
][0]);
212 while (str
.length() < 40) {
216 str
.append(options
[j
][1]);
217 bw
.write(getProject().replaceProperties(str
.toString()));
226 String
[][] attributes
= saq
.getFpdAttributes(validFv
[i
]);
227 if (attributes
.length
> 0) {
228 bw
.write("[attributes]");
230 for (int j
= 0; j
< attributes
.length
; j
++) {
231 StringBuffer str
= new StringBuffer(100);
232 str
.append(attributes
[j
][0]);
233 while (str
.length() < 40) {
237 str
.append(attributes
[j
][1]);
238 bw
.write(getProject().replaceProperties(str
.toString()));
247 String
[][] components
= saq
.getFpdComponents(validFv
[i
]);
248 if (components
.length
> 0) {
249 bw
.write("[components]");
251 for (int j
= 0; j
< components
.length
; j
++) {
252 StringBuffer str
= new StringBuffer(100);
253 str
.append(components
[j
][0]);
254 while (str
.length() < 40) {
258 str
.append(components
[j
][1]);
259 bw
.write(getProject().replaceProperties(str
.toString()));
268 Set
<FpdModuleIdentification
> filesSet
= fvs
.get(validFv
[i
]);
269 if (filesSet
!= null) {
270 FpdModuleIdentification
[] files
= filesSet
.toArray(new FpdModuleIdentification
[filesSet
.size()]);
273 for (int j
= 0; j
< files
.length
; j
++) {
274 String str
= ffsCommonDir
+ File
.separatorChar
+ outfiles
.get(files
[j
]);
275 bw
.write(getProject().replaceProperties("EFI_FILE_NAME = " + str
));
282 } catch (IOException ex
) {
283 BuildException buildException
= new BuildException("Generation of the FV file [" + fvFile
.getPath() + "] failed!\n" + ex
.getMessage());
284 buildException
.setStackTrace(ex
.getStackTrace());
285 throw buildException
;
290 This method is used for Single Module Build.
293 @throws BuildException
294 FPD file is not valid.
296 public void parseFpdFile(File fpdFile
) throws BuildException
, EdkException
{
297 this.fpdFile
= fpdFile
;
301 // Call Platform_build.xml prebuild firstly in stand-alone build
304 isUnified
= OutputManager
.getInstance().prepareBuildDir(getProject());
306 String buildDir
= getProject().getProperty("BUILD_DIR");
308 // For every Target and ToolChain
310 String
[] targetList
= GlobalData
.getToolChainInfo().getTargets();
311 for (int i
= 0; i
< targetList
.length
; i
++) {
312 String
[] toolchainList
= GlobalData
.getToolChainInfo().getTagnames();
313 for(int j
= 0; j
< toolchainList
.length
; j
++) {
317 String ffsCommonDir
= buildDir
+ File
.separatorChar
318 + targetList
[i
] + "_"
320 File fvDir
= new File(ffsCommonDir
+ File
.separatorChar
+ "FV");
325 String platformBuildFile
= buildDir
+ File
.separatorChar
+ platformId
.getName() + "_build.xml";
326 PlatformBuildFileGenerator fileGenerator
= new PlatformBuildFileGenerator(getProject(), outfiles
, fvs
, isUnified
, saq
, platformBuildFile
);
327 fileGenerator
.genBuildFile();
330 ant
.setProject(getProject());
331 ant
.setAntfile(platformBuildFile
);
332 ant
.setTarget("prebuild");
333 ant
.setInheritAll(true);
341 @throws BuildException
342 FPD file is not valid.
344 void parseFpdFile() throws BuildException
{
346 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
348 if (!doc
.validate()) {
349 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] format is invalid!");
352 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
353 map
.put("PlatformSurfaceArea", doc
);
354 saq
= new SurfaceAreaQuery(map
);
359 platformId
= saq
.getFpdHeader();
360 platformId
.setFpdFile(fpdFile
);
361 getProject().setProperty("PLATFORM", platformId
.getName());
362 getProject().setProperty("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
363 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
364 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
366 if( !FrameworkBuildTask
.multithread
) {
367 FrameworkBuildTask
.originalProperties
.put("PLATFORM", platformId
.getName());
368 FrameworkBuildTask
.originalProperties
.put("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
369 FrameworkBuildTask
.originalProperties
.put("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
370 FrameworkBuildTask
.originalProperties
.put("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
374 // Build mode. User-defined output dir.
376 String buildMode
= saq
.getFpdIntermediateDirectories();
377 String userDefinedOutputDir
= saq
.getFpdOutputDirectory();
379 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
382 // TBD. Deal PCD and BuildOption related Info
384 GlobalData
.setFpdBuildOptions(saq
.getFpdBuildOptions());
386 GlobalData
.setToolChainPlatformInfo(saq
.getFpdToolChainInfo());
389 // Parse all list modules SA
391 parseModuleSAFiles();
394 // TBD. Deal PCD and BuildOption related Info
396 parseToolChainFamilyOptions();
397 parseToolChainOptions();
402 // Pcd Collection. Call CollectPCDAction to collect pcd info.
404 PlatformPcdPreprocessActionForBuilding ca
= new PlatformPcdPreprocessActionForBuilding();
405 ca
.perform(platformId
.getFpdFile().getPath(), ActionMessage
.NULL_MESSAGE_LEVEL
);
406 } catch (IOException ex
) {
407 BuildException buildException
= new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + ex
.getMessage());
408 buildException
.setStackTrace(ex
.getStackTrace());
409 throw buildException
;
410 } catch (XmlException ex
) {
411 BuildException buildException
= new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + ex
.getMessage());
412 buildException
.setStackTrace(ex
.getStackTrace());
413 throw buildException
;
414 } catch (EdkException ex
) {
415 BuildException buildException
= new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + ex
.getMessage());
416 buildException
.setStackTrace(ex
.getStackTrace());
417 throw buildException
;
422 Parse all modules listed in FPD file.
424 void parseModuleSAFiles() throws EdkException
{
425 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= saq
.getFpdModules();
428 // For every Module lists in FPD file.
430 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
431 Iterator iter
= keys
.iterator();
432 while (iter
.hasNext()) {
433 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
436 // Judge if Module is existed?
438 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
441 // Put fpdModuleId to the corresponding FV
443 saq
.push(GlobalData
.getDoc(fpdModuleId
));
444 String fvBinding
= saq
.getModuleFvBindingKeyword();
446 fpdModuleId
.setFvBinding(fvBinding
);
447 updateFvs(fvBinding
, fpdModuleId
);
450 // Prepare for out put file name
452 ModuleIdentification moduleId
= fpdModuleId
.getModule();
454 String baseName
= saq
.getModuleOutputFileBasename();
456 if (baseName
== null) {
457 baseName
= moduleId
.getName();
459 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
460 + moduleId
.getGuid() + "-" + baseName
461 + getSuffix(moduleId
.getModuleType()));
464 // parse module build options, if any
466 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
467 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
472 ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
473 String
[][] options
= saq
.getModuleBuildOptions(toolChainFamilyFlag
);
474 if (options
== null || options
.length
== 0) {
475 return new ToolChainMap();
477 return parseOptions(options
);
480 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
481 String
[][] options
= saq
.getPlatformBuildOptions(toolChainFamilyFlag
);
482 if (options
== null || options
.length
== 0) {
483 return new ToolChainMap();
485 return parseOptions(options
);
488 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
489 ToolChainMap map
= new ToolChainMap();
490 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
492 for (int i
= 0; i
< options
.length
; ++i
) {
493 String flagString
= options
[i
][flagIndex
];
494 if (flagString
== null) {
497 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
498 map
.put(options
[i
], flagString
.trim());
504 private void parseToolChainFamilyOptions() throws EdkException
{
505 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
508 private void parseToolChainOptions() throws EdkException
{
509 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
513 Add the current module to corresponding FV.
515 @param fvName current FV name
516 @param moduleName current module identification
518 void updateFvs(String fvName
, FpdModuleIdentification fpdModuleId
) {
519 if (fvName
== null || fvName
.trim().length() == 0) {
522 String
[] fvNameArray
= fvName
.split("[, \t]+");
523 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
525 // Put module to corresponding fvName
527 if (fvs
.containsKey(fvNameArray
[i
])) {
528 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
529 set
.add(fpdModuleId
);
531 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
532 set
.add(fpdModuleId
);
533 fvs
.put(fvNameArray
[i
], set
);
539 Get the suffix based on module type. Current relationship are listed:
542 <b>ModuleType</b> <b>Suffix</b>
549 DXE_RUNTIME_DRIVER .DXE
554 UEFI_APPLICATION .APP
558 @param moduleType module type
560 @throws BuildException
561 If module type is null
563 public static String
getSuffix(String moduleType
) throws BuildException
{
564 if (moduleType
== null) {
565 throw new BuildException("Module type is not specified.");
568 String
[][] suffix
= EdkDefinitions
.ModuleTypeExtensions
;
570 for (int i
= 0; i
< suffix
.length
; i
++) {
571 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
585 public void addProperty(Property p
) {
586 properties
.addElement(p
);
589 public void setFpdFile(File fpdFile
) {
590 this.fpdFile
= fpdFile
;
593 public void setType(String type
) {
597 public String
getAllArchForModule(ModuleIdentification moduleId
) {
599 Iterator
<FpdModuleIdentification
> iter
= outfiles
.keySet().iterator();
600 while (iter
.hasNext()) {
601 FpdModuleIdentification fpdModuleId
= iter
.next();
603 if (fpdModuleId
.getModule().equals(moduleId
)) {
604 archs
+= fpdModuleId
.getArch() + " ";