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