]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/Source/GenBuild/org/tianocore/build/fpd/FpdParserTask.java
To locate module precisely in stand-alone module build. Except Module Guid, add MSA...
[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 /**
302 Parse FPD file.
303
304 @throws BuildException
305 FPD file is not valid.
306 **/
307 void parseFpdFile() throws BuildException {
308 try {
309 XmlObject doc = XmlObject.Factory.parse(fpdFile);
310
311 if (!doc.validate()) {
312 throw new BuildException("Platform Surface Area file [" + fpdFile.getPath() + "] format is invalid!");
313 }
314
315 Map<String, XmlObject> map = new HashMap<String, XmlObject>();
316 map.put("PlatformSurfaceArea", doc);
317 saq = new SurfaceAreaQuery(map);
318
319 //
320 // Initialize
321 //
322 platformId = saq.getFpdHeader();
323 platformId.setFpdFile(fpdFile);
324 getProject().setProperty("PLATFORM", platformId.getName());
325 getProject().setProperty("PLATFORM_FILE", platformId.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
326 getProject().setProperty("PLATFORM_DIR", platformId.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
327 getProject().setProperty("PLATFORM_RELATIVE_DIR", platformId.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
328
329 if( !FrameworkBuildTask.multithread) {
330 FrameworkBuildTask.originalProperties.put("PLATFORM", platformId.getName());
331 FrameworkBuildTask.originalProperties.put("PLATFORM_FILE", platformId.getRelativeFpdFile().replaceAll("(\\\\)", "/"));
332 FrameworkBuildTask.originalProperties.put("PLATFORM_DIR", platformId.getFpdFile().getParent().replaceAll("(\\\\)", "/"));
333 FrameworkBuildTask.originalProperties.put("PLATFORM_RELATIVE_DIR", platformId.getPlatformRelativeDir().replaceAll("(\\\\)", "/"));
334 }
335
336 //
337 // Build mode. User-defined output dir.
338 //
339 String buildMode = saq.getFpdIntermediateDirectories();
340 String userDefinedOutputDir = saq.getFpdOutputDirectory();
341
342 OutputManager.getInstance().setup(userDefinedOutputDir, buildMode);
343
344 //
345 // TBD. Deal PCD and BuildOption related Info
346 //
347 GlobalData.setFpdBuildOptions(saq.getFpdBuildOptions());
348
349 GlobalData.setToolChainPlatformInfo(saq.getFpdToolChainInfo());
350
351 //
352 // Parse all list modules SA
353 //
354 parseModuleSAFiles();
355
356 //
357 // TBD. Deal PCD and BuildOption related Info
358 //
359 parseToolChainFamilyOptions();
360 parseToolChainOptions();
361
362 saq.push(map);
363
364 //
365 // Pcd Collection. Call CollectPCDAction to collect pcd info.
366 //
367 PlatformPcdPreprocessActionForBuilding ca = new PlatformPcdPreprocessActionForBuilding();
368 ca.perform(platformId.getFpdFile().getPath(), ActionMessage.NULL_MESSAGE_LEVEL);
369 } catch (IOException ex) {
370 BuildException buildException = new BuildException("Parsing of the FPD file [" + fpdFile.getPath() + "] failed!\n" + ex.getMessage());
371 buildException.setStackTrace(ex.getStackTrace());
372 throw buildException;
373 } catch (XmlException ex) {
374 BuildException buildException = new BuildException("Parsing of the FPD file [" + fpdFile.getPath() + "] failed!\n" + ex.getMessage());
375 buildException.setStackTrace(ex.getStackTrace());
376 throw buildException;
377 } catch (EdkException ex) {
378 BuildException buildException = new BuildException("Parsing of the FPD file [" + fpdFile.getPath() + "] failed!\n" + ex.getMessage());
379 buildException.setStackTrace(ex.getStackTrace());
380 throw buildException;
381 }
382 }
383
384 /**
385 Parse all modules listed in FPD file.
386 **/
387 void parseModuleSAFiles() throws EdkException{
388 Map<FpdModuleIdentification, Map<String, XmlObject>> moduleSAs = saq.getFpdModules();
389
390 //
391 // For every Module lists in FPD file.
392 //
393 Set<FpdModuleIdentification> keys = moduleSAs.keySet();
394 Iterator iter = keys.iterator();
395 while (iter.hasNext()) {
396 FpdModuleIdentification fpdModuleId = (FpdModuleIdentification) iter.next();
397
398 //
399 // Judge if Module is existed?
400 // TBD
401 GlobalData.registerFpdModuleSA(fpdModuleId, moduleSAs.get(fpdModuleId));
402
403 //
404 // Put fpdModuleId to the corresponding FV
405 //
406 saq.push(GlobalData.getDoc(fpdModuleId));
407 String fvBinding = saq.getModuleFvBindingKeyword();
408
409 fpdModuleId.setFvBinding(fvBinding);
410 updateFvs(fvBinding, fpdModuleId);
411
412 //
413 // Prepare for out put file name
414 //
415 ModuleIdentification moduleId = fpdModuleId.getModule();
416
417 String baseName = saq.getModuleOutputFileBasename();
418
419 if (baseName == null) {
420 baseName = moduleId.getName();
421 }
422 outfiles.put(fpdModuleId, fpdModuleId.getArch() + File.separatorChar
423 + moduleId.getGuid() + "-" + baseName
424 + getSuffix(moduleId.getModuleType()));
425
426 //
427 // parse module build options, if any
428 //
429 GlobalData.addModuleToolChainOption(fpdModuleId, parseModuleBuildOptions(false));
430 GlobalData.addModuleToolChainFamilyOption(fpdModuleId, parseModuleBuildOptions(true));
431 saq.pop();
432 }
433 }
434
435 ToolChainMap parseModuleBuildOptions(boolean toolChainFamilyFlag) throws EdkException {
436 String[][] options = saq.getModuleBuildOptions(toolChainFamilyFlag);
437 if (options == null || options.length == 0) {
438 return new ToolChainMap();
439 }
440 return parseOptions(options);
441 }
442
443 private ToolChainMap parsePlatformBuildOptions(boolean toolChainFamilyFlag) throws EdkException {
444 String[][] options = saq.getPlatformBuildOptions(toolChainFamilyFlag);
445 if (options == null || options.length == 0) {
446 return new ToolChainMap();
447 }
448 return parseOptions(options);
449 }
450
451 private ToolChainMap parseOptions(String[][] options) throws EdkException {
452 ToolChainMap map = new ToolChainMap();
453 int flagIndex = ToolChainElement.ATTRIBUTE.value;
454
455 for (int i = 0; i < options.length; ++i) {
456 String flagString = options[i][flagIndex];
457 if (flagString == null) {
458 flagString = "";
459 }
460 options[i][flagIndex] = ToolChainAttribute.FLAGS + "";
461 map.put(options[i], flagString.trim());
462 }
463
464 return map;
465 }
466
467 private void parseToolChainFamilyOptions() throws EdkException {
468 GlobalData.setPlatformToolChainFamilyOption(parsePlatformBuildOptions(true));
469 }
470
471 private void parseToolChainOptions() throws EdkException {
472 GlobalData.setPlatformToolChainOption(parsePlatformBuildOptions(false));
473 }
474
475 /**
476 Add the current module to corresponding FV.
477
478 @param fvName current FV name
479 @param moduleName current module identification
480 **/
481 void updateFvs(String fvName, FpdModuleIdentification fpdModuleId) {
482 if (fvName == null || fvName.trim().length() == 0) {
483 fvName = "NULL";
484 }
485 String[] fvNameArray = fvName.split("[, \t]+");
486 for (int i = 0; i < fvNameArray.length; i++) {
487 //
488 // Put module to corresponding fvName
489 //
490 if (fvs.containsKey(fvNameArray[i])) {
491 Set<FpdModuleIdentification> set = fvs.get(fvNameArray[i]);
492 set.add(fpdModuleId);
493 } else {
494 Set<FpdModuleIdentification> set = new LinkedHashSet<FpdModuleIdentification>();
495 set.add(fpdModuleId);
496 fvs.put(fvNameArray[i], set);
497 }
498 }
499 }
500
501 /**
502 Get the suffix based on module type. Current relationship are listed:
503
504 <pre>
505 <b>ModuleType</b> <b>Suffix</b>
506 BASE .FFS
507 SEC .SEC
508 PEI_CORE .PEI
509 PEIM .PEI
510 DXE_CORE .DXE
511 DXE_DRIVER .DXE
512 DXE_RUNTIME_DRIVER .DXE
513 DXE_SAL_DRIVER .DXE
514 DXE_SMM_DRIVER .DXE
515 TOOL .FFS
516 UEFI_DRIVER .DXE
517 UEFI_APPLICATION .APP
518 USER_DEFINED .FFS
519 </pre>
520
521 @param moduleType module type
522 @return
523 @throws BuildException
524 If module type is null
525 **/
526 public static String getSuffix(String moduleType) throws BuildException {
527 if (moduleType == null) {
528 throw new BuildException("Module type is not specified.");
529 }
530
531 String[][] suffix = EdkDefinitions.ModuleTypeExtensions;
532
533 for (int i = 0; i < suffix.length; i++) {
534 if (suffix[i][0].equalsIgnoreCase(moduleType)) {
535 return suffix[i][1];
536 }
537 }
538 //
539 // Default is '.FFS'
540 //
541 return ".FFS";
542 }
543 /**
544 Add a property.
545
546 @param p property
547 **/
548 public void addProperty(Property p) {
549 properties.addElement(p);
550 }
551
552 public void setFpdFile(File fpdFile) {
553 this.fpdFile = fpdFile;
554 }
555
556 public void setType(String type) {
557 this.type = type;
558 }
559
560 public String getAllArchForModule(ModuleIdentification moduleId) {
561 String archs = "";
562 Iterator<FpdModuleIdentification> iter = outfiles.keySet().iterator();
563 while (iter.hasNext()) {
564 FpdModuleIdentification fpdModuleId = iter.next();
565
566 if (fpdModuleId.getModule().equals(moduleId)) {
567 archs += fpdModuleId.getArch() + " ";
568 }
569 }
570
571 return archs;
572 }
573 }