3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 package org
.tianocore
.build
;
15 import java
.util
.LinkedHashMap
;
16 import java
.util
.LinkedHashSet
;
19 import java
.io
.FileOutputStream
;
20 import java
.io
.OutputStreamWriter
;
22 import javax
.xml
.parsers
.DocumentBuilder
;
23 import javax
.xml
.parsers
.DocumentBuilderFactory
;
24 import javax
.xml
.transform
.OutputKeys
;
25 import javax
.xml
.transform
.Result
;
26 import javax
.xml
.transform
.Source
;
27 import javax
.xml
.transform
.Transformer
;
28 import javax
.xml
.transform
.TransformerFactory
;
29 import javax
.xml
.transform
.dom
.DOMSource
;
30 import javax
.xml
.transform
.stream
.StreamResult
;
32 import org
.apache
.tools
.ant
.BuildException
;
33 import org
.apache
.tools
.ant
.Project
;
34 import org
.tianocore
.build
.fpd
.FpdParserTask
;
35 import org
.tianocore
.build
.global
.GlobalData
;
36 import org
.tianocore
.build
.global
.SurfaceAreaQuery
;
37 import org
.tianocore
.build
.id
.FpdModuleIdentification
;
38 import org
.tianocore
.build
.id
.ModuleIdentification
;
39 import org
.tianocore
.build
.id
.PackageIdentification
;
40 import org
.w3c
.dom
.Comment
;
41 import org
.w3c
.dom
.Document
;
42 import org
.w3c
.dom
.Element
;
43 import org
.w3c
.dom
.Node
;
45 public class ModuleBuildFileGenerator
{
48 /// Pass: TARGET, TOOLCHAIN, ARCH
49 /// PACKAGE, PACKAGE_GUID, PACKAGE_VERSION
51 String
[] inheritProperties
= {"ARCH", "MODULE_GUID", "MODULE_VERSION", "PLATFORM_FILE", "PACKAGE_GUID", "PACKAGE_VERSION"};
54 /// The information at the header of <em>build.xml</em>.
56 private String info
= "DO NOT EDIT \n"
57 + "File auto-generated by build utility\n"
60 + "Auto-generated ANT build file for building of EFI Modules/Platforms\n";
62 private FpdModuleIdentification fpdModuleId
;
64 private Project project
;
66 private String ffsKeyword
;
68 public ModuleBuildFileGenerator(Project project
, String ffsKeyword
, FpdModuleIdentification fpdModuleId
) {
69 this.project
= project
;
70 this.fpdModuleId
= fpdModuleId
;
71 this.ffsKeyword
= ffsKeyword
;
75 The whole BaseName_build.xml is composed of seven part.
77 <li> ANT properties; </li>
78 <li> Dependent module (dependent library instances in most case); </li>
79 <li> Source files; </li>
80 <li> Sections if module is not library; </li>
81 <li> Output (different for library module and driver module); </li>
86 @throws BuildException
87 Error throws during BaseName_build.xml generating.
89 public void genBuildFile(String buildFilename
) throws BuildException
{
90 FfsProcess fp
= new FfsProcess();
91 DocumentBuilderFactory domfac
= DocumentBuilderFactory
.newInstance();
93 DocumentBuilder dombuilder
= domfac
.newDocumentBuilder();
94 Document document
= dombuilder
.newDocument();
95 Comment rootComment
= document
.createComment(info
);
98 // create root element and its attributes
100 Element root
= document
.createElement("project");
101 root
.setAttribute("name", fpdModuleId
.getModule().getName());
102 root
.setAttribute("default", "all");
103 root
.setAttribute("basedir", ".");
106 // element for External ANT tasks
108 root
.appendChild(document
.createComment("Apply external ANT tasks"));
109 Element ele
= document
.createElement("taskdef");
110 ele
.setAttribute("resource", "frameworktasks.tasks");
111 root
.appendChild(ele
);
112 ele
= document
.createElement("taskdef");
113 ele
.setAttribute("resource", "cpptasks.tasks");
114 root
.appendChild(ele
);
115 ele
= document
.createElement("typedef");
116 ele
.setAttribute("resource", "cpptasks.types");
117 root
.appendChild(ele
);
118 ele
= document
.createElement("taskdef");
119 ele
.setAttribute("resource", "net/sf/antcontrib/antlib.xml");
120 root
.appendChild(ele
);
123 // Generate the default target,
124 // which depends on init, sections and output target
126 root
.appendChild(document
.createComment("Default target"));
127 ele
= document
.createElement("target");
128 ele
.setAttribute("name", "all");
129 ele
.setAttribute("depends", "libraries, sourcefiles, sections, output");
130 root
.appendChild(ele
);
133 // compile all source files
135 root
.appendChild(document
.createComment("Compile all dependency Library instances."));
136 ele
= document
.createElement("target");
137 ele
.setAttribute("name", "libraries");
140 // Parse all sourfiles but files specified in sections
142 applyLibraryInstance(document
, ele
);
143 root
.appendChild(ele
);
146 // compile all source files
148 root
.appendChild(document
.createComment("sourcefiles target"));
149 ele
= document
.createElement("target");
150 ele
.setAttribute("name", "sourcefiles");
153 // Parse all sourfiles but files specified in sections
155 applyCompileElement(document
, ele
);
156 root
.appendChild(ele
);
159 // generate the init target
160 // main purpose is create all nessary pathes
161 // generate the sections target
163 root
.appendChild(document
.createComment("sections target"));
164 ele
= document
.createElement("target");
165 ele
.setAttribute("name", "sections");
166 applySectionsElement(document
, ele
, fp
);
167 root
.appendChild(ele
);
170 // generate the output target
172 root
.appendChild(document
.createComment("output target"));
173 ele
= document
.createElement("target");
174 ele
.setAttribute("name", "output");
175 applyOutputElement(document
, ele
, fp
);
176 root
.appendChild(ele
);
180 // generate the clean target
182 root
.appendChild(document
.createComment("clean target"));
183 ele
= document
.createElement("target");
184 ele
.setAttribute("name", "clean");
185 applyCleanElement(document
, ele
);
186 root
.appendChild(ele
);
189 // generate the Clean All target
191 root
.appendChild(document
.createComment("Clean All target"));
192 ele
= document
.createElement("target");
193 ele
.setAttribute("name", "cleanall");
194 applyDeepcleanElement(document
, ele
);
195 root
.appendChild(ele
);
198 // add the root element to the document
200 document
.appendChild(rootComment
);
201 document
.appendChild(root
);
203 // Prepare the DOM document for writing
205 Source source
= new DOMSource(document
);
208 // Prepare the output file
210 File file
= new File(buildFilename
);
213 // generate all directory path
215 (new File(file
.getParent())).mkdirs();
216 FileOutputStream outputStream
= new FileOutputStream(file
);
217 Result result
= new StreamResult(new OutputStreamWriter(outputStream
));
220 // Write the DOM document to the file
222 Transformer xformer
= TransformerFactory
.newInstance().newTransformer();
223 xformer
.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
224 xformer
.setOutputProperty(OutputKeys
.INDENT
, "yes");
225 xformer
.transform(source
, result
);
226 } catch (Exception ex
) {
227 throw new BuildException("Module [" + fpdModuleId
.getModule().getName() + "] generating build file failed.\n" + ex
.getMessage());
232 Generate the clean elements for BaseName_build.xml.
234 @param document current BaseName_build.xml XML document
235 @param root Root element for current
237 private void applyCleanElement(Document document
, Node root
) {
238 ModuleIdentification
[] libinstances
= SurfaceAreaQuery
.getLibraryInstance(fpdModuleId
.getArch());
239 for (int i
= 0; i
< libinstances
.length
; i
++) {
241 // Put package file path to module identification
243 PackageIdentification packageId
= libinstances
[i
].getPackage();
246 // Generate ANT script to clean
248 Element ele
= document
.createElement("GenBuild");
249 ele
.setAttribute("type", "clean");
252 // Prepare pass down information
254 Map
<String
, String
> passDownMap
= new LinkedHashMap
<String
, String
>();
255 for (int j
= 0; j
< inheritProperties
.length
; j
++){
256 passDownMap
.put(inheritProperties
[j
], "${" + inheritProperties
[j
] + "}");
258 passDownMap
.put("MODULE_GUID", libinstances
[i
].getGuid());
259 passDownMap
.put("MODULE_VERSION", libinstances
[i
].getVersion());
261 passDownMap
.put("PACKAGE_GUID", packageId
.getGuid());
262 passDownMap
.put("PACKAGE_VERSION", packageId
.getVersion());
264 for (int j
= 0; j
< inheritProperties
.length
; j
++){
265 Element property
= document
.createElement("property");
266 property
.setAttribute("name", inheritProperties
[j
]);
267 property
.setAttribute("value", passDownMap
.get(inheritProperties
[j
]));
268 ele
.appendChild(property
);
271 root
.appendChild(ele
);
274 // <delete includeemptydirs="true">
275 // <fileset dir="${DEST_DIR_OUTPUT}" includes="" excludes="" />
278 Element deleteEle
= document
.createElement("delete");
279 deleteEle
.setAttribute("includeemptydirs", "true");
280 Element filesetEle
= document
.createElement("fileset");
281 filesetEle
.setAttribute("dir", "${DEST_DIR_OUTPUT}");
282 filesetEle
.setAttribute("includes", "**/*");
283 filesetEle
.setAttribute("excludes", "*.xml");
284 deleteEle
.appendChild(filesetEle
);
285 root
.appendChild(deleteEle
);
289 Generate the cleanall elements for BaseName_build.xml.
291 @param document current BaseName_build.xml XML document
292 @param root Root element for current
294 private void applyDeepcleanElement(Document document
, Node root
) {
295 ModuleIdentification
[] libinstances
= SurfaceAreaQuery
.getLibraryInstance(fpdModuleId
.getArch());
296 for (int i
= 0; i
< libinstances
.length
; i
++) {
298 // Put package file path to module identification
300 PackageIdentification packageId
= libinstances
[i
].getPackage();
303 // Generate ANT script to clean
305 Element ele
= document
.createElement("GenBuild");
306 ele
.setAttribute("type", "cleanall");
309 // Prepare pass down information
311 Map
<String
, String
> passDownMap
= new LinkedHashMap
<String
, String
>();
312 for (int j
= 0; j
< inheritProperties
.length
; j
++){
313 passDownMap
.put(inheritProperties
[j
], "${" + inheritProperties
[j
] + "}");
316 passDownMap
.put("MODULE_GUID", libinstances
[i
].getGuid());
317 passDownMap
.put("MODULE_VERSION", libinstances
[i
].getVersion());
319 passDownMap
.put("PACKAGE_GUID", packageId
.getGuid());
320 passDownMap
.put("PACKAGE_VERSION", packageId
.getVersion());
322 for (int j
= 0; j
< inheritProperties
.length
; j
++){
323 Element property
= document
.createElement("property");
324 property
.setAttribute("name", inheritProperties
[j
]);
325 property
.setAttribute("value", passDownMap
.get(inheritProperties
[j
]));
326 ele
.appendChild(property
);
329 root
.appendChild(ele
);
332 // <delete includeemptydirs="true">
333 // <fileset dir="${DEST_DIR_OUTPUT}" includes="" excludes="" />
336 Element deleteEle
= document
.createElement("delete");
337 deleteEle
.setAttribute("includeemptydirs", "true");
338 Element filesetEle
= document
.createElement("fileset");
339 filesetEle
.setAttribute("dir", "${DEST_DIR_OUTPUT}");
340 filesetEle
.setAttribute("includes", "**/*");
341 filesetEle
.setAttribute("excludes", "*.xml");
342 deleteEle
.appendChild(filesetEle
);
343 root
.appendChild(deleteEle
);
346 // <delete includeemptydirs="true">
347 // <fileset dir="${DEST_DIR_DEBUG}" includes="" />
350 deleteEle
= document
.createElement("delete");
351 deleteEle
.setAttribute("includeemptydirs", "true");
352 filesetEle
= document
.createElement("fileset");
353 filesetEle
.setAttribute("dir", "${DEST_DIR_DEBUG}");
354 filesetEle
.setAttribute("includes", "**/*");
355 deleteEle
.appendChild(filesetEle
);
356 root
.appendChild(deleteEle
);
360 Generate the dependent library instances elements for BaseName_build.xml.
362 @param document current BaseName_build.xml XML document
363 @param root Root element for current
365 private void applyLibraryInstance(Document document
, Node root
) {
366 ModuleIdentification
[] libinstances
= SurfaceAreaQuery
.getLibraryInstance(fpdModuleId
.getArch());
367 // String propertyLibs = "";
368 for (int i
= 0; i
< libinstances
.length
; i
++) {
370 // Put package file path to module identification
372 PackageIdentification packageId
= libinstances
[i
].getPackage();
375 // Generate ANT script to build library instances
377 Element ele
= document
.createElement("GenBuild");
378 ele
.setAttribute("type", "build");
379 // ele.setAttribute("inheritAll", "false");
382 // Prepare pass down information
384 Map
<String
, String
> passDownMap
= new LinkedHashMap
<String
, String
>();
385 for (int j
= 0; j
< inheritProperties
.length
; j
++){
386 passDownMap
.put(inheritProperties
[j
], "${" + inheritProperties
[j
] + "}");
389 passDownMap
.put("MODULE_GUID", libinstances
[i
].getGuid());
390 passDownMap
.put("MODULE_VERSION", libinstances
[i
].getVersion());
392 passDownMap
.put("PACKAGE_GUID", packageId
.getGuid());
393 passDownMap
.put("PACKAGE_VERSION", packageId
.getVersion());
395 for (int j
= 0; j
< inheritProperties
.length
; j
++){
396 Element property
= document
.createElement("property");
397 property
.setAttribute("name", inheritProperties
[j
]);
398 property
.setAttribute("value", passDownMap
.get(inheritProperties
[j
]));
399 ele
.appendChild(property
);
402 root
.appendChild(ele
);
403 // propertyLibs += " " + project.getProperty("BIN_DIR") + File.separatorChar + libinstances[i].getName() + ".lib";
405 // project.setProperty("LIBS", propertyLibs.replaceAll("(\\\\)", "/"));
409 Return the name of the directory that corresponds to the architecture.
410 This is a translation from the XML Schema tag to a directory that
411 corresponds to our directory name coding convention.
414 private String
archDir(String arch
) {
415 return arch
.replaceFirst("X64", "x64")
416 .replaceFirst("IPF", "Ipf")
417 .replaceFirst("IA32", "Ia32")
418 .replaceFirst("ARM", "Arm")
419 .replaceFirst("EBC", "Ebc");
423 Generate the build source files elements for BaseName_build.xml.
425 @param document current BaseName_build.xml XML document
426 @param root Root element for current
428 private void applyCompileElement(Document document
, Node root
) {
430 // Prepare the includes: PackageDependencies and Output debug direactory
432 Set
<String
> includes
= new LinkedHashSet
<String
>();
433 String arch
= project
.getProperty("ARCH");
438 includes
.add("${WORKSPACE_DIR}" + File
.separatorChar
);
443 includes
.add("${MODULE_DIR}");
444 includes
.add("${MODULE_DIR}" + File
.separatorChar
+ archDir(arch
));
447 // Packages in PackageDenpendencies
449 PackageIdentification
[] packageDependencies
= SurfaceAreaQuery
.getDependencePkg(fpdModuleId
.getArch());
450 for (int i
= 0; i
< packageDependencies
.length
; i
++) {
451 GlobalData
.refreshPackageIdentification(packageDependencies
[i
]);
452 File packageFile
= packageDependencies
[i
].getSpdFile();
453 includes
.add(packageFile
.getParent() + File
.separatorChar
+ "Include");
454 includes
.add(packageFile
.getParent() + File
.separatorChar
+ "Include" + File
.separatorChar
+ archDir(arch
));
458 // All Dependency Library Instance's PackageDependencies
460 ModuleIdentification
[] libinstances
= SurfaceAreaQuery
.getLibraryInstance(fpdModuleId
.getArch());
461 for (int i
= 0; i
< libinstances
.length
; i
++) {
462 SurfaceAreaQuery
.push(GlobalData
.getDoc(libinstances
[i
], fpdModuleId
.getArch()));
463 PackageIdentification
[] libraryPackageDependencies
= SurfaceAreaQuery
.getDependencePkg(fpdModuleId
.getArch());
464 for (int j
= 0; j
< libraryPackageDependencies
.length
; j
++) {
465 GlobalData
.refreshPackageIdentification(libraryPackageDependencies
[j
]);
466 File packageFile
= libraryPackageDependencies
[j
].getSpdFile();
467 includes
.add(packageFile
.getParent() + File
.separatorChar
+ "Include");
468 includes
.add(packageFile
.getParent() + File
.separatorChar
+ "Include" + File
.separatorChar
+ archDir(arch
));
470 SurfaceAreaQuery
.pop();
475 // The package which the module belongs to
477 includes
.add(fpdModuleId
.getModule().getPackage().getPackageDir() + File
.separatorChar
+ "Include");
478 includes
.add(fpdModuleId
.getModule().getPackage().getPackageDir() + File
.separatorChar
+ "Include" + File
.separatorChar
+ archDir(arch
));
481 // Debug files output directory
483 includes
.add("${DEST_DIR_DEBUG}");
486 // sourceFiles[][0] is FileType, [][1] is File name relative to Module_Dir
488 String
[][] sourceFiles
= SurfaceAreaQuery
.getSourceFiles(fpdModuleId
.getArch());
490 FileProcess fileProcess
= new FileProcess();
491 fileProcess
.init(project
, includes
, document
);
493 String moduleDir
= project
.getProperty("MODULE_DIR");
495 // Parse all Unicode files
497 for (int i
= 0; i
< sourceFiles
.length
; i
++) {
499 // Go through all source files. Add MODULE_DIR to preffix
501 File sourceFile
= new File(moduleDir
+ File
.separatorChar
+ sourceFiles
[i
][1]);
502 sourceFiles
[i
][1] = sourceFile
.getPath();
503 String filetype
= sourceFiles
[i
][0];
504 if (filetype
!= null) {
505 fileProcess
.parseFile(sourceFiles
[i
][1], filetype
, root
, true);
507 fileProcess
.parseFile(sourceFiles
[i
][1], root
, true);
512 // If exist Unicode file
514 if (fileProcess
.isUnicodeExist()) {
515 Element ele
= document
.createElement("Build_Unicode_Database");
516 ele
.setAttribute("FILEPATH", ".");
517 ele
.setAttribute("FILENAME", "${BASE_NAME}");
518 String
[] includePaths
= includes
.toArray(new String
[includes
.size()]);
519 Element includesEle
= document
.createElement("EXTRA.INC");
520 for (int i
= 0; i
< includePaths
.length
; i
++) {
521 Element includeEle
= document
.createElement("includepath");
522 includeEle
.setAttribute("path", includePaths
[i
]);
523 includesEle
.appendChild(includeEle
);
525 ele
.appendChild(includesEle
);
526 root
.appendChild(ele
);
530 // Parse AutoGen.c & AutoGen.h
532 if ( ! fpdModuleId
.getModule().getName().equalsIgnoreCase("Shell")) {
533 fileProcess
.parseFile(project
.getProperty("DEST_DIR_DEBUG") + File
.separatorChar
+ "AutoGen.c", root
, false);
537 // Parse all source files but Unicode files
539 for (int i
= 0; i
< sourceFiles
.length
; i
++) {
540 String filetype
= sourceFiles
[i
][0];
541 if (filetype
!= null) {
542 fileProcess
.parseFile(sourceFiles
[i
][1], filetype
, root
, false);
544 fileProcess
.parseFile(sourceFiles
[i
][1], root
, false);
549 // Initialize SOURCE_FILES for dependcy check use
552 for (int i
= 0; i
< sourceFiles
.length
; i
++) {
553 str
+= " " + sourceFiles
[i
][1];
555 project
.setProperty("SOURCE_FILES", str
.replaceAll("(\\\\)", "/"));
559 Generate the section elements for BaseName_build.xml. Library module will
562 @param document current BaseName_build.xml XML document
563 @param root Root element for current
565 private void applySectionsElement(Document document
, Node root
, FfsProcess fp
) {
566 if (fpdModuleId
.getModule().isLibrary()) {
569 if (fp
.initSections(ffsKeyword
, project
, fpdModuleId
)) {
570 String targetFilename
= fpdModuleId
.getModule().getGuid() + "-" + "${BASE_NAME}" + FpdParserTask
.getSuffix(fpdModuleId
.getModule().getModuleType());
571 String
[] list
= fp
.getGenSectionElements(document
, "${BASE_NAME}", fpdModuleId
.getModule().getGuid(), targetFilename
);
573 for (int i
= 0; i
< list
.length
; i
++) {
574 Element ele
= document
.createElement(list
[i
]);
575 ele
.setAttribute("FILEPATH", ".");
576 ele
.setAttribute("FILENAME", "${BASE_NAME}");
577 root
.appendChild(ele
);
583 Generate the output elements for BaseName_build.xml. If module is library,
584 call the <em>LIB</em> command, else call the <em>GenFfs</em> command.
586 @param document current BaseName_build.xml XML document
587 @param root Root element for current
589 private void applyOutputElement(Document document
, Node root
, FfsProcess fp
) {
590 if (fpdModuleId
.getModule().isLibrary()) {
594 Element cc
= document
.createElement("Build_Library");
595 cc
.setAttribute("FILENAME", fpdModuleId
.getModule().getName());
596 root
.appendChild(cc
);
599 // if it is a module but library
602 if (fp
.getFfsNode() != null) {
603 root
.appendChild(fp
.getFfsNode());