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