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