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