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