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
;
17 import java
.io
.FileNotFoundException
;
18 import java
.io
.FileOutputStream
;
19 import java
.io
.OutputStreamWriter
;
21 import javax
.xml
.parsers
.DocumentBuilder
;
22 import javax
.xml
.parsers
.DocumentBuilderFactory
;
23 import javax
.xml
.parsers
.ParserConfigurationException
;
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
.TransformerConfigurationException
;
29 import javax
.xml
.transform
.TransformerException
;
30 import javax
.xml
.transform
.TransformerFactory
;
31 import javax
.xml
.transform
.dom
.DOMSource
;
32 import javax
.xml
.transform
.stream
.StreamResult
;
34 import org
.apache
.tools
.ant
.BuildException
;
35 import org
.apache
.tools
.ant
.Project
;
36 import org
.tianocore
.build
.exception
.GenBuildException
;
37 import org
.tianocore
.build
.fpd
.FpdParserTask
;
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
.PackageIdentification
;
42 import org
.tianocore
.common
.exception
.EdkException
;
43 import org
.w3c
.dom
.Comment
;
44 import org
.w3c
.dom
.Document
;
45 import org
.w3c
.dom
.Element
;
46 import org
.w3c
.dom
.Node
;
48 public class ModuleBuildFileGenerator
{
51 /// Pass: TARGET, TOOLCHAIN, ARCH
52 /// PACKAGE, PACKAGE_GUID, PACKAGE_VERSION
54 String
[] inheritProperties
= {"ARCH", "MODULE_GUID", "MODULE_VERSION", "PACKAGE_GUID", "PACKAGE_VERSION"};
57 /// The information at the header of <em>build.xml</em>.
59 private String info
= "DO NOT EDIT \n"
60 + "This file is auto-generated by the build utility\n"
63 + "Auto-generated ANT build file for build EFI Modules and Platforms\n";
65 private FpdModuleIdentification fpdModuleId
;
67 private Project project
;
69 private String ffsKeyword
;
71 private String
[] includes
;
73 private SurfaceAreaQuery saq
= null;
75 public ModuleBuildFileGenerator(Project project
, String ffsKeyword
, FpdModuleIdentification fpdModuleId
, String
[] includes
, SurfaceAreaQuery saq
) {
76 this.project
= project
;
77 this.fpdModuleId
= fpdModuleId
;
78 this.ffsKeyword
= ffsKeyword
;
79 this.includes
= includes
;
84 The whole BaseName_build.xml is composed of seven part.
86 <li> ANT properties; </li>
87 <li> Dependent module (dependent library instances in most case); </li>
88 <li> Source files; </li>
89 <li> Sections if module is not library; </li>
90 <li> Output (different for library module and driver module); </li>
95 @throws BuildException
96 Error throws during BaseName_build.xml generating.
98 public void genBuildFile(String buildFilename
) throws GenBuildException
, EdkException
{
99 FfsProcess fp
= new FfsProcess();
100 DocumentBuilderFactory domfac
= DocumentBuilderFactory
.newInstance();
102 DocumentBuilder dombuilder
= domfac
.newDocumentBuilder();
103 Document document
= dombuilder
.newDocument();
104 Comment rootComment
= document
.createComment(info
);
107 // create root element and its attributes
109 Element root
= document
.createElement("project");
110 root
.setAttribute("name", fpdModuleId
.getModule().getName());
111 root
.setAttribute("default", "all");
112 root
.setAttribute("basedir", ".");
115 // element for External ANT tasks
117 root
.appendChild(document
.createComment("Apply external ANT tasks"));
118 Element ele
= document
.createElement("taskdef");
119 ele
.setAttribute("resource", "frameworktasks.tasks");
120 root
.appendChild(ele
);
121 ele
= document
.createElement("taskdef");
122 ele
.setAttribute("resource", "cpptasks.tasks");
123 root
.appendChild(ele
);
124 ele
= document
.createElement("typedef");
125 ele
.setAttribute("resource", "cpptasks.types");
126 root
.appendChild(ele
);
127 ele
= document
.createElement("taskdef");
128 ele
.setAttribute("resource", "net/sf/antcontrib/antlib.xml");
129 root
.appendChild(ele
);
132 // Generate the default target,
133 // which depends on init, sections and output target
135 root
.appendChild(document
.createComment("Default target"));
136 ele
= document
.createElement("target");
137 ele
.setAttribute("name", "all");
138 ele
.setAttribute("depends", "libraries, sourcefiles, sections, output");
139 root
.appendChild(ele
);
142 // compile all source files
144 root
.appendChild(document
.createComment("Compile all dependency Library instances."));
145 ele
= document
.createElement("target");
146 ele
.setAttribute("name", "libraries");
149 // Parse all sourfiles but files specified in sections
151 if (!FrameworkBuildTask
.multithread
) {
152 applyLibraryInstance(document
, ele
);
154 root
.appendChild(ele
);
157 // compile all source files
159 root
.appendChild(document
.createComment("sourcefiles target"));
160 ele
= document
.createElement("target");
161 ele
.setAttribute("name", "sourcefiles");
164 // Parse all sourfiles but files specified in sections
166 applyCompileElement(document
, ele
);
167 root
.appendChild(ele
);
170 // generate the init target
171 // main purpose is create all nessary pathes
172 // generate the sections target
174 root
.appendChild(document
.createComment("sections target"));
175 ele
= document
.createElement("target");
176 ele
.setAttribute("name", "sections");
177 applySectionsElement(document
, ele
, fp
);
178 root
.appendChild(ele
);
181 // generate the output target
183 root
.appendChild(document
.createComment("output target"));
184 ele
= document
.createElement("target");
185 ele
.setAttribute("name", "output");
186 applyOutputElement(document
, ele
, fp
);
187 root
.appendChild(ele
);
191 // generate the clean target
193 root
.appendChild(document
.createComment("clean target"));
194 ele
= document
.createElement("target");
195 ele
.setAttribute("name", "clean");
196 applyCleanElement(document
, ele
);
197 root
.appendChild(ele
);
200 // generate the Clean All target
202 root
.appendChild(document
.createComment("Clean All target"));
203 ele
= document
.createElement("target");
204 ele
.setAttribute("name", "cleanall");
205 applyDeepcleanElement(document
, ele
);
206 root
.appendChild(ele
);
209 // add the root element to the document
211 document
.appendChild(rootComment
);
212 document
.appendChild(root
);
214 // Prepare the DOM document for writing
216 Source source
= new DOMSource(document
);
219 // Prepare the output file
221 File file
= new File(buildFilename
);
224 // generate all directory path
226 (new File(file
.getParent())).mkdirs();
227 FileOutputStream outputStream
= new FileOutputStream(file
);
228 Result result
= new StreamResult(new OutputStreamWriter(outputStream
));
231 // Write the DOM document to the file
233 Transformer xformer
= TransformerFactory
.newInstance().newTransformer();
234 xformer
.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
235 xformer
.setOutputProperty(OutputKeys
.INDENT
, "yes");
236 xformer
.transform(source
, result
);
237 } catch (ParserConfigurationException ex
) {
238 GenBuildException e
= new GenBuildException("Generating the module [" + fpdModuleId
.getModule().getName() + "] build.xml file failed!.\n" + ex
.getMessage());
239 e
.setStackTrace(ex
.getStackTrace());
241 } catch (FileNotFoundException ex
) {
242 GenBuildException e
= new GenBuildException("Generating the module [" + fpdModuleId
.getModule().getName() + "] build.xml file failed!.\n" + ex
.getMessage());
243 e
.setStackTrace(ex
.getStackTrace());
245 } catch (TransformerConfigurationException ex
) {
246 GenBuildException e
= new GenBuildException("Generating the module [" + fpdModuleId
.getModule().getName() + "] build.xml file failed!.\n" + ex
.getMessage());
247 e
.setStackTrace(ex
.getStackTrace());
249 } catch (TransformerException ex
) {
250 GenBuildException e
= new GenBuildException("Generating the module [" + fpdModuleId
.getModule().getName() + "] build.xml file failed!.\n" + ex
.getMessage());
251 e
.setStackTrace(ex
.getStackTrace());
257 Generate the clean elements for BaseName_build.xml.
259 @param document current BaseName_build.xml XML document
260 @param root Root element for current
262 private void applyCleanElement(Document document
, Node root
) {
264 // <delete includeemptydirs="true">
265 // <fileset dir="${DEST_DIR_OUTPUT}" includes="" excludes="" />
268 Element deleteEle
= document
.createElement("delete");
269 deleteEle
.setAttribute("includeemptydirs", "true");
270 Element filesetEle
= document
.createElement("fileset");
271 filesetEle
.setAttribute("dir", "${DEST_DIR_OUTPUT}");
272 filesetEle
.setAttribute("includes", "**/*");
273 filesetEle
.setAttribute("excludes", "*.xml");
274 deleteEle
.appendChild(filesetEle
);
275 root
.appendChild(deleteEle
);
279 Generate the cleanall elements for BaseName_build.xml.
281 @param document current BaseName_build.xml XML document
282 @param root Root element for current
284 private void applyDeepcleanElement(Document document
, Node root
) {
286 // <delete includeemptydirs="true">
287 // <fileset dir="${DEST_DIR_OUTPUT}" includes="" excludes="" />
290 Element deleteEle
= document
.createElement("delete");
291 deleteEle
.setAttribute("includeemptydirs", "true");
292 Element filesetEle
= document
.createElement("fileset");
293 filesetEle
.setAttribute("dir", "${DEST_DIR_OUTPUT}");
294 filesetEle
.setAttribute("includes", "**/*");
295 filesetEle
.setAttribute("excludes", "*.xml");
296 deleteEle
.appendChild(filesetEle
);
297 root
.appendChild(deleteEle
);
300 // <delete includeemptydirs="true">
301 // <fileset dir="${DEST_DIR_DEBUG}" includes="" />
304 deleteEle
= document
.createElement("delete");
305 deleteEle
.setAttribute("includeemptydirs", "true");
306 filesetEle
= document
.createElement("fileset");
307 filesetEle
.setAttribute("dir", "${DEST_DIR_DEBUG}");
308 filesetEle
.setAttribute("includes", "**/*");
309 deleteEle
.appendChild(filesetEle
);
310 root
.appendChild(deleteEle
);
314 Generate the dependent library instances elements for BaseName_build.xml.
316 @param document current BaseName_build.xml XML document
317 @param root Root element for current
319 private void applyLibraryInstance(Document document
, Node root
) throws EdkException
{
320 ModuleIdentification
[] libinstances
= saq
.getLibraryInstance(fpdModuleId
.getArch());
321 for (int i
= 0; i
< libinstances
.length
; i
++) {
323 // Put package file path to module identification
325 PackageIdentification packageId
= libinstances
[i
].getPackage();
328 // Generate ANT script to build library instances
330 Element ele
= document
.createElement("GenBuild");
331 ele
.setAttribute("type", "build");
334 // Prepare pass down information
336 Map
<String
, String
> passDownMap
= new LinkedHashMap
<String
, String
>();
337 for (int j
= 0; j
< inheritProperties
.length
; j
++){
338 passDownMap
.put(inheritProperties
[j
], "${" + inheritProperties
[j
] + "}");
341 passDownMap
.put("MODULE_GUID", libinstances
[i
].getGuid());
342 passDownMap
.put("MODULE_VERSION", libinstances
[i
].getVersion());
344 passDownMap
.put("PACKAGE_GUID", packageId
.getGuid());
345 passDownMap
.put("PACKAGE_VERSION", packageId
.getVersion());
347 for (int j
= 0; j
< inheritProperties
.length
; j
++){
348 Element property
= document
.createElement("property");
349 property
.setAttribute("name", inheritProperties
[j
]);
350 property
.setAttribute("value", passDownMap
.get(inheritProperties
[j
]));
351 ele
.appendChild(property
);
354 root
.appendChild(ele
);
359 Generate the build source files elements for BaseName_build.xml.
361 @param document current BaseName_build.xml XML document
362 @param root Root element for current
364 private void applyCompileElement(Document document
, Node root
) {
366 // sourceFiles[][0] is FileType, [][1] is File name relative to Module_Dir
368 String
[][] sourceFiles
= saq
.getSourceFiles(fpdModuleId
.getArch());
370 FileProcess fileProcess
= new FileProcess();
371 fileProcess
.init(project
, includes
, document
);
374 // Initialize some properties by user
376 Element initEle
= document
.createElement("Build_Init");
377 root
.appendChild(initEle
);
379 String moduleDir
= project
.getProperty("MODULE_DIR");
381 // Parse all Unicode files
383 for (int i
= 0; i
< sourceFiles
.length
; i
++) {
385 // Go through all source files. Add MODULE_DIR to preffix
387 File sourceFile
= new File(moduleDir
+ File
.separatorChar
+ sourceFiles
[i
][1]);
388 sourceFiles
[i
][1] = sourceFile
.getPath();
389 String filetype
= sourceFiles
[i
][0];
390 if (filetype
!= null) {
391 fileProcess
.parseFile(sourceFiles
[i
][1], filetype
, root
, true);
393 fileProcess
.parseFile(sourceFiles
[i
][1], root
, true);
398 // If exist Unicode file
400 if (fileProcess
.isUnicodeExist()) {
401 Element ele
= document
.createElement("Build_Unicode_Database");
402 ele
.setAttribute("FILEPATH", ".");
403 ele
.setAttribute("FILENAME", "${BASE_NAME}");
404 Element includesEle
= document
.createElement("EXTRA.INC");
405 for (int i
= 0; i
< includes
.length
; i
++) {
406 Element includeEle
= document
.createElement("includepath");
407 includeEle
.setAttribute("path", includes
[i
]);
408 includesEle
.appendChild(includeEle
);
410 ele
.appendChild(includesEle
);
411 root
.appendChild(ele
);
415 // Parse AutoGen.c & AutoGen.h
417 if ( ! fpdModuleId
.getModule().getName().equalsIgnoreCase("Shell")) {
418 fileProcess
.parseFile(project
.getProperty("DEST_DIR_DEBUG") + File
.separatorChar
+ "AutoGen.c", root
, false);
422 // Parse all source files but Unicode files
424 for (int i
= 0; i
< sourceFiles
.length
; i
++) {
425 String filetype
= sourceFiles
[i
][0];
426 if (filetype
!= null) {
427 fileProcess
.parseFile(sourceFiles
[i
][1], filetype
, root
, false);
429 fileProcess
.parseFile(sourceFiles
[i
][1], root
, false);
434 // Initialize SOURCE_FILES for dependcy check use
437 for (int i
= 0; i
< sourceFiles
.length
; i
++) {
438 str
+= " " + sourceFiles
[i
][1];
440 project
.setProperty("SOURCE_FILES", str
.replaceAll("(\\\\)", "/"));
444 Generate the section elements for BaseName_build.xml. Library module will
447 @param document current BaseName_build.xml XML document
448 @param root Root element for current
450 private void applySectionsElement(Document document
, Node root
, FfsProcess fp
) {
451 if (fpdModuleId
.getModule().isLibrary()) {
454 if (fp
.initSections(ffsKeyword
, project
, fpdModuleId
)) {
455 String targetFilename
= fpdModuleId
.getModule().getGuid() + "-" + "${BASE_NAME}" + FpdParserTask
.getSuffix(fpdModuleId
.getModule().getModuleType());
456 String
[] list
= fp
.getGenSectionElements(document
, "${BASE_NAME}", fpdModuleId
.getModule().getGuid(), targetFilename
);
458 for (int i
= 0; i
< list
.length
; i
++) {
459 Element ele
= document
.createElement(list
[i
]);
460 ele
.setAttribute("FILEPATH", ".");
461 ele
.setAttribute("FILENAME", "${BASE_NAME}");
462 root
.appendChild(ele
);
468 Generate the output elements for BaseName_build.xml. If module is library,
469 call the <em>LIB</em> command, else call the <em>GenFfs</em> command.
471 @param document current BaseName_build.xml XML document
472 @param root Root element for current
474 private void applyOutputElement(Document document
, Node root
, FfsProcess fp
) {
475 if (fpdModuleId
.getModule().isLibrary()) {
479 Element cc
= document
.createElement("Build_Library");
480 cc
.setAttribute("FILENAME", fpdModuleId
.getModule().getName());
481 root
.appendChild(cc
);
484 // if it is a module but library
487 if (fp
.getFfsNode() != null) {
488 root
.appendChild(fp
.getFfsNode());