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