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
;
20 import javax
.xml
.parsers
.DocumentBuilder
;
21 import javax
.xml
.parsers
.DocumentBuilderFactory
;
22 import javax
.xml
.transform
.OutputKeys
;
23 import javax
.xml
.transform
.Result
;
24 import javax
.xml
.transform
.Source
;
25 import javax
.xml
.transform
.Transformer
;
26 import javax
.xml
.transform
.TransformerFactory
;
27 import javax
.xml
.transform
.dom
.DOMSource
;
28 import javax
.xml
.transform
.stream
.StreamResult
;
30 import org
.apache
.tools
.ant
.BuildException
;
31 import org
.apache
.tools
.ant
.Project
;
32 import org
.tianocore
.build
.fpd
.FpdParserTask
;
33 import org
.tianocore
.build
.global
.GlobalData
;
34 import org
.tianocore
.build
.global
.SurfaceAreaQuery
;
35 import org
.tianocore
.build
.id
.FpdModuleIdentification
;
36 import org
.tianocore
.build
.id
.ModuleIdentification
;
37 import org
.tianocore
.build
.id
.PackageIdentification
;
38 import org
.w3c
.dom
.Comment
;
39 import org
.w3c
.dom
.Document
;
40 import org
.w3c
.dom
.Element
;
41 import org
.w3c
.dom
.Node
;
43 public class ModuleBuildFileGenerator
{
46 /// Pass: TARGET, TOOLCHAIN, ARCH
47 /// PACKAGE, PACKAGE_GUID, PACKAGE_VERSION
49 String
[] inheritProperties
= {"ARCH", "MODULE_GUID", "MODULE_VERSION", "PLATFORM", "PACKAGE_GUID", "PACKAGE_VERSION"};
52 /// The information at the header of <em>build.xml</em>.
54 private String info
= "DO NOT EDIT \n"
55 + "File auto-generated by build utility\n"
58 + "Auto-generated ANT build file for building of EFI Modules/Platforms\n";
60 private FpdModuleIdentification fpdModuleId
;
62 private Project project
;
64 private String ffsKeyword
;
66 public ModuleBuildFileGenerator(Project project
, String ffsKeyword
, FpdModuleIdentification fpdModuleId
) {
67 this.project
= project
;
68 this.fpdModuleId
= fpdModuleId
;
69 this.ffsKeyword
= ffsKeyword
;
73 The whole BaseName_build.xml is composed of seven part.
75 <li> ANT properties; </li>
76 <li> Dependent module (dependent library instances in most case); </li>
77 <li> Source files; </li>
78 <li> Sections if module is not library; </li>
79 <li> Output (different for library module and driver module); </li>
84 @throws BuildException
85 Error throws during BaseName_build.xml generating.
87 public void genBuildFile(String buildFilename
) throws BuildException
{
88 FfsProcess fp
= new FfsProcess();
89 DocumentBuilderFactory domfac
= DocumentBuilderFactory
.newInstance();
91 DocumentBuilder dombuilder
= domfac
.newDocumentBuilder();
92 Document document
= dombuilder
.newDocument();
93 Comment rootComment
= document
.createComment(info
);
96 // create root element and its attributes
98 Element root
= document
.createElement("project");
99 root
.setAttribute("name", fpdModuleId
.getModule().getName());
100 root
.setAttribute("default", "all");
101 root
.setAttribute("basedir", ".");
104 // element for External ANT tasks
106 root
.appendChild(document
.createComment("Apply external ANT tasks"));
107 Element ele
= document
.createElement("taskdef");
108 ele
.setAttribute("resource", "frameworktasks.tasks");
109 root
.appendChild(ele
);
110 ele
= document
.createElement("taskdef");
111 ele
.setAttribute("resource", "cpptasks.tasks");
112 root
.appendChild(ele
);
113 ele
= document
.createElement("typedef");
114 ele
.setAttribute("resource", "cpptasks.types");
115 root
.appendChild(ele
);
116 ele
= document
.createElement("taskdef");
117 ele
.setAttribute("resource", "net/sf/antcontrib/antlib.xml");
118 root
.appendChild(ele
);
121 // Generate the default target,
122 // which depends on init, sections and output target
124 root
.appendChild(document
.createComment("Default target"));
125 ele
= document
.createElement("target");
126 ele
.setAttribute("name", "all");
127 ele
.setAttribute("depends", "libraries, sourcefiles, sections, output");
128 root
.appendChild(ele
);
131 // compile all source files
133 root
.appendChild(document
.createComment("Compile all dependency Library instances."));
134 ele
= document
.createElement("target");
135 ele
.setAttribute("name", "libraries");
138 // Parse all sourfiles but files specified in sections
140 applyLibraryInstance(document
, ele
);
141 root
.appendChild(ele
);
144 // compile all source files
146 root
.appendChild(document
.createComment("sourcefiles target"));
147 ele
= document
.createElement("target");
148 ele
.setAttribute("name", "sourcefiles");
151 // Parse all sourfiles but files specified in sections
153 applyCompileElement(document
, ele
);
154 root
.appendChild(ele
);
157 // generate the init target
158 // main purpose is create all nessary pathes
159 // generate the sections target
161 root
.appendChild(document
.createComment("sections target"));
162 ele
= document
.createElement("target");
163 ele
.setAttribute("name", "sections");
164 applySectionsElement(document
, ele
, fp
);
165 root
.appendChild(ele
);
168 // generate the output target
170 root
.appendChild(document
.createComment("output target"));
171 ele
= document
.createElement("target");
172 ele
.setAttribute("name", "output");
173 applyOutputElement(document
, ele
, fp
);
174 root
.appendChild(ele
);
178 // generate the clean target
180 root
.appendChild(document
.createComment("clean target"));
181 ele
= document
.createElement("target");
182 ele
.setAttribute("name", "clean");
183 applyCleanElement(document
, ele
);
184 root
.appendChild(ele
);
187 // generate the Clean All target
189 root
.appendChild(document
.createComment("Clean All target"));
190 ele
= document
.createElement("target");
191 ele
.setAttribute("name", "cleanall");
192 applyDeepcleanElement(document
, ele
);
193 root
.appendChild(ele
);
196 // add the root element to the document
198 document
.appendChild(rootComment
);
199 document
.appendChild(root
);
201 // Prepare the DOM document for writing
203 Source source
= new DOMSource(document
);
206 // Prepare the output file
208 File file
= new File(buildFilename
);
211 // generate all directory path
213 (new File(file
.getParent())).mkdirs();
214 Result result
= new StreamResult(file
);
217 // Write the DOM document to the file
219 Transformer xformer
= TransformerFactory
.newInstance().newTransformer();
220 xformer
.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
221 xformer
.setOutputProperty(OutputKeys
.INDENT
, "yes");
222 xformer
.transform(source
, result
);
223 } catch (Exception ex
) {
224 ex
.printStackTrace();
225 throw new BuildException("Module [" + fpdModuleId
.getModule().getName() + "] generating build file failed.\n" + ex
.getMessage());
230 Generate the clean elements for BaseName_build.xml.
232 @param document current BaseName_build.xml XML document
233 @param root Root element for current
235 private void applyCleanElement(Document document
, Node root
) {
236 ModuleIdentification
[] libinstances
= SurfaceAreaQuery
.getLibraryInstance(fpdModuleId
.getArch());
237 for (int i
= 0; i
< libinstances
.length
; i
++) {
239 // Put package file path to module identification
241 PackageIdentification packageId
= libinstances
[i
].getPackage();
244 // Generate ANT script to clean
246 Element ele
= document
.createElement("GenBuild");
247 ele
.setAttribute("type", "clean");
250 // Prepare pass down information
252 Map
<String
, String
> passDownMap
= new LinkedHashMap
<String
, String
>();
253 for (int j
= 0; j
< inheritProperties
.length
; j
++){
254 passDownMap
.put(inheritProperties
[j
], "${" + inheritProperties
[j
] + "}");
256 passDownMap
.put("MODULE_GUID", libinstances
[i
].getGuid());
257 passDownMap
.put("MODULE_VERSION", libinstances
[i
].getVersion());
259 passDownMap
.put("PACKAGE_GUID", packageId
.getGuid());
260 passDownMap
.put("PACKAGE_VERSION", packageId
.getVersion());
262 for (int j
= 0; j
< inheritProperties
.length
; j
++){
263 Element property
= document
.createElement("property");
264 property
.setAttribute("name", inheritProperties
[j
]);
265 property
.setAttribute("value", passDownMap
.get(inheritProperties
[j
]));
266 ele
.appendChild(property
);
269 root
.appendChild(ele
);
272 // <delete includeemptydirs="true">
273 // <fileset dir="${DEST_DIR_OUTPUT}" includes="" excludes="" />
276 Element deleteEle
= document
.createElement("delete");
277 deleteEle
.setAttribute("includeemptydirs", "true");
278 Element filesetEle
= document
.createElement("fileset");
279 filesetEle
.setAttribute("dir", "${DEST_DIR_OUTPUT}");
280 filesetEle
.setAttribute("includes", "**/*");
281 filesetEle
.setAttribute("excludes", "*.xml");
282 deleteEle
.appendChild(filesetEle
);
283 root
.appendChild(deleteEle
);
287 Generate the cleanall elements for BaseName_build.xml.
289 @param document current BaseName_build.xml XML document
290 @param root Root element for current
292 private void applyDeepcleanElement(Document document
, Node root
) {
293 ModuleIdentification
[] libinstances
= SurfaceAreaQuery
.getLibraryInstance(fpdModuleId
.getArch());
294 for (int i
= 0; i
< libinstances
.length
; i
++) {
296 // Put package file path to module identification
298 PackageIdentification packageId
= libinstances
[i
].getPackage();
301 // Generate ANT script to clean
303 Element ele
= document
.createElement("GenBuild");
304 ele
.setAttribute("type", "cleanall");
307 // Prepare pass down information
309 Map
<String
, String
> passDownMap
= new LinkedHashMap
<String
, String
>();
310 for (int j
= 0; j
< inheritProperties
.length
; j
++){
311 passDownMap
.put(inheritProperties
[j
], "${" + inheritProperties
[j
] + "}");
314 passDownMap
.put("MODULE_GUID", libinstances
[i
].getGuid());
315 passDownMap
.put("MODULE_VERSION", libinstances
[i
].getVersion());
317 passDownMap
.put("PACKAGE_GUID", packageId
.getGuid());
318 passDownMap
.put("PACKAGE_VERSION", packageId
.getVersion());
320 for (int j
= 0; j
< inheritProperties
.length
; j
++){
321 Element property
= document
.createElement("property");
322 property
.setAttribute("name", inheritProperties
[j
]);
323 property
.setAttribute("value", passDownMap
.get(inheritProperties
[j
]));
324 ele
.appendChild(property
);
327 root
.appendChild(ele
);
330 // <delete includeemptydirs="true">
331 // <fileset dir="${DEST_DIR_OUTPUT}" includes="" excludes="" />
334 Element deleteEle
= document
.createElement("delete");
335 deleteEle
.setAttribute("includeemptydirs", "true");
336 Element filesetEle
= document
.createElement("fileset");
337 filesetEle
.setAttribute("dir", "${DEST_DIR_OUTPUT}");
338 filesetEle
.setAttribute("includes", "**/*");
339 filesetEle
.setAttribute("excludes", "*.xml");
340 deleteEle
.appendChild(filesetEle
);
341 root
.appendChild(deleteEle
);
344 // <delete includeemptydirs="true">
345 // <fileset dir="${DEST_DIR_DEBUG}" includes="" />
348 deleteEle
= document
.createElement("delete");
349 deleteEle
.setAttribute("includeemptydirs", "true");
350 filesetEle
= document
.createElement("fileset");
351 filesetEle
.setAttribute("dir", "${DEST_DIR_DEBUG}");
352 filesetEle
.setAttribute("includes", "**/*");
353 deleteEle
.appendChild(filesetEle
);
354 root
.appendChild(deleteEle
);
358 Generate the dependent library instances elements for BaseName_build.xml.
360 @param document current BaseName_build.xml XML document
361 @param root Root element for current
363 private void applyLibraryInstance(Document document
, Node root
) {
364 ModuleIdentification
[] libinstances
= SurfaceAreaQuery
.getLibraryInstance(fpdModuleId
.getArch());
365 // String propertyLibs = "";
366 for (int i
= 0; i
< libinstances
.length
; i
++) {
368 // Put package file path to module identification
370 PackageIdentification packageId
= libinstances
[i
].getPackage();
373 // Generate ANT script to build library instances
375 Element ele
= document
.createElement("GenBuild");
376 ele
.setAttribute("type", "build");
377 // ele.setAttribute("inheritAll", "false");
380 // Prepare pass down information
382 Map
<String
, String
> passDownMap
= new LinkedHashMap
<String
, String
>();
383 for (int j
= 0; j
< inheritProperties
.length
; j
++){
384 passDownMap
.put(inheritProperties
[j
], "${" + inheritProperties
[j
] + "}");
387 passDownMap
.put("MODULE_GUID", libinstances
[i
].getGuid());
388 passDownMap
.put("MODULE_VERSION", libinstances
[i
].getVersion());
390 passDownMap
.put("PACKAGE_GUID", packageId
.getGuid());
391 passDownMap
.put("PACKAGE_VERSION", packageId
.getVersion());
393 for (int j
= 0; j
< inheritProperties
.length
; j
++){
394 Element property
= document
.createElement("property");
395 property
.setAttribute("name", inheritProperties
[j
]);
396 property
.setAttribute("value", passDownMap
.get(inheritProperties
[j
]));
397 ele
.appendChild(property
);
400 root
.appendChild(ele
);
401 // propertyLibs += " " + project.getProperty("BIN_DIR") + File.separatorChar + libinstances[i].getName() + ".lib";
403 // project.setProperty("LIBS", propertyLibs.replaceAll("(\\\\)", "/"));
407 Generate the build source files elements for BaseName_build.xml.
409 @param document current BaseName_build.xml XML document
410 @param root Root element for current
412 private void applyCompileElement(Document document
, Node root
) {
414 // Prepare the includes: PackageDependencies and Output debug direactory
416 Set
<String
> includes
= new LinkedHashSet
<String
>();
421 includes
.add("${WORKSPACE_DIR}");
426 includes
.add("${MODULE_DIR}");
427 includes
.add("${MODULE_DIR}" + File
.separatorChar
+ "${ARCH}");
430 // Packages in PackageDenpendencies
432 PackageIdentification
[] packageDependencies
= SurfaceAreaQuery
.getDependencePkg(fpdModuleId
.getArch());
433 for (int i
= 0; i
< packageDependencies
.length
; i
++) {
434 GlobalData
.refreshPackageIdentification(packageDependencies
[i
]);
435 File packageFile
= packageDependencies
[i
].getSpdFile();
436 includes
.add(packageFile
.getParent() + File
.separatorChar
+ "Include");
437 includes
.add(packageFile
.getParent() + File
.separatorChar
+ "Include" + File
.separatorChar
+ "${ARCH}");
441 // All Dependency Library Instance's PackageDependencies
443 ModuleIdentification
[] libinstances
= SurfaceAreaQuery
.getLibraryInstance(fpdModuleId
.getArch());
444 for (int i
= 0; i
< libinstances
.length
; i
++) {
445 SurfaceAreaQuery
.push(GlobalData
.getDoc(libinstances
[i
], fpdModuleId
.getArch()));
446 PackageIdentification
[] libraryPackageDependencies
= SurfaceAreaQuery
.getDependencePkg(fpdModuleId
.getArch());
447 for (int j
= 0; j
< libraryPackageDependencies
.length
; j
++) {
448 GlobalData
.refreshPackageIdentification(libraryPackageDependencies
[j
]);
449 File packageFile
= libraryPackageDependencies
[j
].getSpdFile();
450 includes
.add(packageFile
.getParent() + File
.separatorChar
+ "Include");
451 includes
.add(packageFile
.getParent() + File
.separatorChar
+ "Include" + File
.separatorChar
+ "${ARCH}");
453 SurfaceAreaQuery
.pop();
458 // The package which the module belongs to
460 includes
.add(fpdModuleId
.getModule().getPackage().getPackageDir() + File
.separatorChar
+ "Include");
461 includes
.add(fpdModuleId
.getModule().getPackage().getPackageDir() + File
.separatorChar
+ "Include" + File
.separatorChar
+ "${ARCH}");
464 // Debug files output directory
466 includes
.add("${DEST_DIR_DEBUG}");
469 // sourceFiles[][0] is FileType, [][1] is File name relative to Module_Dir
471 String
[][] sourceFiles
= SurfaceAreaQuery
.getSourceFiles(fpdModuleId
.getArch());
473 FileProcess fileProcess
= new FileProcess();
474 fileProcess
.init(project
, includes
, document
);
476 String moduleDir
= project
.getProperty("MODULE_DIR");
478 // Parse all Unicode files
480 for (int i
= 0; i
< sourceFiles
.length
; i
++) {
482 // Go through all source files. Add MODULE_DIR to preffix
484 File sourceFile
= new File(moduleDir
+ File
.separatorChar
+ sourceFiles
[i
][1]);
485 sourceFiles
[i
][1] = sourceFile
.getPath();
486 String filetype
= sourceFiles
[i
][0];
487 if (filetype
!= null) {
488 fileProcess
.parseFile(sourceFiles
[i
][1], filetype
, root
, true);
490 fileProcess
.parseFile(sourceFiles
[i
][1], root
, true);
495 // If exist Unicode file
497 if (fileProcess
.isUnicodeExist()) {
498 Element ele
= document
.createElement("Build_Unicode_Database");
499 ele
.setAttribute("FILEPATH", ".");
500 ele
.setAttribute("FILENAME", "${BASE_NAME}");
501 String
[] includePaths
= includes
.toArray(new String
[includes
.size()]);
502 Element includesEle
= document
.createElement("EXTRA.INC");
503 for (int i
= 0; i
< includePaths
.length
; i
++) {
504 Element includeEle
= document
.createElement("includepath");
505 includeEle
.setAttribute("path", includePaths
[i
]);
506 includesEle
.appendChild(includeEle
);
508 ele
.appendChild(includesEle
);
509 root
.appendChild(ele
);
513 // Parse AutoGen.c & AutoGen.h
515 if ( ! fpdModuleId
.getModule().getName().equalsIgnoreCase("Shell")) {
516 fileProcess
.parseFile(project
.getProperty("DEST_DIR_DEBUG") + File
.separatorChar
+ "AutoGen.c", root
, false);
520 // Parse all source files but Unicode files
522 for (int i
= 0; i
< sourceFiles
.length
; i
++) {
523 String filetype
= sourceFiles
[i
][0];
524 if (filetype
!= null) {
525 fileProcess
.parseFile(sourceFiles
[i
][1], filetype
, root
, false);
527 fileProcess
.parseFile(sourceFiles
[i
][1], root
, false);
532 // Initialize SOURCE_FILES for dependcy check use
535 for (int i
= 0; i
< sourceFiles
.length
; i
++) {
536 str
+= " " + sourceFiles
[i
][1];
538 project
.setProperty("SOURCE_FILES", str
.replaceAll("(\\\\)", "/"));
542 Generate the section elements for BaseName_build.xml. Library module will
545 @param document current BaseName_build.xml XML document
546 @param root Root element for current
548 private void applySectionsElement(Document document
, Node root
, FfsProcess fp
) {
549 if (fpdModuleId
.getModule().isLibrary()) {
552 if (fp
.initSections(ffsKeyword
, project
, fpdModuleId
)) {
553 String targetFilename
= fpdModuleId
.getModule().getGuid() + "-" + fpdModuleId
.getModule().getName() + FpdParserTask
.getSuffix(fpdModuleId
.getModule().getModuleType());
554 String
[] list
= fp
.getGenSectionElements(document
, "${BASE_NAME}", fpdModuleId
.getModule().getGuid(), targetFilename
);
556 for (int i
= 0; i
< list
.length
; i
++) {
557 Element ele
= document
.createElement(list
[i
]);
558 ele
.setAttribute("FILEPATH", ".");
559 ele
.setAttribute("FILENAME", "${BASE_NAME}");
560 root
.appendChild(ele
);
566 Generate the output elements for BaseName_build.xml. If module is library,
567 call the <em>LIB</em> command, else call the <em>GenFfs</em> command.
569 @param document current BaseName_build.xml XML document
570 @param root Root element for current
572 private void applyOutputElement(Document document
, Node root
, FfsProcess fp
) {
573 if (fpdModuleId
.getModule().isLibrary()) {
577 Element cc
= document
.createElement("Build_Library");
578 cc
.setAttribute("FILENAME", fpdModuleId
.getModule().getName());
579 root
.appendChild(cc
);
582 // if it is a module but library
585 if (fp
.getFfsNode() != null) {
586 root
.appendChild(fp
.getFfsNode());