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