]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/Source/GenBuild/org/tianocore/build/fpd/FpdParserTask.java
edaab68aaabc3c7d863faebe327a3df200b156cb
[mirror_edk2.git] / Tools / Source / GenBuild / org / tianocore / build / fpd / FpdParserTask.java
1 /** @file
2 This file is ANT task FpdParserTask.
3
4 FpdParserTask is used to parse FPD (Framework Platform Description) and generate
5 build.out.xml. It is for Package or Platform build use.
6
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
12
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.
15 **/
16 package org.tianocore.build.fpd;
17
18 import java.io.BufferedWriter;
19 import java.io.File;
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;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.Vector;
28
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;
34
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.global.GlobalData;
39 import org.tianocore.build.global.OutputManager;
40 import org.tianocore.build.global.SurfaceAreaQuery;
41 import org.tianocore.build.id.FpdModuleIdentification;
42 import org.tianocore.build.id.ModuleIdentification;
43 import org.tianocore.build.id.PlatformIdentification;
44 import org.tianocore.build.pcd.action.PlatformPcdPreprocessActionForBuilding;
45 import org.tianocore.build.toolchain.ToolChainAttribute;
46 import org.tianocore.build.toolchain.ToolChainElement;
47 import org.tianocore.build.toolchain.ToolChainMap;
48
49 /**
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.
53
54 <p>The task sets global properties PLATFORM, PLATFORM_DIR, PLATFORM_RELATIVE_DIR
55 and BUILD_DIR. </p>
56
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>
60
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>
64
65 <p>The method parseFpdFile is also prepared for single module build. </p>
66
67 <p>The usage is (take NT32 Platform for example):</p>
68
69 <pre>
70 &lt;FPDParser platformName="Nt32" /&gt;
71 </pre>
72
73 <p>The task will initialize all information through parsing Framework Database,
74 SPD, Tool chain configuration files. </p>
75
76 @since GenBuild 1.0
77 **/
78 public class FpdParserTask extends Task {
79
80 private String platformName;
81
82 private File fpdFile = null;
83
84 private PlatformIdentification platformId;
85
86 private String type;
87
88 ///
89 /// Mapping from modules identification to out put file name
90 ///
91 private Map<FpdModuleIdentification, String> outfiles = new LinkedHashMap<FpdModuleIdentification, String>();
92
93 ///
94 /// Mapping from FV name to its modules
95 ///
96 private Map<String, Set<FpdModuleIdentification>> fvs = new HashMap<String, Set<FpdModuleIdentification>>();
97
98 ///
99 /// FpdParserTask can specify some ANT properties.
100 ///
101 private Vector<Property> properties = new Vector<Property>();
102
103 private boolean isUnified = true;
104
105
106 /**
107 Public construct method. It is necessary for ANT task.
108 **/
109 public FpdParserTask() {
110 }
111
112 /**
113 ANT task's entry method. The main steps is described as following:
114
115 <ul>
116 <li>Initialize global information (Framework DB, SPD files and all MSA files
117 listed in SPD). This step will execute only once in whole build process;</li>
118 <li>Parse specified FPD file; </li>
119 <li>Generate FV.inf files; </li>
120 <li>Generate PlatformName_build.xml file for Flatform build; </li>
121 <li>Collect PCD information. </li>
122 </ul>
123
124 @throws BuildException
125 Surface area is not valid.
126 **/
127 public void execute() throws BuildException {
128 //
129 // If fpdFile is not specified,
130 // then try to get FPD file by platformName
131 //
132 if ( fpdFile == null) {
133 if (platformName == null) {
134 throw new BuildException("FpdParserTask parameter error. Please specify either the platform name or FPD file!");
135 }
136 platformId = GlobalData.getPlatformByName(platformName);
137 fpdFile = platformId.getFpdFile();
138 }
139
140 //
141 // Parse FPD file
142 //
143 parseFpdFile();
144
145 //
146 // Prepare BUILD_DIR
147 //
148 isUnified = OutputManager.getInstance().prepareBuildDir(getProject());
149
150 //
151 // For every Target and ToolChain
152 //
153 String[] targetList = GlobalData.getToolChainInfo().getTargets();
154 for (int i = 0; i < targetList.length; i++) {
155 String[] toolchainList = GlobalData.getToolChainInfo().getTagnames();
156 for(int j = 0; j < toolchainList.length; j++) {
157 //
158 // Prepare FV_DIR
159 //
160 String ffsCommonDir = getProject().getProperty("BUILD_DIR") + File.separatorChar
161 + targetList[i] + File.separatorChar
162 + toolchainList[j];
163 File fvDir = new File(ffsCommonDir + File.separatorChar + "FV");
164 fvDir.mkdirs();
165 getProject().setProperty("FV_DIR", fvDir.getPath().replaceAll("(\\\\)", "/"));
166
167 //
168 // Gen Fv.inf files
169 //
170 genFvInfFiles(ffsCommonDir);
171 }
172 }
173
174 //
175 // Gen build.xml
176 //
177 PlatformBuildFileGenerator fileGenerator = new PlatformBuildFileGenerator(getProject(), outfiles, isUnified);
178 fileGenerator.genBuildFile();
179
180 //
181 // Ant call ${PLATFORM}_build.xml
182 //
183
184 Ant ant = new Ant();
185 ant.setProject(getProject());
186 ant.setAntfile(platformId.getFpdFile().getParent() + File.separatorChar + platformId.getName() + "_build.xml");
187 ant.setTarget(type);
188 ant.setInheritAll(true);
189 ant.init();
190 ant.execute();
191 }
192
193 /**
194 Generate Fv.inf files. The Fv.inf file is composed with four
195 parts: Options, Attributes, Components and Files. The Fv.inf files
196 will be under FV_DIR.
197
198 @throws BuildException
199 File write FV.inf files error.
200 **/
201 private void genFvInfFiles(String ffsCommonDir) throws BuildException {
202 String[] validFv = SurfaceAreaQuery.getFpdValidImageNames();
203 for (int i = 0; i < validFv.length; i++) {
204 //
205 // Get all global variables from FPD and set them to properties
206 //
207 String[][] globalVariables = SurfaceAreaQuery.getFpdGlobalVariable();
208 for (int j = 0; j < globalVariables.length; j++) {
209 getProject().setProperty(globalVariables[j][0], globalVariables[j][1]);
210 }
211
212 getProject().setProperty("FV_FILENAME", validFv[i]);
213
214 File fvFile = new File(getProject().replaceProperties( getProject().getProperty("FV_DIR") + File.separatorChar + validFv[i] + ".inf"));
215 fvFile.getParentFile().mkdirs();
216
217 try {
218 FileWriter fw = new FileWriter(fvFile);
219 BufferedWriter bw = new BufferedWriter(fw);
220
221 //
222 // Options
223 //
224 String[][] options = SurfaceAreaQuery.getFpdOptions(validFv[i]);
225 if (options.length > 0) {
226 bw.write("[options]");
227 bw.newLine();
228 for (int j = 0; j < options.length; j++) {
229 StringBuffer str = new StringBuffer(100);
230 str.append(options[j][0]);
231 while (str.length() < 40) {
232 str.append(' ');
233 }
234 str.append("= ");
235 str.append(options[j][1]);
236 bw.write(getProject().replaceProperties(str.toString()));
237 bw.newLine();
238 }
239 bw.newLine();
240 }
241
242 //
243 // Attributes;
244 //
245 String[][] attributes = SurfaceAreaQuery.getFpdAttributes(validFv[i]);
246 if (attributes.length > 0) {
247 bw.write("[attributes]");
248 bw.newLine();
249 for (int j = 0; j < attributes.length; j++) {
250 StringBuffer str = new StringBuffer(100);
251 str.append(attributes[j][0]);
252 while (str.length() < 40) {
253 str.append(' ');
254 }
255 str.append("= ");
256 str.append(attributes[j][1]);
257 bw.write(getProject().replaceProperties(str.toString()));
258 bw.newLine();
259 }
260 bw.newLine();
261 }
262
263 //
264 // Components
265 //
266 String[][] components = SurfaceAreaQuery.getFpdComponents(validFv[i]);
267 if (components.length > 0) {
268 bw.write("[components]");
269 bw.newLine();
270 for (int j = 0; j < components.length; j++) {
271 StringBuffer str = new StringBuffer(100);
272 str.append(components[j][0]);
273 while (str.length() < 40) {
274 str.append(' ');
275 }
276 str.append("= ");
277 str.append(components[j][1]);
278 bw.write(getProject().replaceProperties(str.toString()));
279 bw.newLine();
280 }
281 bw.newLine();
282 }
283
284 //
285 // Files
286 //
287 Set<FpdModuleIdentification> filesSet = fvs.get(validFv[i]);
288 if (filesSet != null) {
289 FpdModuleIdentification[] files = filesSet.toArray(new FpdModuleIdentification[filesSet.size()]);
290 bw.write("[files]");
291 bw.newLine();
292 for (int j = 0; j < files.length; j++) {
293 String str = ffsCommonDir + File.separatorChar + outfiles.get(files[j]);
294 bw.write(getProject().replaceProperties("EFI_FILE_NAME = " + str));
295 bw.newLine();
296 }
297 }
298 bw.flush();
299 bw.close();
300 fw.close();
301 } catch (Exception e) {
302 throw new BuildException("Generation of the FV file [" + fvFile.getPath() + "] failed!\n" + e.getMessage());
303 }
304 }
305 }
306 /**
307 This method is used for Single Module Build.
308
309
310 @throws BuildException
311 FPD file is not valid.
312 **/
313 public void parseFpdFile(File fpdFile) throws BuildException {
314 this.fpdFile = fpdFile;
315 parseFpdFile();
316 }
317
318 /**
319 Parse FPD file.
320
321 @throws BuildException
322 FPD file is not valid.
323 **/
324 private void parseFpdFile() throws BuildException {
325 try {
326 XmlObject doc = XmlObject.Factory.parse(fpdFile);
327
328 if (!doc.validate()) {
329 throw new BuildException("Platform Surface Area file [" + fpdFile.getPath() + "] format is invalid!");
330 }
331
332 Map<String, XmlObject> map = new HashMap<String, XmlObject>();
333 map.put("PlatformSurfaceArea", doc);
334 SurfaceAreaQuery.setDoc(map);
335
336 //
337 // Initialize
338 //
339 platformId = SurfaceAreaQuery.getFpdHeader();
340 platformId.setFpdFile(fpdFile);
341 getProject().setProperty("PLATFORM", platformId.getName());
342 getProject().setProperty("PLATFORM_FILE", platformId.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
343 getProject().setProperty("PLATFORM_DIR", platformId.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
344 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
345
346 //
347 // Build mode. User-defined output dir.
348 //
349 String buildMode = SurfaceAreaQuery.getFpdIntermediateDirectories();
350 String userDefinedOutputDir = SurfaceAreaQuery.getFpdOutputDirectory();
351
352 OutputManager.getInstance().setup(userDefinedOutputDir, buildMode);
353
354 //
355 // TBD. Deal PCD and BuildOption related Info
356 //
357 GlobalData.setFpdBuildOptions(SurfaceAreaQuery.getFpdBuildOptions());
358
359 GlobalData.setToolChainPlatformInfo(SurfaceAreaQuery.getFpdToolChainInfo());
360
361 //
362 // Parse all list modules SA
363 //
364 parseModuleSAFiles();
365
366 //
367 // TBD. Deal PCD and BuildOption related Info
368 //
369 parseToolChainFamilyOptions();
370 parseToolChainOptions();
371
372 SurfaceAreaQuery.setDoc(map);
373
374 //
375 // Pcd Collection. Call CollectPCDAction to collect pcd info.
376 //
377 PlatformPcdPreprocessActionForBuilding ca = new PlatformPcdPreprocessActionForBuilding();
378 ca.perform(platformId.getFpdFile().getPath(), ActionMessage.NULL_MESSAGE_LEVEL);
379 } catch (Exception e) {
380 throw new BuildException("Parsing of the FPD file [" + fpdFile.getPath() + "] failed!\n" + e.getMessage());
381 }
382 }
383
384
385
386 /**
387 Parse all modules listed in FPD file.
388 **/
389 private void parseModuleSAFiles() throws EdkException{
390 Map<FpdModuleIdentification, Map<String, XmlObject>> moduleSAs = SurfaceAreaQuery.getFpdModules();
391
392 //
393 // For every Module lists in FPD file.
394 //
395 Set<FpdModuleIdentification> keys = moduleSAs.keySet();
396 Iterator iter = keys.iterator();
397 while (iter.hasNext()) {
398 FpdModuleIdentification fpdModuleId = (FpdModuleIdentification) iter.next();
399
400 //
401 // Judge if Module is existed?
402 // TBD
403
404 GlobalData.registerFpdModuleSA(fpdModuleId, moduleSAs.get(fpdModuleId));
405
406 //
407 // Put fpdModuleId to the corresponding FV
408 //
409 SurfaceAreaQuery.push(GlobalData.getDoc(fpdModuleId));
410 String fvBinding = SurfaceAreaQuery.getModuleFvBindingKeyword();
411
412 fpdModuleId.setFvBinding(fvBinding);
413 updateFvs(fvBinding, fpdModuleId);
414
415 //
416 // Prepare for out put file name
417 //
418 ModuleIdentification moduleId = fpdModuleId.getModule();
419
420 String baseName = SurfaceAreaQuery.getModuleOutputFileBasename();
421
422 if (baseName == null) {
423 baseName = moduleId.getName();
424 }
425 outfiles.put(fpdModuleId, fpdModuleId.getArch() + File.separatorChar
426 + moduleId.getGuid() + "-" + baseName
427 + getSuffix(moduleId.getModuleType()));
428
429 //
430 // parse module build options, if any
431 //
432 GlobalData.addModuleToolChainOption(fpdModuleId, parseModuleBuildOptions(false));
433 GlobalData.addModuleToolChainFamilyOption(fpdModuleId, parseModuleBuildOptions(true));
434 SurfaceAreaQuery.pop();
435 }
436 }
437
438 private ToolChainMap parseModuleBuildOptions(boolean toolChainFamilyFlag) throws EdkException {
439 String[][] options = SurfaceAreaQuery.getModuleBuildOptions(toolChainFamilyFlag);
440 if (options == null || options.length == 0) {
441 return null;
442 }
443 return parseOptions(options);
444 }
445
446 private ToolChainMap parsePlatformBuildOptions(boolean toolChainFamilyFlag) throws EdkException {
447 String[][] options = SurfaceAreaQuery.getPlatformBuildOptions(toolChainFamilyFlag);
448 if (options == null || options.length == 0) {
449 return null;
450 }
451 return parseOptions(options);
452 }
453
454 private ToolChainMap parseOptions(String[][] options) throws EdkException {
455 ToolChainMap map = new ToolChainMap();
456 int flagIndex = ToolChainElement.ATTRIBUTE.value;
457
458 for (int i = 0; i < options.length; ++i) {
459 String flagString = options[i][flagIndex];
460 if (flagString == null) {
461 flagString = "";
462 }
463 options[i][flagIndex] = ToolChainAttribute.FLAGS + "";
464 map.put(options[i], flagString.trim());
465 }
466
467 return map;
468 }
469
470 private void parseToolChainFamilyOptions() throws EdkException {
471 GlobalData.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
472 }
473
474 private void parseToolChainOptions() throws EdkException {
475 GlobalData.setPlatformToolChainOption(parsePlatformBuildOptions(false));
476 }
477
478 /**
479 Add the current module to corresponding FV.
480
481 @param fvName current FV name
482 @param moduleName current module identification
483 **/
484 private void updateFvs(String fvName, FpdModuleIdentification fpdModuleId) {
485 if (fvName == null || fvName.trim().length() == 0) {
486 fvName = "NULL";
487 }
488 String[] fvNameArray = fvName.split("[, \t]+");
489 for (int i = 0; i < fvNameArray.length; i++) {
490 //
491 // Put module to corresponding fvName
492 //
493 if (fvs.containsKey(fvNameArray[i])) {
494 Set<FpdModuleIdentification> set = fvs.get(fvNameArray[i]);
495 set.add(fpdModuleId);
496 } else {
497 Set<FpdModuleIdentification> set = new LinkedHashSet<FpdModuleIdentification>();
498 set.add(fpdModuleId);
499 fvs.put(fvNameArray[i], set);
500 }
501 }
502 }
503
504 /**
505 Get the suffix based on module type. Current relationship are listed:
506
507 <pre>
508 <b>ModuleType</b> <b>Suffix</b>
509 BASE .FFS
510 SEC .SEC
511 PEI_CORE .PEI
512 PEIM .PEI
513 DXE_CORE .DXE
514 DXE_DRIVER .DXE
515 DXE_RUNTIME_DRIVER .DXE
516 DXE_SAL_DRIVER .DXE
517 DXE_SMM_DRIVER .DXE
518 TOOL .FFS
519 UEFI_DRIVER .DXE
520 UEFI_APPLICATION .APP
521 USER_DEFINED .FFS
522 </pre>
523
524 @param moduleType module type
525 @return
526 @throws BuildException
527 If module type is null
528 **/
529 public static String getSuffix(String moduleType) throws BuildException {
530 if (moduleType == null) {
531 throw new BuildException("Module type is not specified.");
532 }
533
534 String[][] suffix = EdkDefinitions.ModuleTypeExtensions;
535
536 for (int i = 0; i < suffix.length; i++) {
537 if (suffix[i][0].equalsIgnoreCase(moduleType)) {
538 return suffix[i][1];
539 }
540 }
541 //
542 // Default is '.FFS'
543 //
544 return ".FFS";
545 }
546 /**
547 Add a property.
548
549 @param p property
550 **/
551 public void addProperty(Property p) {
552 properties.addElement(p);
553 }
554
555 public void setPlatformName(String platformName) {
556 this.platformName = platformName;
557 }
558
559 public void setFpdFile(File fpdFile) {
560 this.fpdFile = fpdFile;
561 }
562
563 public void setType(String type) {
564 this.type = type;
565 }
566 }