a2f22c1b0b1db3ce4c33da126dc8c82468f1e265
[mirror_edk2.git] / Tools / Java / Source / GenBuild / org / tianocore / build / fpd / FpdParserForThread.java
1 /** @file
2 This file is ANT task FpdParserTask.
3
4 Copyright (c) 2006, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 **/
13 package org.tianocore.build.fpd;
14
15 import java.io.File;
16 import java.util.ArrayList;
17 import java.util.Iterator;
18 import java.util.LinkedHashMap;
19 import java.util.LinkedHashSet;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23
24 import org.apache.tools.ant.BuildException;
25 import org.apache.tools.ant.taskdefs.Ant;
26 import org.apache.xmlbeans.XmlObject;
27
28 import org.tianocore.build.global.GenBuildLogger;
29 import org.tianocore.build.global.GlobalData;
30 import org.tianocore.build.global.OutputManager;
31 import org.tianocore.build.id.FpdModuleIdentification;
32 import org.tianocore.build.id.ModuleIdentification;
33 import org.tianocore.build.FrameworkBuildTask;
34 import org.tianocore.build.GenBuildThread;
35 import org.tianocore.common.exception.EdkException;
36 import org.tianocore.common.logger.EdkLog;
37
38 /**
39
40 @since GenBuild 1.0
41 **/
42 public class FpdParserForThread extends FpdParserTask {
43
44 public static Map<FpdModuleIdentification, GenBuildThread> allThreads = new LinkedHashMap<FpdModuleIdentification, GenBuildThread>();
45
46 List<String> queueList = new ArrayList<String>();
47
48 public final static Object deamonSemaphore = new Object();
49
50 private final static Object countSemaphore = new Object();
51
52 public static int STATUS_DEPENDENCY_NOT_READY = 1;
53
54 public static int STATUS_DEPENDENCY_READY = 2;
55
56 public static int STATUS_START_RUN = 3;
57
58 public static int STATUS_END_RUN = 4;
59
60 private int currentQueueCode = 0;
61
62 public static int currentRunNumber = 0;
63
64 public static int totalNumber = 0;
65
66 public static int remainNumber = 0;
67
68 public static ThreadGroup tg = new ThreadGroup("Framework");
69
70 public static FpdModuleIdentification errorModule = null;
71
72 /**
73 Public construct method. It is necessary for ANT task.
74 **/
75 public FpdParserForThread() {
76 }
77
78 /**
79
80
81 **/
82 public void execute() throws BuildException {
83
84 this.setTaskName(".........");
85 //
86 // Parse FPD file
87 //
88 parseFpdFile();
89
90 //
91 // Prepare BUILD_DIR
92 //
93 isUnified = OutputManager.getInstance().prepareBuildDir(getProject());
94 String buildDir = getProject().getProperty("BUILD_DIR");
95
96 //
97 // For every Target and ToolChain
98 //
99 String[] targetList = GlobalData.getToolChainInfo().getTargets();
100 for (int i = 0; i < targetList.length; i++) {
101 String[] toolchainList = GlobalData.getToolChainInfo().getTagnames();
102 for(int j = 0; j < toolchainList.length; j++) {
103 //
104 // Prepare FV_DIR
105 //
106 String ffsCommonDir = buildDir + File.separatorChar
107 + targetList[i] + "_"
108 + toolchainList[j];
109 File fvDir = new File(ffsCommonDir + File.separatorChar + "FV");
110 fvDir.mkdirs();
111 getProject().setProperty("FV_DIR", fvDir.getPath().replaceAll("(\\\\)", "/"));
112
113 //
114 // Gen Fv.inf files
115 //
116 genFvInfFiles(ffsCommonDir);
117 }
118 }
119
120 //
121 // Gen build.xml
122 //
123 String platformBuildFile = buildDir + File.separatorChar + platformId.getName() + "_build.xml";
124 PlatformBuildFileGenerator fileGenerator = new PlatformBuildFileGenerator(getProject(), outfiles, fvs, isUnified, saq, platformBuildFile);
125 fileGenerator.genBuildFile();
126
127 //
128 // Prepare Queue
129 //
130 queueList.add("libqueue");
131
132 String[] validFv = saq.getFpdValidImageNames();
133
134 for (int i = 0; i < validFv.length; i++) {
135 queueList.add(validFv[i]);
136 }
137
138 Iterator<String> fvsNameIter = fvs.keySet().iterator();
139
140 while (fvsNameIter.hasNext()) {
141 String fvName = fvsNameIter.next();
142 if (!isContain(validFv, fvName)) {
143 queueList.add(fvName);
144 }
145 }
146
147 //
148 // Ant call ${PLATFORM}_build.xml
149 //
150 Ant ant = new Ant();
151 ant.setProject(getProject());
152 ant.setAntfile(platformBuildFile);
153 ant.setTarget("prebuild");
154 ant.setInheritAll(true);
155 ant.init();
156 ant.execute();
157
158 remainNumber = totalNumber = allThreads.size();
159
160 EdkLog.log(this, EdkLog.EDK_ALWAYS, "Total thread number is " + totalNumber);
161 GenBuildLogger.setCacheEnable(true);
162 //
163 // Waiting for all thread over, or time out
164 //
165 synchronized (deamonSemaphore) {
166
167 while (true) {
168 //
169 // If all modules are already built
170 //
171 if (currentQueueCode >= queueList.size()) {
172 break ;
173 }
174
175 int percentage = (totalNumber - remainNumber) * 100 / totalNumber;
176 updateTaskName(percentage);
177 EdkLog.log(this, EdkLog.EDK_ALWAYS, percentage + "% finished. Has built " + (totalNumber - remainNumber) + " modules of " + totalNumber + " total. ");
178
179 Set<FpdModuleIdentification> currentQueueModules = fvs.get(queueList.get(currentQueueCode));
180
181 if (currentQueueModules == null) {
182 ++currentQueueCode;
183 continue ;
184 }
185 Iterator<FpdModuleIdentification> currentIter = currentQueueModules.iterator();
186
187 GenBuildThread a = null;
188
189 boolean existNoneReady = false;
190
191 while (currentIter.hasNext()) {
192 GenBuildThread item = allThreads.get(currentIter.next());
193 if (item.getStatus() == STATUS_DEPENDENCY_NOT_READY) {
194 existNoneReady = true;
195 } else if (item.getStatus() == STATUS_DEPENDENCY_READY) {
196 a = item;
197 addCount();
198 a.start();
199 if (currentRunNumber == FrameworkBuildTask.MAX_CONCURRENT_THREAD_NUMBER) {
200 break ;
201 }
202 }
203 }
204
205 if (a != null) {
206 //
207 // Exist ready thread
208 //
209 EdkLog.log(this, EdkLog.EDK_DEBUG, "Exist ready thread");
210
211 } else if (existNoneReady && currentRunNumber == 0) {
212 //
213 // No active thread, but still have dependency not read thread
214 //
215 throw new BuildException("Existing some modules can't resolve depedencies. ");
216 } else if (!existNoneReady && currentRunNumber == 0) {
217 //
218 // Current queue build finish, move to next
219 //
220 EdkLog.log(this, EdkLog.EDK_DEBUG, "Current queue build finish, move to next");
221 ++currentQueueCode;
222 continue ;
223 } else {
224 //
225 // active thread exist, but no ready thread
226 //
227 EdkLog.log(this, EdkLog.EDK_DEBUG, "Active thread exist, but no ready thread. Current running number is " + currentRunNumber);
228 }
229
230 try {
231 deamonSemaphore.wait();
232
233 //
234 // if find error. Waiting running threads to finish
235 //
236 if (errorModule != null) {
237 while (currentRunNumber > 0) {
238 deamonSemaphore.wait();
239 }
240
241 GenBuildLogger.setCacheEnable(false);
242
243 GenBuildLogger.flushErrorModuleLog(errorModule);
244
245 EdkLog.flushLogToFile(new File(buildDir + File.separatorChar + "build.log"));
246
247 throw new BuildException(errorModule + " build error. ");
248 }
249 } catch (InterruptedException ex) {
250 BuildException e = new BuildException("Thread wait Error. \n" + ex.getMessage());
251 e.setStackTrace(ex.getStackTrace());
252 throw e;
253 }
254 }
255 }
256
257 GenBuildLogger.setCacheEnable(false);
258 //
259 // call fvs, postbuild
260 //
261 ant = new Ant();
262 ant.setProject(getProject());
263 ant.setAntfile(platformBuildFile);
264 ant.setTarget("fvs");
265 ant.setInheritAll(true);
266 ant.init();
267 ant.execute();
268
269 ant = new Ant();
270 ant.setProject(getProject());
271 ant.setAntfile(platformBuildFile);
272 ant.setTarget("postbuild");
273 ant.setInheritAll(true);
274 ant.init();
275 ant.execute();
276
277 EdkLog.flushLogToFile(new File(buildDir + File.separatorChar + "build.log"));
278 }
279
280
281 /**
282 Parse all modules listed in FPD file.
283 **/
284 void parseModuleSAFiles() throws EdkException{
285
286 Map<FpdModuleIdentification, Map<String, XmlObject>> moduleSAs = saq.getFpdModules();
287
288 //
289 // For every Module lists in FPD file.
290 //
291 Set<FpdModuleIdentification> keys = moduleSAs.keySet();
292 Iterator<FpdModuleIdentification> iter = keys.iterator();
293 while (iter.hasNext()) {
294 FpdModuleIdentification fpdModuleId = iter.next();
295
296 //
297 // Generate GenBuildThread
298 //
299 GenBuildThread genBuildThread = new GenBuildThread(fpdModuleId.getModule(), fpdModuleId.getArch());
300 genBuildThread.setParentModuleId(null);
301 genBuildThread.setProject(getProject());
302
303 Set<FpdModuleIdentification> dependencies = new LinkedHashSet<FpdModuleIdentification>();
304
305 GlobalData.registerFpdModuleSA(fpdModuleId, moduleSAs.get(fpdModuleId));
306
307 //
308 // Add all dependent Library Instance
309 //
310 saq.push(GlobalData.getDoc(fpdModuleId));
311
312 ModuleIdentification[] libinstances = saq.getLibraryInstance(fpdModuleId.getArch());
313 saq.pop();
314
315 for (int i = 0; i < libinstances.length; i++) {
316 FpdModuleIdentification libFpdModuleId = new FpdModuleIdentification(libinstances[i], fpdModuleId.getArch());
317 //
318 // Add to dependencies
319 //
320 dependencies.add(libFpdModuleId);
321
322 //
323 // Create thread for library instances
324 //
325 GenBuildThread liBuildThread = new GenBuildThread(libinstances[i], fpdModuleId.getArch());
326 liBuildThread.setParentModuleId(fpdModuleId.getModule());
327 liBuildThread.setProject(getProject());
328 liBuildThread.setStatus(STATUS_DEPENDENCY_READY);
329 liBuildThread.setHighPriority(true);
330 allThreads.put(libFpdModuleId, liBuildThread);
331
332 updateFvs("libqueue", libFpdModuleId);
333 }
334
335 genBuildThread.setDependencies(dependencies);
336
337 // if (dependencies.size() == 0) {
338 genBuildThread.setStatus(STATUS_DEPENDENCY_READY);
339 // }
340
341 allThreads.put(fpdModuleId, genBuildThread);
342
343 //
344 // Put fpdModuleId to the corresponding FV
345 //
346 saq.push(GlobalData.getDoc(fpdModuleId));
347 String fvBinding = saq.getModuleFvBindingKeyword();
348
349 fpdModuleId.setFvBinding(fvBinding);
350 updateFvs(fvBinding, fpdModuleId);
351
352 //
353 // Prepare for out put file name
354 //
355 ModuleIdentification moduleId = fpdModuleId.getModule();
356
357 String baseName = saq.getModuleOutputFileBasename();
358
359 if (baseName == null) {
360 baseName = moduleId.getName();
361 }
362 outfiles.put(fpdModuleId, fpdModuleId.getArch() + File.separatorChar
363 + moduleId.getGuid() + "-" + baseName
364 + getSuffix(moduleId.getModuleType()));
365
366 //
367 // parse module build options, if any
368 //
369 GlobalData.addModuleToolChainOption(fpdModuleId, parseModuleBuildOptions(false));
370 GlobalData.addModuleToolChainFamilyOption(fpdModuleId, parseModuleBuildOptions(true));
371
372 //
373 // parse MSA build options
374 //
375 GlobalData.addMsaBuildOption(moduleId, parseMsaBuildOptions(false));
376 GlobalData.addMsaFamilyBuildOption(moduleId, parseMsaBuildOptions(true));
377
378 saq.pop();
379 }
380 }
381
382 private boolean isContain(String[] list, String item) {
383 for (int i = 0; i < list.length; i++) {
384 if (list[i].equalsIgnoreCase(item)) {
385 return true;
386 }
387 }
388 return false;
389 }
390
391 public synchronized static void addCount() {
392 synchronized (countSemaphore) {
393 ++currentRunNumber;
394 }
395 }
396
397 public synchronized static void subCount() {
398 synchronized (countSemaphore) {
399 --currentRunNumber;
400 --remainNumber;
401 }
402 }
403
404 private void updateTaskName(int percentage){
405 int number = percentage/10;
406 StringBuffer str = new StringBuffer(9);
407 for(int i = 0; i < 9; i++) {
408 if (i < number) {
409 str.append('>');
410 } else {
411 str.append('.');
412 }
413 }
414 this.setTaskName(str.toString());
415 }
416 }