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