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
;
304 @throws BuildException
305 FPD file is not valid.
307 void parseFpdFile() throws BuildException
{
309 XmlObject doc
= XmlObject
.Factory
.parse(fpdFile
);
311 if (!doc
.validate()) {
312 throw new BuildException("Platform Surface Area file [" + fpdFile
.getPath() + "] format is invalid!");
315 Map
<String
, XmlObject
> map
= new HashMap
<String
, XmlObject
>();
316 map
.put("PlatformSurfaceArea", doc
);
317 saq
= new SurfaceAreaQuery(map
);
322 platformId
= saq
.getFpdHeader();
323 platformId
.setFpdFile(fpdFile
);
324 getProject().setProperty("PLATFORM", platformId
.getName());
325 getProject().setProperty("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
326 getProject().setProperty("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
327 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
329 if( !FrameworkBuildTask
.multithread
) {
330 FrameworkBuildTask
.originalProperties
.put("PLATFORM", platformId
.getName());
331 FrameworkBuildTask
.originalProperties
.put("PLATFORM_FILE", platformId
.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
332 FrameworkBuildTask
.originalProperties
.put("PLATFORM_DIR", platformId
.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
333 FrameworkBuildTask
.originalProperties
.put("PLATFORM_RELATIVE_DIR", platformId
.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
337 // Build mode. User-defined output dir.
339 String buildMode
= saq
.getFpdIntermediateDirectories();
340 String userDefinedOutputDir
= saq
.getFpdOutputDirectory();
342 OutputManager
.getInstance().setup(userDefinedOutputDir
, buildMode
);
345 // TBD. Deal PCD and BuildOption related Info
347 GlobalData
.setFpdBuildOptions(saq
.getFpdBuildOptions());
349 GlobalData
.setToolChainPlatformInfo(saq
.getFpdToolChainInfo());
352 // Parse all list modules SA
354 parseModuleSAFiles();
357 // TBD. Deal PCD and BuildOption related Info
359 parseToolChainFamilyOptions();
360 parseToolChainOptions();
365 // Pcd Collection. Call CollectPCDAction to collect pcd info.
367 PlatformPcdPreprocessActionForBuilding ca
= new PlatformPcdPreprocessActionForBuilding();
368 ca
.perform(platformId
.getFpdFile().getPath(), ActionMessage
.NULL_MESSAGE_LEVEL
);
369 } catch (IOException ex
) {
370 BuildException buildException
= new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + ex
.getMessage());
371 buildException
.setStackTrace(ex
.getStackTrace());
372 throw buildException
;
373 } catch (XmlException ex
) {
374 BuildException buildException
= new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + ex
.getMessage());
375 buildException
.setStackTrace(ex
.getStackTrace());
376 throw buildException
;
377 } catch (EdkException ex
) {
378 BuildException buildException
= new BuildException("Parsing of the FPD file [" + fpdFile
.getPath() + "] failed!\n" + ex
.getMessage());
379 buildException
.setStackTrace(ex
.getStackTrace());
380 throw buildException
;
385 Parse all modules listed in FPD file.
387 void parseModuleSAFiles() throws EdkException
{
388 Map
<FpdModuleIdentification
, Map
<String
, XmlObject
>> moduleSAs
= saq
.getFpdModules();
391 // For every Module lists in FPD file.
393 Set
<FpdModuleIdentification
> keys
= moduleSAs
.keySet();
394 Iterator iter
= keys
.iterator();
395 while (iter
.hasNext()) {
396 FpdModuleIdentification fpdModuleId
= (FpdModuleIdentification
) iter
.next();
399 // Judge if Module is existed?
401 GlobalData
.registerFpdModuleSA(fpdModuleId
, moduleSAs
.get(fpdModuleId
));
404 // Put fpdModuleId to the corresponding FV
406 saq
.push(GlobalData
.getDoc(fpdModuleId
));
407 String fvBinding
= saq
.getModuleFvBindingKeyword();
409 fpdModuleId
.setFvBinding(fvBinding
);
410 updateFvs(fvBinding
, fpdModuleId
);
413 // Prepare for out put file name
415 ModuleIdentification moduleId
= fpdModuleId
.getModule();
417 String baseName
= saq
.getModuleOutputFileBasename();
419 if (baseName
== null) {
420 baseName
= moduleId
.getName();
422 outfiles
.put(fpdModuleId
, fpdModuleId
.getArch() + File
.separatorChar
423 + moduleId
.getGuid() + "-" + baseName
424 + getSuffix(moduleId
.getModuleType()));
427 // parse module build options, if any
429 GlobalData
.addModuleToolChainOption(fpdModuleId
, parseModuleBuildOptions(false));
430 GlobalData
.addModuleToolChainFamilyOption(fpdModuleId
, parseModuleBuildOptions(true));
435 ToolChainMap
parseModuleBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
436 String
[][] options
= saq
.getModuleBuildOptions(toolChainFamilyFlag
);
437 if (options
== null || options
.length
== 0) {
438 return new ToolChainMap();
440 return parseOptions(options
);
443 private ToolChainMap
parsePlatformBuildOptions(boolean toolChainFamilyFlag
) throws EdkException
{
444 String
[][] options
= saq
.getPlatformBuildOptions(toolChainFamilyFlag
);
445 if (options
== null || options
.length
== 0) {
446 return new ToolChainMap();
448 return parseOptions(options
);
451 private ToolChainMap
parseOptions(String
[][] options
) throws EdkException
{
452 ToolChainMap map
= new ToolChainMap();
453 int flagIndex
= ToolChainElement
.ATTRIBUTE
.value
;
455 for (int i
= 0; i
< options
.length
; ++i
) {
456 String flagString
= options
[i
][flagIndex
];
457 if (flagString
== null) {
460 options
[i
][flagIndex
] = ToolChainAttribute
.FLAGS
+ "";
461 map
.put(options
[i
], flagString
.trim());
467 private void parseToolChainFamilyOptions() throws EdkException
{
468 GlobalData
.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
471 private void parseToolChainOptions() throws EdkException
{
472 GlobalData
.setPlatformToolChainOption(parsePlatformBuildOptions(false));
476 Add the current module to corresponding FV.
478 @param fvName current FV name
479 @param moduleName current module identification
481 void updateFvs(String fvName
, FpdModuleIdentification fpdModuleId
) {
482 if (fvName
== null || fvName
.trim().length() == 0) {
485 String
[] fvNameArray
= fvName
.split("[, \t]+");
486 for (int i
= 0; i
< fvNameArray
.length
; i
++) {
488 // Put module to corresponding fvName
490 if (fvs
.containsKey(fvNameArray
[i
])) {
491 Set
<FpdModuleIdentification
> set
= fvs
.get(fvNameArray
[i
]);
492 set
.add(fpdModuleId
);
494 Set
<FpdModuleIdentification
> set
= new LinkedHashSet
<FpdModuleIdentification
>();
495 set
.add(fpdModuleId
);
496 fvs
.put(fvNameArray
[i
], set
);
502 Get the suffix based on module type. Current relationship are listed:
505 <b>ModuleType</b> <b>Suffix</b>
512 DXE_RUNTIME_DRIVER .DXE
517 UEFI_APPLICATION .APP
521 @param moduleType module type
523 @throws BuildException
524 If module type is null
526 public static String
getSuffix(String moduleType
) throws BuildException
{
527 if (moduleType
== null) {
528 throw new BuildException("Module type is not specified.");
531 String
[][] suffix
= EdkDefinitions
.ModuleTypeExtensions
;
533 for (int i
= 0; i
< suffix
.length
; i
++) {
534 if (suffix
[i
][0].equalsIgnoreCase(moduleType
)) {
548 public void addProperty(Property p
) {
549 properties
.addElement(p
);
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() + " ";