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