]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/Source/GenBuild/org/tianocore/build/fpd/FpdParserTask.java
addb43a6cf637dd917c56e74126370179c3a0123
[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 if (fvFile.exists() && (fvFile.lastModified() >= fpdFile.lastModified())) {
197 //
198 // don't re-generate FV.inf if fpd has not been changed
199 //
200 continue;
201 }
202 fvFile.getParentFile().mkdirs();
203
204 try {
205 FileWriter fw = new FileWriter(fvFile);
206 BufferedWriter bw = new BufferedWriter(fw);
207
208 //
209 // Options
210 //
211 String[][] options = saq.getFpdOptions(validFv[i]);
212 if (options.length > 0) {
213 bw.write("[options]");
214 bw.newLine();
215 for (int j = 0; j < options.length; j++) {
216 StringBuffer str = new StringBuffer(100);
217 str.append(options[j][0]);
218 while (str.length() < 40) {
219 str.append(' ');
220 }
221 str.append("= ");
222 str.append(options[j][1]);
223 bw.write(getProject().replaceProperties(str.toString()));
224 bw.newLine();
225 }
226 bw.newLine();
227 }
228
229 //
230 // Attributes;
231 //
232 String[][] attributes = saq.getFpdAttributes(validFv[i]);
233 if (attributes.length > 0) {
234 bw.write("[attributes]");
235 bw.newLine();
236 for (int j = 0; j < attributes.length; j++) {
237 StringBuffer str = new StringBuffer(100);
238 str.append(attributes[j][0]);
239 while (str.length() < 40) {
240 str.append(' ');
241 }
242 str.append("= ");
243 str.append(attributes[j][1]);
244 bw.write(getProject().replaceProperties(str.toString()));
245 bw.newLine();
246 }
247 bw.newLine();
248 }
249
250 //
251 // Components
252 //
253 String[][] components = saq.getFpdComponents(validFv[i]);
254 if (components.length > 0) {
255 bw.write("[components]");
256 bw.newLine();
257 for (int j = 0; j < components.length; j++) {
258 StringBuffer str = new StringBuffer(100);
259 str.append(components[j][0]);
260 while (str.length() < 40) {
261 str.append(' ');
262 }
263 str.append("= ");
264 str.append(components[j][1]);
265 bw.write(getProject().replaceProperties(str.toString()));
266 bw.newLine();
267 }
268 bw.newLine();
269 }
270
271 //
272 // Files
273 //
274 Set<FpdModuleIdentification> filesSet = fvs.get(validFv[i]);
275 if (filesSet != null) {
276 FpdModuleIdentification[] files = filesSet.toArray(new FpdModuleIdentification[filesSet.size()]);
277 bw.write("[files]");
278 bw.newLine();
279 for (int j = 0; j < files.length; j++) {
280 String str = ffsCommonDir + File.separatorChar + outfiles.get(files[j]);
281 bw.write(getProject().replaceProperties("EFI_FILE_NAME = " + str));
282 bw.newLine();
283 }
284 }
285 bw.flush();
286 bw.close();
287 fw.close();
288 } catch (IOException ex) {
289 BuildException buildException = new BuildException("Generation of the FV file [" + fvFile.getPath() + "] failed!\n" + ex.getMessage());
290 buildException.setStackTrace(ex.getStackTrace());
291 throw buildException;
292 }
293 }
294 }
295 /**
296 This method is used for Single Module Build.
297
298
299 @throws BuildException
300 FPD file is not valid.
301 **/
302 public void parseFpdFile(File fpdFile) throws BuildException, EdkException {
303 this.fpdFile = fpdFile;
304 parseFpdFile();
305
306 //
307 // Call Platform_build.xml prebuild firstly in stand-alone build
308 // Prepare BUILD_DIR
309 //
310 isUnified = OutputManager.getInstance().prepareBuildDir(getProject());
311
312 String buildDir = getProject().getProperty("BUILD_DIR");
313 //
314 // For every Target and ToolChain
315 //
316 String[] targetList = GlobalData.getToolChainInfo().getTargets();
317 for (int i = 0; i < targetList.length; i++) {
318 String[] toolchainList = GlobalData.getToolChainInfo().getTagnames();
319 for(int j = 0; j < toolchainList.length; j++) {
320 //
321 // Prepare FV_DIR
322 //
323 String ffsCommonDir = buildDir + File.separatorChar
324 + targetList[i] + "_"
325 + toolchainList[j];
326 File fvDir = new File(ffsCommonDir + File.separatorChar + "FV");
327 fvDir.mkdirs();
328 }
329 }
330
331 String platformBuildFile = buildDir + File.separatorChar + platformId.getName() + "_build.xml";
332 PlatformBuildFileGenerator fileGenerator = new PlatformBuildFileGenerator(getProject(), outfiles, fvs, isUnified, saq, platformBuildFile);
333 fileGenerator.genBuildFile();
334
335 Ant ant = new Ant();
336 ant.setProject(getProject());
337 ant.setAntfile(platformBuildFile);
338 ant.setTarget("prebuild");
339 ant.setInheritAll(true);
340 ant.init();
341 ant.execute();
342 }
343
344 /**
345 Parse FPD file.
346
347 @throws BuildException
348 FPD file is not valid.
349 **/
350 void parseFpdFile() throws BuildException {
351 try {
352 XmlObject doc = XmlObject.Factory.parse(fpdFile);
353
354 if (!doc.validate()) {
355 throw new BuildException("Platform Surface Area file [" + fpdFile.getPath() + "] format is invalid!");
356 }
357
358 Map<String, XmlObject> map = new HashMap<String, XmlObject>();
359 map.put("PlatformSurfaceArea", doc);
360 saq = new SurfaceAreaQuery(map);
361
362 //
363 // Initialize
364 //
365 platformId = saq.getFpdHeader();
366 platformId.setFpdFile(fpdFile);
367 getProject().setProperty("PLATFORM", platformId.getName());
368 getProject().setProperty("PLATFORM_FILE", platformId.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
369 getProject().setProperty("PLATFORM_DIR", platformId.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
370 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
371
372 if( !FrameworkBuildTask.multithread) {
373 FrameworkBuildTask.originalProperties.put("PLATFORM", platformId.getName());
374 FrameworkBuildTask.originalProperties.put("PLATFORM_FILE", platformId.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
375 FrameworkBuildTask.originalProperties.put("PLATFORM_DIR", platformId.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
376 FrameworkBuildTask.originalProperties.put("PLATFORM_RELATIVE_DIR", platformId.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
377 }
378
379 //
380 // Build mode. User-defined output dir.
381 //
382 String buildMode = saq.getFpdIntermediateDirectories();
383 String userDefinedOutputDir = saq.getFpdOutputDirectory();
384
385 OutputManager.getInstance().setup(userDefinedOutputDir, buildMode);
386
387 //
388 // TBD. Deal PCD and BuildOption related Info
389 //
390 GlobalData.setFpdBuildOptions(saq.getFpdBuildOptions());
391
392 GlobalData.setToolChainPlatformInfo(saq.getFpdToolChainInfo());
393
394 //
395 // Parse all list modules SA
396 //
397 parseModuleSAFiles();
398
399 //
400 // TBD. Deal PCD and BuildOption related Info
401 //
402 parseToolChainFamilyOptions();
403 parseToolChainOptions();
404
405 saq.push(map);
406
407 //
408 // Pcd Collection. Call CollectPCDAction to collect pcd info.
409 //
410 PlatformPcdPreprocessActionForBuilding ca = new PlatformPcdPreprocessActionForBuilding();
411 ca.perform(platformId.getFpdFile().getPath(), ActionMessage.NULL_MESSAGE_LEVEL);
412 } catch (IOException ex) {
413 BuildException buildException = new BuildException("Parsing of the FPD file [" + fpdFile.getPath() + "] failed!\n" + ex.getMessage());
414 buildException.setStackTrace(ex.getStackTrace());
415 throw buildException;
416 } catch (XmlException ex) {
417 BuildException buildException = new BuildException("Parsing of the FPD file [" + fpdFile.getPath() + "] failed!\n" + ex.getMessage());
418 buildException.setStackTrace(ex.getStackTrace());
419 throw buildException;
420 } catch (EdkException ex) {
421 BuildException buildException = new BuildException("Parsing of the FPD file [" + fpdFile.getPath() + "] failed!\n" + ex.getMessage());
422 buildException.setStackTrace(ex.getStackTrace());
423 throw buildException;
424 }
425 }
426
427 /**
428 Parse all modules listed in FPD file.
429 **/
430 void parseModuleSAFiles() throws EdkException{
431 Map<FpdModuleIdentification, Map<String, XmlObject>> moduleSAs = saq.getFpdModules();
432
433 //
434 // For every Module lists in FPD file.
435 //
436 Set<FpdModuleIdentification> keys = moduleSAs.keySet();
437 Iterator iter = keys.iterator();
438 while (iter.hasNext()) {
439 FpdModuleIdentification fpdModuleId = (FpdModuleIdentification) iter.next();
440
441 //
442 // Judge if Module is existed?
443 // TBD
444 GlobalData.registerFpdModuleSA(fpdModuleId, moduleSAs.get(fpdModuleId));
445
446 //
447 // Put fpdModuleId to the corresponding FV
448 //
449 saq.push(GlobalData.getDoc(fpdModuleId));
450 String fvBinding = saq.getModuleFvBindingKeyword();
451
452 fpdModuleId.setFvBinding(fvBinding);
453 updateFvs(fvBinding, fpdModuleId);
454
455 //
456 // Prepare for out put file name
457 //
458 ModuleIdentification moduleId = fpdModuleId.getModule();
459
460 String baseName = saq.getModuleOutputFileBasename();
461
462 if (baseName == null) {
463 baseName = moduleId.getName();
464 }
465 outfiles.put(fpdModuleId, fpdModuleId.getArch() + File.separatorChar
466 + moduleId.getGuid() + "-" + baseName
467 + getSuffix(moduleId.getModuleType()));
468
469 //
470 // parse module build options, if any
471 //
472 GlobalData.addModuleToolChainOption(fpdModuleId, parseModuleBuildOptions(false));
473 GlobalData.addModuleToolChainFamilyOption(fpdModuleId, parseModuleBuildOptions(true));
474 saq.pop();
475 }
476 }
477
478 ToolChainMap parseModuleBuildOptions(boolean toolChainFamilyFlag) throws EdkException {
479 String[][] options = saq.getModuleBuildOptions(toolChainFamilyFlag);
480 if (options == null || options.length == 0) {
481 return new ToolChainMap();
482 }
483 return parseOptions(options);
484 }
485
486 private ToolChainMap parsePlatformBuildOptions(boolean toolChainFamilyFlag) throws EdkException {
487 String[][] options = saq.getPlatformBuildOptions(toolChainFamilyFlag);
488 if (options == null || options.length == 0) {
489 return new ToolChainMap();
490 }
491 return parseOptions(options);
492 }
493
494 private ToolChainMap parseOptions(String[][] options) throws EdkException {
495 ToolChainMap map = new ToolChainMap();
496 int flagIndex = ToolChainElement.ATTRIBUTE.value;
497
498 for (int i = 0; i < options.length; ++i) {
499 String flagString = options[i][flagIndex];
500 if (flagString == null) {
501 flagString = "";
502 }
503 options[i][flagIndex] = ToolChainAttribute.FLAGS + "";
504 map.put(options[i], flagString.trim());
505 }
506
507 return map;
508 }
509
510 private void parseToolChainFamilyOptions() throws EdkException {
511 GlobalData.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
512 }
513
514 private void parseToolChainOptions() throws EdkException {
515 GlobalData.setPlatformToolChainOption(parsePlatformBuildOptions(false));
516 }
517
518 /**
519 Add the current module to corresponding FV.
520
521 @param fvName current FV name
522 @param moduleName current module identification
523 **/
524 void updateFvs(String fvName, FpdModuleIdentification fpdModuleId) {
525 if (fvName == null || fvName.trim().length() == 0) {
526 fvName = "NULL";
527 }
528 String[] fvNameArray = fvName.split("[, \t]+");
529 for (int i = 0; i < fvNameArray.length; i++) {
530 //
531 // Put module to corresponding fvName
532 //
533 if (fvs.containsKey(fvNameArray[i])) {
534 Set<FpdModuleIdentification> set = fvs.get(fvNameArray[i]);
535 set.add(fpdModuleId);
536 } else {
537 Set<FpdModuleIdentification> set = new LinkedHashSet<FpdModuleIdentification>();
538 set.add(fpdModuleId);
539 fvs.put(fvNameArray[i], set);
540 }
541 }
542 }
543
544 /**
545 Get the suffix based on module type. Current relationship are listed:
546
547 <pre>
548 <b>ModuleType</b> <b>Suffix</b>
549 BASE .FFS
550 SEC .SEC
551 PEI_CORE .PEI
552 PEIM .PEI
553 DXE_CORE .DXE
554 DXE_DRIVER .DXE
555 DXE_RUNTIME_DRIVER .DXE
556 DXE_SAL_DRIVER .DXE
557 DXE_SMM_DRIVER .DXE
558 TOOL .FFS
559 UEFI_DRIVER .DXE
560 UEFI_APPLICATION .APP
561 USER_DEFINED .FFS
562 </pre>
563
564 @param moduleType module type
565 @return
566 @throws BuildException
567 If module type is null
568 **/
569 public static String getSuffix(String moduleType) throws BuildException {
570 if (moduleType == null) {
571 throw new BuildException("Module type is not specified.");
572 }
573
574 String[][] suffix = EdkDefinitions.ModuleTypeExtensions;
575
576 for (int i = 0; i < suffix.length; i++) {
577 if (suffix[i][0].equalsIgnoreCase(moduleType)) {
578 return suffix[i][1];
579 }
580 }
581 //
582 // Default is '.FFS'
583 //
584 return ".FFS";
585 }
586 /**
587 Add a property.
588
589 @param p property
590 **/
591 public void addProperty(Property p) {
592 properties.addElement(p);
593 }
594
595 public void setFpdFile(File fpdFile) {
596 this.fpdFile = fpdFile;
597 }
598
599 public void setType(String type) {
600 this.type = type;
601 }
602
603 public String getAllArchForModule(ModuleIdentification moduleId) {
604 String archs = "";
605 Iterator<FpdModuleIdentification> iter = outfiles.keySet().iterator();
606 while (iter.hasNext()) {
607 FpdModuleIdentification fpdModuleId = iter.next();
608
609 if (fpdModuleId.getModule().equals(moduleId)) {
610 archs += fpdModuleId.getArch() + " ";
611 }
612 }
613
614 return archs;
615 }
616 }