- Move global declarations from AutoGen.c to AutoGen.h
[mirror_edk2.git] / Tools / Java / Source / GenBuild / org / tianocore / build / ModuleBuildFileGenerator.java
1 /** @file
2
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
8
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.
11 **/
12 package org.tianocore.build;
13
14 import java.io.File;
15 import java.util.LinkedHashMap;
16 import java.util.Map;
17 import java.io.FileNotFoundException;
18 import java.io.FileOutputStream;
19 import java.io.OutputStreamWriter;
20
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;
33
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;
47
48 public class ModuleBuildFileGenerator {
49
50 ///
51 /// Pass: TARGET, TOOLCHAIN, ARCH
52 /// PACKAGE, PACKAGE_GUID, PACKAGE_VERSION
53 ///
54 String[] inheritProperties = {"ARCH", "MODULE_GUID", "MODULE_VERSION", "PACKAGE_GUID", "PACKAGE_VERSION"};
55
56 ///
57 /// The information at the header of <em>build.xml</em>.
58 ///
59 private String info = "DO NOT EDIT \n"
60 + "This file is auto-generated by the build utility\n"
61 + "\n"
62 + "Abstract:\n"
63 + "Auto-generated ANT build file for build EFI Modules and Platforms\n";
64
65 private FpdModuleIdentification fpdModuleId;
66
67 private Project project;
68
69 private String ffsKeyword;
70
71 private String[] includes;
72
73 private SurfaceAreaQuery saq = null;
74
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;
80 this.saq = saq;
81 }
82
83 /**
84 The whole BaseName_build.xml is composed of seven part.
85 <ul>
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>
91 <li> Clean; </li>
92 <li> Clean all. </li>
93 </ul>
94
95 @throws BuildException
96 Error throws during BaseName_build.xml generating.
97 **/
98 public void genBuildFile(String buildFilename) throws GenBuildException, EdkException {
99 FfsProcess fp = new FfsProcess();
100 DocumentBuilderFactory domfac = DocumentBuilderFactory.newInstance();
101 try {
102 DocumentBuilder dombuilder = domfac.newDocumentBuilder();
103 Document document = dombuilder.newDocument();
104 Comment rootComment = document.createComment(info);
105
106 //
107 // create root element and its attributes
108 //
109 Element root = document.createElement("project");
110 root.setAttribute("name", fpdModuleId.getModule().getName());
111 root.setAttribute("default", "all");
112 root.setAttribute("basedir", ".");
113
114 //
115 // element for External ANT tasks
116 //
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);
130
131 //
132 // Generate the default target,
133 // which depends on init, sections and output target
134 //
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);
140
141 //
142 // compile all source files
143 //
144 root.appendChild(document.createComment("Compile all dependency Library instances."));
145 ele = document.createElement("target");
146 ele.setAttribute("name", "libraries");
147
148 //
149 // Parse all sourfiles but files specified in sections
150 //
151 if (!FrameworkBuildTask.multithread) {
152 applyLibraryInstance(document, ele);
153 }
154 root.appendChild(ele);
155
156 //
157 // compile all source files
158 //
159 root.appendChild(document.createComment("sourcefiles target"));
160 ele = document.createElement("target");
161 ele.setAttribute("name", "sourcefiles");
162
163 //
164 // Parse all sourfiles but files specified in sections
165 //
166 applyCompileElement(document, ele);
167 root.appendChild(ele);
168
169 //
170 // generate the init target
171 // main purpose is create all nessary pathes
172 // generate the sections target
173 //
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);
179
180 //
181 // generate the output target
182 //
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);
188
189
190 //
191 // generate the clean target
192 //
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);
198
199 //
200 // generate the Clean All target
201 //
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);
207
208 //
209 // add the root element to the document
210 //
211 document.appendChild(rootComment);
212 document.appendChild(root);
213 //
214 // Prepare the DOM document for writing
215 //
216 Source source = new DOMSource(document);
217
218 //
219 // Prepare the output file
220 //
221 File file = new File(buildFilename);
222
223 //
224 // generate all directory path
225 //
226 (new File(file.getParent())).mkdirs();
227 FileOutputStream outputStream = new FileOutputStream(file);
228 Result result = new StreamResult(new OutputStreamWriter(outputStream));
229
230 //
231 // Write the DOM document to the file
232 //
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());
240 throw e;
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());
244 throw e;
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());
248 throw e;
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());
252 throw e;
253 }
254 }
255
256 /**
257 Generate the clean elements for BaseName_build.xml.
258
259 @param document current BaseName_build.xml XML document
260 @param root Root element for current
261 **/
262 private void applyCleanElement(Document document, Node root) {
263 //
264 // <delete includeemptydirs="true">
265 // <fileset dir="${DEST_DIR_OUTPUT}" includes="" excludes="" />
266 // </delete>
267 //
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);
276 }
277
278 /**
279 Generate the cleanall elements for BaseName_build.xml.
280
281 @param document current BaseName_build.xml XML document
282 @param root Root element for current
283 **/
284 private void applyDeepcleanElement(Document document, Node root) {
285 //
286 // <delete includeemptydirs="true">
287 // <fileset dir="${DEST_DIR_OUTPUT}" includes="" excludes="" />
288 // </delete>
289 //
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);
298
299 //
300 // <delete includeemptydirs="true">
301 // <fileset dir="${DEST_DIR_DEBUG}" includes="" />
302 // </delete>
303 //
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);
311 }
312
313 /**
314 Generate the dependent library instances elements for BaseName_build.xml.
315
316 @param document current BaseName_build.xml XML document
317 @param root Root element for current
318 **/
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++) {
322 //
323 // Put package file path to module identification
324 //
325 PackageIdentification packageId = libinstances[i].getPackage();
326
327 //
328 // Generate ANT script to build library instances
329 //
330 Element ele = document.createElement("GenBuild");
331 ele.setAttribute("type", "build");
332
333 //
334 // Prepare pass down information
335 //
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] + "}");
339 }
340
341 passDownMap.put("MODULE_GUID", libinstances[i].getGuid());
342 passDownMap.put("MODULE_VERSION", libinstances[i].getVersion());
343
344 passDownMap.put("PACKAGE_GUID", packageId.getGuid());
345 passDownMap.put("PACKAGE_VERSION", packageId.getVersion());
346
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);
352 }
353
354 root.appendChild(ele);
355 }
356 }
357
358 /**
359 Generate the build source files elements for BaseName_build.xml.
360
361 @param document current BaseName_build.xml XML document
362 @param root Root element for current
363 **/
364 private void applyCompileElement(Document document, Node root) {
365 //
366 // sourceFiles[][0] is FileType,
367 // [][1] is File name relative to Module_Dir,
368 // [][2] is ToolChainFamily
369 //
370 String[][] sourceFiles = saq.getSourceFiles(fpdModuleId.getArch());
371
372 FileProcess fileProcess = new FileProcess();
373 fileProcess.init(project, includes, document);
374
375 //
376 // Initialize some properties by user
377 //
378 Element initEle = document.createElement("Build_Init");
379 Element initIncEle = document.createElement("EXTRA.INC");
380 for (int i = 0; i < includes.length; i++) {
381 Element includeEle = document.createElement("includepath");
382 includeEle.setAttribute("path", includes[i]);
383 initIncEle.appendChild(includeEle);
384 }
385 initEle.appendChild(initIncEle);
386 root.appendChild(initEle);
387
388 String moduleDir = project.getProperty("MODULE_DIR");
389 //
390 // Parse all Unicode files
391 //
392 for (int i = 0; i < sourceFiles.length; i++) {
393 //
394 // Go through all source files. Add MODULE_DIR to preffix
395 //
396 File sourceFile = new File(moduleDir + File.separatorChar + sourceFiles[i][1]);
397 sourceFiles[i][1] = sourceFile.getPath();
398 String filetype = sourceFiles[i][0];
399 if (filetype != null) {
400 fileProcess.parseFile(sourceFiles[i][1], filetype, sourceFiles[i][2], root, true);
401 } else {
402 fileProcess.parseFile(sourceFiles[i][1], sourceFiles[i][2], root, true);
403 }
404 }
405
406 //
407 // If exist Unicode file
408 //
409 if (fileProcess.isUnicodeExist()) {
410 Element ele = document.createElement("Build_Unicode_Database");
411 ele.setAttribute("FILEPATH", ".");
412 ele.setAttribute("FILENAME", "${BASE_NAME}");
413 Element includesEle = document.createElement("EXTRA.INC");
414 for (int i = 0; i < includes.length; i++) {
415 Element includeEle = document.createElement("includepath");
416 includeEle.setAttribute("path", includes[i]);
417 includesEle.appendChild(includeEle);
418 }
419 ele.appendChild(includesEle);
420 root.appendChild(ele);
421 }
422
423 //
424 // Parse AutoGen.c & AutoGen.h
425 //
426 if (!fpdModuleId.getModule().isLibrary()
427 && !fpdModuleId.getModule().isBinary()) {
428 fileProcess.parseFile(project.getProperty("DEST_DIR_DEBUG") + File.separatorChar + "AutoGen.c", null, root, false);
429 }
430
431 //
432 // Parse all source files but Unicode files
433 //
434 for (int i = 0; i < sourceFiles.length; i++) {
435 String filetype = sourceFiles[i][0];
436 if (filetype != null) {
437 fileProcess.parseFile(sourceFiles[i][1], filetype, sourceFiles[i][2], root, false);
438 } else {
439 fileProcess.parseFile(sourceFiles[i][1], sourceFiles[i][2], root, false);
440 }
441 }
442
443 //
444 // Initialize SOURCE_FILES for dependcy check use
445 //
446 String str = "";
447 for (int i = 0; i < sourceFiles.length; i++) {
448 str += " " + sourceFiles[i][1];
449 }
450 project.setProperty("SOURCE_FILES", str.replaceAll("(\\\\)", "/"));
451 }
452
453 /**
454 Generate the section elements for BaseName_build.xml. Library module will
455 skip this process.
456
457 @param document current BaseName_build.xml XML document
458 @param root Root element for current
459 **/
460 private void applySectionsElement(Document document, Node root, FfsProcess fp) {
461 if (fpdModuleId.getModule().isLibrary()) {
462 return ;
463 }
464 if (fp.initSections(ffsKeyword, project, fpdModuleId)) {
465 String targetFilename = fpdModuleId.getModule().getGuid() + "-" + "${BASE_NAME}" + FpdParserTask.getSuffix(fpdModuleId.getModule().getModuleType());
466 String[] list = fp.getGenSectionElements(document, "${BASE_NAME}", fpdModuleId.getModule().getGuid(), targetFilename);
467
468 for (int i = 0; i < list.length; i++) {
469 String sectiontype = list[i];
470 if (sectiontype.equalsIgnoreCase("EFI_SECTION_RAW") && project.getProperty("MODULE_TYPE").equalsIgnoreCase("SEC")) {
471 sectiontype += "_SEC";
472 }
473 Element ele = document.createElement(sectiontype);
474 ele.setAttribute("FILEPATH", ".");
475 ele.setAttribute("FILENAME", "${BASE_NAME}");
476 root.appendChild(ele);
477 }
478 }
479 }
480
481 /**
482 Generate the output elements for BaseName_build.xml. If module is library,
483 call the <em>LIB</em> command, else call the <em>GenFfs</em> command.
484
485 @param document current BaseName_build.xml XML document
486 @param root Root element for current
487 **/
488 private void applyOutputElement(Document document, Node root, FfsProcess fp) {
489 if (fpdModuleId.getModule().isLibrary()) {
490 //
491 // call Lib command
492 //
493 Element cc = document.createElement("Build_Library");
494 cc.setAttribute("FILENAME", fpdModuleId.getModule().getName());
495 root.appendChild(cc);
496 }
497 //
498 // if it is a module but library
499 //
500 else {
501 if (fp.getFfsNode() != null) {
502 root.appendChild(fp.getFfsNode());
503 }
504 }
505 }
506
507 }