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