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