]>
Commit | Line | Data |
---|---|---|
30fdf114 LG |
1 | ## @file |
2 | # Generate AutoGen.h, AutoGen.c and *.depex files | |
3 | # | |
4 | # Copyright (c) 2007, 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 | ||
14 | ## Import Modules | |
15 | # | |
16 | import os | |
17 | import re | |
18 | import os.path as path | |
19 | import copy | |
20 | ||
21 | import GenC | |
22 | import GenMake | |
23 | import GenDepex | |
24 | ||
25 | from StrGather import * | |
26 | from BuildEngine import BuildRule | |
27 | ||
28 | from Common.BuildToolError import * | |
29 | from Common.DataType import * | |
30 | from Common.Misc import * | |
31 | from Common.String import * | |
32 | import Common.GlobalData as GlobalData | |
33 | from GenFds.FdfParser import * | |
34 | from CommonDataClass.CommonClass import SkuInfoClass | |
35 | from Workspace.BuildClassObject import * | |
36 | ||
37 | ## Regular expression for splitting Dependency Expression stirng into tokens | |
38 | gDepexTokenPattern = re.compile("(\(|\)|\w+| \S+\.inf)") | |
39 | ||
40 | ## Mapping Makefile type | |
41 | gMakeTypeMap = {"MSFT":"nmake", "GCC":"gmake"} | |
42 | ||
43 | ||
44 | ## Build rule configuration file | |
45 | gBuildRuleFile = 'Conf/build_rule.txt' | |
46 | ||
47 | ## default file name for AutoGen | |
48 | gAutoGenCodeFileName = "AutoGen.c" | |
49 | gAutoGenHeaderFileName = "AutoGen.h" | |
50 | gAutoGenStringFileName = "%(module_name)sStrDefs.h" | |
51 | gAutoGenDepexFileName = "%(module_name)s.depex" | |
52 | gAutoGenSmmDepexFileName = "%(module_name)s.smm" | |
53 | ||
54 | ## Base class for AutoGen | |
55 | # | |
56 | # This class just implements the cache mechanism of AutoGen objects. | |
57 | # | |
58 | class AutoGen(object): | |
59 | # database to maintain the objects of xxxAutoGen | |
60 | _CACHE_ = {} # (BuildTarget, ToolChain) : {ARCH : {platform file: AutoGen object}}} | |
61 | ||
62 | ## Factory method | |
63 | # | |
64 | # @param Class class object of real AutoGen class | |
65 | # (WorkspaceAutoGen, ModuleAutoGen or PlatformAutoGen) | |
66 | # @param Workspace Workspace directory or WorkspaceAutoGen object | |
67 | # @param MetaFile The path of meta file | |
68 | # @param Target Build target | |
69 | # @param Toolchain Tool chain name | |
70 | # @param Arch Target arch | |
71 | # @param *args The specific class related parameters | |
72 | # @param **kwargs The specific class related dict parameters | |
73 | # | |
74 | def __new__(Class, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs): | |
75 | # check if the object has been created | |
76 | Key = (Target, Toolchain) | |
77 | if Key not in Class._CACHE_ or Arch not in Class._CACHE_[Key] \ | |
78 | or MetaFile not in Class._CACHE_[Key][Arch]: | |
79 | AutoGenObject = super(AutoGen, Class).__new__(Class) | |
80 | # call real constructor | |
81 | if not AutoGenObject._Init(Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs): | |
82 | return None | |
83 | if Key not in Class._CACHE_: | |
84 | Class._CACHE_[Key] = {} | |
85 | if Arch not in Class._CACHE_[Key]: | |
86 | Class._CACHE_[Key][Arch] = {} | |
87 | Class._CACHE_[Key][Arch][MetaFile] = AutoGenObject | |
88 | else: | |
89 | AutoGenObject = Class._CACHE_[Key][Arch][MetaFile] | |
90 | ||
91 | return AutoGenObject | |
92 | ||
93 | ## hash() operator | |
94 | # | |
95 | # The file path of platform file will be used to represent hash value of this object | |
96 | # | |
97 | # @retval int Hash value of the file path of platform file | |
98 | # | |
99 | def __hash__(self): | |
100 | return hash(self.MetaFile) | |
101 | ||
102 | ## str() operator | |
103 | # | |
104 | # The file path of platform file will be used to represent this object | |
105 | # | |
106 | # @retval string String of platform file path | |
107 | # | |
108 | def __str__(self): | |
109 | return str(self.MetaFile) | |
110 | ||
111 | ## "==" operator | |
112 | def __eq__(self, Other): | |
113 | return Other and self.MetaFile == Other | |
114 | ||
115 | ## Workspace AutoGen class | |
116 | # | |
117 | # This class is used mainly to control the whole platform build for different | |
118 | # architecture. This class will generate top level makefile. | |
119 | # | |
120 | class WorkspaceAutoGen(AutoGen): | |
121 | ## Real constructor of WorkspaceAutoGen | |
122 | # | |
123 | # This method behaves the same as __init__ except that it needs explict invoke | |
124 | # (in super class's __new__ method) | |
125 | # | |
126 | # @param WorkspaceDir Root directory of workspace | |
127 | # @param ActivePlatform Meta-file of active platform | |
128 | # @param Target Build target | |
129 | # @param Toolchain Tool chain name | |
130 | # @param ArchList List of architecture of current build | |
131 | # @param MetaFileDb Database containing meta-files | |
132 | # @param BuildConfig Configuration of build | |
133 | # @param ToolDefinition Tool chain definitions | |
134 | # @param FlashDefinitionFile File of flash definition | |
135 | # @param Fds FD list to be generated | |
136 | # @param Fvs FV list to be generated | |
137 | # @param SkuId SKU id from command line | |
138 | # | |
139 | def _Init(self, WorkspaceDir, ActivePlatform, Target, Toolchain, ArchList, MetaFileDb, | |
140 | BuildConfig, ToolDefinition, FlashDefinitionFile='', Fds=[], Fvs=[], SkuId=''): | |
141 | self.MetaFile = ActivePlatform.MetaFile | |
142 | self.WorkspaceDir = WorkspaceDir | |
143 | self.Platform = ActivePlatform | |
144 | self.BuildTarget = Target | |
145 | self.ToolChain = Toolchain | |
146 | self.ArchList = ArchList | |
147 | self.SkuId = SkuId | |
148 | ||
149 | self.BuildDatabase = MetaFileDb | |
150 | self.TargetTxt = BuildConfig | |
151 | self.ToolDef = ToolDefinition | |
152 | self.FdfFile = FlashDefinitionFile | |
153 | self.FdTargetList = Fds | |
154 | self.FvTargetList = Fvs | |
155 | self.AutoGenObjectList = [] | |
156 | ||
157 | # there's many relative directory operations, so ... | |
158 | os.chdir(self.WorkspaceDir) | |
159 | ||
160 | # parse FDF file to get PCDs in it, if any | |
161 | if self.FdfFile != None and self.FdfFile != '': | |
162 | Fdf = FdfParser(self.FdfFile.Path) | |
163 | Fdf.ParseFile() | |
164 | PcdSet = Fdf.Profile.PcdDict | |
165 | ModuleList = Fdf.Profile.InfList | |
166 | else: | |
167 | PcdSet = {} | |
168 | ModuleList = [] | |
169 | ||
170 | # apply SKU and inject PCDs from Flash Definition file | |
171 | for Arch in self.ArchList: | |
172 | Platform = self.BuildDatabase[self.MetaFile, Arch] | |
173 | Platform.SkuName = self.SkuId | |
174 | for Name, Guid in PcdSet: | |
175 | Platform.AddPcd(Name, Guid, PcdSet[Name, Guid]) | |
176 | ||
177 | Pa = PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch) | |
178 | # | |
179 | # Explicitly collect platform's dynamic PCDs | |
180 | # | |
181 | Pa.CollectPlatformDynamicPcds() | |
182 | self.AutoGenObjectList.append(Pa) | |
183 | ||
184 | self._BuildDir = None | |
185 | self._FvDir = None | |
186 | self._MakeFileDir = None | |
187 | self._BuildCommand = None | |
188 | ||
189 | return True | |
190 | ||
191 | def __repr__(self): | |
192 | return "%s [%s]" % (self.MetaFile, ", ".join(self.ArchList)) | |
193 | ||
194 | ## Return the directory to store FV files | |
195 | def _GetFvDir(self): | |
196 | if self._FvDir == None: | |
197 | self._FvDir = path.join(self.BuildDir, 'FV') | |
198 | return self._FvDir | |
199 | ||
200 | ## Return the directory to store all intermediate and final files built | |
201 | def _GetBuildDir(self): | |
202 | return self.AutoGenObjectList[0].BuildDir | |
203 | ||
204 | ## Return the build output directory platform specifies | |
205 | def _GetOutputDir(self): | |
206 | return self.Platform.OutputDirectory | |
207 | ||
208 | ## Return platform name | |
209 | def _GetName(self): | |
210 | return self.Platform.PlatformName | |
211 | ||
212 | ## Return meta-file GUID | |
213 | def _GetGuid(self): | |
214 | return self.Platform.Guid | |
215 | ||
216 | ## Return platform version | |
217 | def _GetVersion(self): | |
218 | return self.Platform.Version | |
219 | ||
220 | ## Return paths of tools | |
221 | def _GetToolDefinition(self): | |
222 | return self.AutoGenObjectList[0].ToolDefinition | |
223 | ||
224 | ## Return directory of platform makefile | |
225 | # | |
226 | # @retval string Makefile directory | |
227 | # | |
228 | def _GetMakeFileDir(self): | |
229 | if self._MakeFileDir == None: | |
230 | self._MakeFileDir = self.BuildDir | |
231 | return self._MakeFileDir | |
232 | ||
233 | ## Return build command string | |
234 | # | |
235 | # @retval string Build command string | |
236 | # | |
237 | def _GetBuildCommand(self): | |
238 | if self._BuildCommand == None: | |
239 | # BuildCommand should be all the same. So just get one from platform AutoGen | |
240 | self._BuildCommand = self.AutoGenObjectList[0].BuildCommand | |
241 | return self._BuildCommand | |
242 | ||
243 | ## Create makefile for the platform and mdoules in it | |
244 | # | |
245 | # @param CreateDepsMakeFile Flag indicating if the makefile for | |
246 | # modules will be created as well | |
247 | # | |
248 | def CreateMakeFile(self, CreateDepsMakeFile=False): | |
249 | # create makefile for platform | |
250 | Makefile = GenMake.TopLevelMakefile(self) | |
251 | if Makefile.Generate(): | |
252 | EdkLogger.debug(EdkLogger.DEBUG_9, "Generated makefile for platform [%s] %s\n" % | |
253 | (self.MetaFile, self.ArchList)) | |
254 | else: | |
255 | EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of makefile for platform [%s] %s\n" % | |
256 | (self.MetaFile, self.ArchList)) | |
257 | ||
258 | if CreateDepsMakeFile: | |
259 | for Pa in self.AutoGenObjectList: | |
260 | Pa.CreateMakeFile(CreateDepsMakeFile) | |
261 | ||
262 | ## Create autogen code for platform and modules | |
263 | # | |
264 | # Since there's no autogen code for platform, this method will do nothing | |
265 | # if CreateModuleCodeFile is set to False. | |
266 | # | |
267 | # @param CreateDepsCodeFile Flag indicating if creating module's | |
268 | # autogen code file or not | |
269 | # | |
270 | def CreateCodeFile(self, CreateDepsCodeFile=False): | |
271 | if not CreateDepsCodeFile: | |
272 | return | |
273 | for Pa in self.AutoGenObjectList: | |
274 | Pa.CreateCodeFile(CreateDepsCodeFile) | |
275 | ||
276 | Name = property(_GetName) | |
277 | Guid = property(_GetGuid) | |
278 | Version = property(_GetVersion) | |
279 | OutputDir = property(_GetOutputDir) | |
280 | ||
281 | ToolDefinition = property(_GetToolDefinition) # toolcode : tool path | |
282 | ||
283 | BuildDir = property(_GetBuildDir) | |
284 | FvDir = property(_GetFvDir) | |
285 | MakeFileDir = property(_GetMakeFileDir) | |
286 | BuildCommand = property(_GetBuildCommand) | |
287 | ||
288 | ## AutoGen class for platform | |
289 | # | |
290 | # PlatformAutoGen class will process the original information in platform | |
291 | # file in order to generate makefile for platform. | |
292 | # | |
293 | class PlatformAutoGen(AutoGen): | |
294 | # | |
295 | # Used to store all PCDs for both PEI and DXE phase, in order to generate | |
296 | # correct PCD database | |
297 | # | |
298 | _DynaPcdList_ = [] | |
299 | _NonDynaPcdList_ = [] | |
300 | ||
301 | ## The real constructor of PlatformAutoGen | |
302 | # | |
303 | # This method is not supposed to be called by users of PlatformAutoGen. It's | |
304 | # only used by factory method __new__() to do real initialization work for an | |
305 | # object of PlatformAutoGen | |
306 | # | |
307 | # @param Workspace WorkspaceAutoGen object | |
308 | # @param PlatformFile Platform file (DSC file) | |
309 | # @param Target Build target (DEBUG, RELEASE) | |
310 | # @param Toolchain Name of tool chain | |
311 | # @param Arch arch of the platform supports | |
312 | # | |
313 | def _Init(self, Workspace, PlatformFile, Target, Toolchain, Arch): | |
314 | EdkLogger.debug(EdkLogger.DEBUG_9, "AutoGen platform [%s] [%s]" % (PlatformFile, Arch)) | |
315 | GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (PlatformFile, Arch, Toolchain, Target) | |
316 | ||
317 | self.MetaFile = PlatformFile | |
318 | self.Workspace = Workspace | |
319 | self.WorkspaceDir = Workspace.WorkspaceDir | |
320 | self.ToolChain = Toolchain | |
321 | self.BuildTarget = Target | |
322 | self.Arch = Arch | |
323 | self.SourceDir = PlatformFile.SubDir | |
324 | self.SourceOverrideDir = None | |
325 | self.FdTargetList = self.Workspace.FdTargetList | |
326 | self.FvTargetList = self.Workspace.FvTargetList | |
327 | ||
328 | # flag indicating if the makefile/C-code file has been created or not | |
329 | self.IsMakeFileCreated = False | |
330 | self.IsCodeFileCreated = False | |
331 | ||
332 | self._Platform = None | |
333 | self._Name = None | |
334 | self._Guid = None | |
335 | self._Version = None | |
336 | ||
337 | self._BuildRule = None | |
338 | self._SourceDir = None | |
339 | self._BuildDir = None | |
340 | self._OutputDir = None | |
341 | self._FvDir = None | |
342 | self._MakeFileDir = None | |
343 | self._FdfFile = None | |
344 | ||
345 | self._PcdTokenNumber = None # (TokenCName, TokenSpaceGuidCName) : GeneratedTokenNumber | |
346 | self._DynamicPcdList = None # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...] | |
347 | self._NonDynamicPcdList = None # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...] | |
348 | ||
349 | self._ToolDefinitions = None | |
350 | self._ToolDefFile = None # toolcode : tool path | |
351 | self._ToolChainFamily = None | |
352 | self._BuildRuleFamily = None | |
353 | self._BuildOption = None # toolcode : option | |
354 | self._PackageList = None | |
355 | self._ModuleAutoGenList = None | |
356 | self._LibraryAutoGenList = None | |
357 | self._BuildCommand = None | |
358 | ||
359 | # get the original module/package/platform objects | |
360 | self.BuildDatabase = Workspace.BuildDatabase | |
361 | return True | |
362 | ||
363 | def __repr__(self): | |
364 | return "%s [%s]" % (self.MetaFile, self.Arch) | |
365 | ||
366 | ## Create autogen code for platform and modules | |
367 | # | |
368 | # Since there's no autogen code for platform, this method will do nothing | |
369 | # if CreateModuleCodeFile is set to False. | |
370 | # | |
371 | # @param CreateModuleCodeFile Flag indicating if creating module's | |
372 | # autogen code file or not | |
373 | # | |
374 | def CreateCodeFile(self, CreateModuleCodeFile=False): | |
375 | # only module has code to be greated, so do nothing if CreateModuleCodeFile is False | |
376 | if self.IsCodeFileCreated or not CreateModuleCodeFile: | |
377 | return | |
378 | ||
379 | for Ma in self.ModuleAutoGenList: | |
380 | Ma.CreateCodeFile(True) | |
381 | ||
382 | # don't do this twice | |
383 | self.IsCodeFileCreated = True | |
384 | ||
385 | ## Create makefile for the platform and mdoules in it | |
386 | # | |
387 | # @param CreateModuleMakeFile Flag indicating if the makefile for | |
388 | # modules will be created as well | |
389 | # | |
390 | def CreateMakeFile(self, CreateModuleMakeFile=False): | |
391 | if CreateModuleMakeFile: | |
392 | for ModuleFile in self.Platform.Modules: | |
393 | Ma = ModuleAutoGen(self.Workspace, ModuleFile, self.BuildTarget, | |
394 | self.ToolChain, self.Arch, self.MetaFile) | |
395 | Ma.CreateMakeFile(True) | |
396 | ||
397 | # no need to create makefile for the platform more than once | |
398 | if self.IsMakeFileCreated: | |
399 | return | |
400 | ||
401 | # create makefile for platform | |
402 | Makefile = GenMake.PlatformMakefile(self) | |
403 | if Makefile.Generate(): | |
404 | EdkLogger.debug(EdkLogger.DEBUG_9, "Generated makefile for platform [%s] [%s]\n" % | |
405 | (self.MetaFile, self.Arch)) | |
406 | else: | |
407 | EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of makefile for platform [%s] [%s]\n" % | |
408 | (self.MetaFile, self.Arch)) | |
409 | self.IsMakeFileCreated = True | |
410 | ||
411 | ## Collect dynamic PCDs | |
412 | # | |
413 | # Gather dynamic PCDs list from each module and their settings from platform | |
414 | # This interface should be invoked explicitly when platform action is created. | |
415 | # | |
416 | def CollectPlatformDynamicPcds(self): | |
417 | # for gathering error information | |
418 | NoDatumTypePcdList = set() | |
419 | ||
420 | self._GuidValue = {} | |
421 | for F in self.Platform.Modules.keys(): | |
422 | M = ModuleAutoGen(self.Workspace, F, self.BuildTarget, self.ToolChain, self.Arch, self.MetaFile) | |
423 | #GuidValue.update(M.Guids) | |
424 | for PcdFromModule in M.ModulePcdList+M.LibraryPcdList: | |
425 | # make sure that the "VOID*" kind of datum has MaxDatumSize set | |
426 | if PcdFromModule.DatumType == "VOID*" and PcdFromModule.MaxDatumSize == None: | |
427 | NoDatumTypePcdList.add("%s.%s [%s]" % (PcdFromModule.TokenSpaceGuidCName, PcdFromModule.TokenCName, F)) | |
428 | ||
429 | if PcdFromModule.Type in GenC.gDynamicPcd or PcdFromModule.Type in GenC.gDynamicExPcd: | |
430 | # | |
431 | # If a dynamic PCD used by a PEM module/PEI module & DXE module, | |
432 | # it should be stored in Pcd PEI database, If a dynamic only | |
433 | # used by DXE module, it should be stored in DXE PCD database. | |
434 | # The default Phase is DXE | |
435 | # | |
436 | if M.ModuleType in ["PEIM", "PEI_CORE"]: | |
437 | PcdFromModule.Phase = "PEI" | |
438 | if PcdFromModule not in self._DynaPcdList_: | |
439 | self._DynaPcdList_.append(PcdFromModule) | |
440 | elif PcdFromModule.Phase == 'PEI': | |
441 | # overwrite any the same PCD existing, if Phase is PEI | |
442 | Index = self._DynaPcdList_.index(PcdFromModule) | |
443 | self._DynaPcdList_[Index] = PcdFromModule | |
444 | elif PcdFromModule not in self._NonDynaPcdList_: | |
445 | self._NonDynaPcdList_.append(PcdFromModule) | |
446 | ||
447 | # print out error information and break the build, if error found | |
448 | if len(NoDatumTypePcdList) > 0: | |
449 | NoDatumTypePcdListString = "\n\t\t".join(NoDatumTypePcdList) | |
450 | EdkLogger.error("build", AUTOGEN_ERROR, "PCD setting error", | |
451 | File=self.MetaFile, | |
452 | ExtraData="\n\tPCD(s) without MaxDatumSize:\n\t\t%s\n" | |
453 | % NoDatumTypePcdListString) | |
454 | self._NonDynamicPcdList = self._NonDynaPcdList_ | |
455 | self._DynamicPcdList = self._DynaPcdList_ | |
456 | ||
457 | # | |
458 | # Sort dynamic PCD list to: | |
459 | # 1) If PCD's datum type is VOID* and value is unicode string which starts with L, the PCD item should | |
460 | # try to be put header of dynamicd List | |
461 | # 2) If PCD is HII type, the PCD item should be put after unicode type PCD | |
462 | # | |
463 | # The reason of sorting is make sure the unicode string is in double-byte alignment in string table. | |
464 | # | |
465 | UnicodePcdArray = [] | |
466 | HiiPcdArray = [] | |
467 | OtherPcdArray = [] | |
468 | for Pcd in self._DynamicPcdList: | |
469 | # just pick the a value to determine whether is unicode string type | |
470 | Sku = Pcd.SkuInfoList[Pcd.SkuInfoList.keys()[0]] | |
471 | PcdValue = Sku.DefaultValue | |
472 | if Pcd.DatumType == 'VOID*' and PcdValue.startswith("L"): | |
473 | # if found PCD which datum value is unicode string the insert to left size of UnicodeIndex | |
474 | UnicodePcdArray.append(Pcd) | |
475 | elif len(Sku.VariableName) > 0: | |
476 | # if found HII type PCD then insert to right of UnicodeIndex | |
477 | HiiPcdArray.append(Pcd) | |
478 | else: | |
479 | OtherPcdArray.append(Pcd) | |
480 | del self._DynamicPcdList[:] | |
481 | self._DynamicPcdList.extend(UnicodePcdArray) | |
482 | self._DynamicPcdList.extend(HiiPcdArray) | |
483 | self._DynamicPcdList.extend(OtherPcdArray) | |
484 | ||
485 | ||
486 | ## Return the platform build data object | |
487 | def _GetPlatform(self): | |
488 | if self._Platform == None: | |
489 | self._Platform = self.BuildDatabase[self.MetaFile, self.Arch] | |
490 | return self._Platform | |
491 | ||
492 | ## Return platform name | |
493 | def _GetName(self): | |
494 | return self.Platform.PlatformName | |
495 | ||
496 | ## Return the meta file GUID | |
497 | def _GetGuid(self): | |
498 | return self.Platform.Guid | |
499 | ||
500 | ## Return the platform version | |
501 | def _GetVersion(self): | |
502 | return self.Platform.Version | |
503 | ||
504 | ## Return the FDF file name | |
505 | def _GetFdfFile(self): | |
506 | if self._FdfFile == None: | |
507 | if self.Workspace.FdfFile != "": | |
508 | self._FdfFile= path.join(self.WorkspaceDir, self.Workspace.FdfFile) | |
509 | else: | |
510 | self._FdfFile = '' | |
511 | return self._FdfFile | |
512 | ||
513 | ## Return the build output directory platform specifies | |
514 | def _GetOutputDir(self): | |
515 | return self.Platform.OutputDirectory | |
516 | ||
517 | ## Return the directory to store all intermediate and final files built | |
518 | def _GetBuildDir(self): | |
519 | if self._BuildDir == None: | |
520 | if os.path.isabs(self.OutputDir): | |
521 | self._BuildDir = path.join( | |
522 | path.abspath(self.OutputDir), | |
523 | self.BuildTarget + "_" + self.ToolChain, | |
524 | ) | |
525 | else: | |
526 | self._BuildDir = path.join( | |
527 | self.WorkspaceDir, | |
528 | self.OutputDir, | |
529 | self.BuildTarget + "_" + self.ToolChain, | |
530 | ) | |
531 | return self._BuildDir | |
532 | ||
533 | ## Return directory of platform makefile | |
534 | # | |
535 | # @retval string Makefile directory | |
536 | # | |
537 | def _GetMakeFileDir(self): | |
538 | if self._MakeFileDir == None: | |
539 | self._MakeFileDir = path.join(self.BuildDir, self.Arch) | |
540 | return self._MakeFileDir | |
541 | ||
542 | ## Return build command string | |
543 | # | |
544 | # @retval string Build command string | |
545 | # | |
546 | def _GetBuildCommand(self): | |
547 | if self._BuildCommand == None: | |
548 | self._BuildCommand = [] | |
549 | if "MAKE" in self.ToolDefinition and "PATH" in self.ToolDefinition["MAKE"]: | |
550 | self._BuildCommand += SplitOption(self.ToolDefinition["MAKE"]["PATH"]) | |
551 | if "FLAGS" in self.ToolDefinition["MAKE"]: | |
552 | NewOption = self.ToolDefinition["MAKE"]["FLAGS"].strip() | |
553 | if NewOption != '': | |
554 | self._BuildCommand += SplitOption(NewOption) | |
555 | return self._BuildCommand | |
556 | ||
557 | ## Get tool chain definition | |
558 | # | |
559 | # Get each tool defition for given tool chain from tools_def.txt and platform | |
560 | # | |
561 | def _GetToolDefinition(self): | |
562 | if self._ToolDefinitions == None: | |
563 | ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDictionary | |
564 | if TAB_TOD_DEFINES_COMMAND_TYPE not in self.Workspace.ToolDef.ToolsDefTxtDatabase: | |
565 | EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, "No tools found in configuration", | |
566 | ExtraData="[%s]" % self.MetaFile) | |
567 | self._ToolDefinitions = {} | |
568 | DllPathList = set() | |
569 | for Def in ToolDefinition: | |
570 | Target, Tag, Arch, Tool, Attr = Def.split("_") | |
571 | if Target != self.BuildTarget or Tag != self.ToolChain or Arch != self.Arch: | |
572 | continue | |
573 | ||
574 | Value = ToolDefinition[Def] | |
575 | # don't record the DLL | |
576 | if Attr == "DLL": | |
577 | DllPathList.add(Value) | |
578 | continue | |
579 | ||
580 | if Tool not in self._ToolDefinitions: | |
581 | self._ToolDefinitions[Tool] = {} | |
582 | self._ToolDefinitions[Tool][Attr] = Value | |
583 | ||
584 | ToolsDef = '' | |
585 | MakePath = '' | |
586 | if GlobalData.gOptions.SilentMode and "MAKE" in self._ToolDefinitions: | |
587 | if "FLAGS" not in self._ToolDefinitions["MAKE"]: | |
588 | self._ToolDefinitions["MAKE"]["FLAGS"] = "" | |
589 | self._ToolDefinitions["MAKE"]["FLAGS"] += " -s" | |
590 | MakeFlags = '' | |
591 | for Tool in self._ToolDefinitions: | |
592 | for Attr in self._ToolDefinitions[Tool]: | |
593 | Value = self._ToolDefinitions[Tool][Attr] | |
594 | if Tool in self.BuildOption and Attr in self.BuildOption[Tool]: | |
595 | # check if override is indicated | |
596 | if self.BuildOption[Tool][Attr].startswith('='): | |
597 | Value = self.BuildOption[Tool][Attr][1:] | |
598 | else: | |
599 | Value += " " + self.BuildOption[Tool][Attr] | |
600 | ||
601 | if Attr == "PATH": | |
602 | # Don't put MAKE definition in the file | |
603 | if Tool == "MAKE": | |
604 | MakePath = Value | |
605 | else: | |
606 | ToolsDef += "%s = %s\n" % (Tool, Value) | |
607 | elif Attr != "DLL": | |
608 | # Don't put MAKE definition in the file | |
609 | if Tool == "MAKE": | |
610 | if Attr == "FLAGS": | |
611 | MakeFlags = Value | |
612 | else: | |
613 | ToolsDef += "%s_%s = %s\n" % (Tool, Attr, Value) | |
614 | ToolsDef += "\n" | |
615 | ||
616 | SaveFileOnChange(self.ToolDefinitionFile, ToolsDef) | |
617 | for DllPath in DllPathList: | |
618 | os.environ["PATH"] = DllPath + os.pathsep + os.environ["PATH"] | |
619 | os.environ["MAKE_FLAGS"] = MakeFlags | |
620 | ||
621 | return self._ToolDefinitions | |
622 | ||
623 | ## Return the paths of tools | |
624 | def _GetToolDefFile(self): | |
625 | if self._ToolDefFile == None: | |
626 | self._ToolDefFile = os.path.join(self.MakeFileDir, "TOOLS_DEF." + self.Arch) | |
627 | return self._ToolDefFile | |
628 | ||
629 | ## Retrieve the toolchain family of given toolchain tag. Default to 'MSFT'. | |
630 | def _GetToolChainFamily(self): | |
631 | if self._ToolChainFamily == None: | |
632 | ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase | |
633 | if TAB_TOD_DEFINES_FAMILY not in ToolDefinition \ | |
634 | or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \ | |
635 | or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]: | |
636 | EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \ | |
637 | % self.ToolChain) | |
638 | self._ToolChainFamily = "MSFT" | |
639 | else: | |
640 | self._ToolChainFamily = ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain] | |
641 | return self._ToolChainFamily | |
642 | ||
643 | def _GetBuildRuleFamily(self): | |
644 | if self._BuildRuleFamily == None: | |
645 | ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase | |
646 | if TAB_TOD_DEFINES_BUILDRULEFAMILY not in ToolDefinition \ | |
647 | or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY] \ | |
648 | or not ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]: | |
649 | EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \ | |
650 | % self.ToolChain) | |
651 | self._BuildRuleFamily = "MSFT" | |
652 | else: | |
653 | self._BuildRuleFamily = ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain] | |
654 | return self._BuildRuleFamily | |
655 | ||
656 | ## Return the build options specific to this platform | |
657 | def _GetBuildOptions(self): | |
658 | if self._BuildOption == None: | |
659 | self._BuildOption = self._ExpandBuildOption(self.Platform.BuildOptions) | |
660 | return self._BuildOption | |
661 | ||
662 | ## Parse build_rule.txt in $(WORKSPACE)/Conf/build_rule.txt | |
663 | # | |
664 | # @retval BuildRule object | |
665 | # | |
666 | def _GetBuildRule(self): | |
667 | if self._BuildRule == None: | |
668 | BuildRuleFile = None | |
669 | if TAB_TAT_DEFINES_BUILD_RULE_CONF in self.Workspace.TargetTxt.TargetTxtDictionary: | |
670 | BuildRuleFile = self.Workspace.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_BUILD_RULE_CONF] | |
671 | if BuildRuleFile in [None, '']: | |
672 | BuildRuleFile = gBuildRuleFile | |
673 | self._BuildRule = BuildRule(BuildRuleFile) | |
674 | return self._BuildRule | |
675 | ||
676 | ## Summarize the packages used by modules in this platform | |
677 | def _GetPackageList(self): | |
678 | if self._PackageList == None: | |
679 | self._PackageList = set() | |
680 | for La in self.LibraryAutoGenList: | |
681 | self._PackageList.update(La.DependentPackageList) | |
682 | for Ma in self.ModuleAutoGenList: | |
683 | self._PackageList.update(Ma.DependentPackageList) | |
684 | self._PackageList = list(self._PackageList) | |
685 | return self._PackageList | |
686 | ||
687 | ## Get list of non-dynamic PCDs | |
688 | def _GetNonDynamicPcdList(self): | |
689 | return self._NonDynamicPcdList | |
690 | ||
691 | ## Get list of dynamic PCDs | |
692 | def _GetDynamicPcdList(self): | |
693 | return self._DynamicPcdList | |
694 | ||
695 | ## Generate Token Number for all PCD | |
696 | def _GetPcdTokenNumbers(self): | |
697 | if self._PcdTokenNumber == None: | |
698 | self._PcdTokenNumber = sdict() | |
699 | TokenNumber = 1 | |
700 | for Pcd in self.DynamicPcdList: | |
701 | if Pcd.Phase == "PEI": | |
702 | EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber)) | |
703 | self._PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber | |
704 | TokenNumber += 1 | |
705 | ||
706 | for Pcd in self.DynamicPcdList: | |
707 | if Pcd.Phase == "DXE": | |
708 | EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber)) | |
709 | self._PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber | |
710 | TokenNumber += 1 | |
711 | ||
712 | for Pcd in self.NonDynamicPcdList: | |
713 | self._PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber | |
714 | TokenNumber += 1 | |
715 | return self._PcdTokenNumber | |
716 | ||
717 | ## Summarize ModuleAutoGen objects of all modules/libraries to be built for this platform | |
718 | def _GetAutoGenObjectList(self): | |
719 | self._ModuleAutoGenList = [] | |
720 | self._LibraryAutoGenList = [] | |
721 | for ModuleFile in self.Platform.Modules: | |
722 | Ma = ModuleAutoGen( | |
723 | self.Workspace, | |
724 | ModuleFile, | |
725 | self.BuildTarget, | |
726 | self.ToolChain, | |
727 | self.Arch, | |
728 | self.MetaFile | |
729 | ) | |
730 | if Ma not in self._ModuleAutoGenList: | |
731 | self._ModuleAutoGenList.append(Ma) | |
732 | for La in Ma.LibraryAutoGenList: | |
733 | if La not in self._LibraryAutoGenList: | |
734 | self._LibraryAutoGenList.append(La) | |
735 | ||
736 | ## Summarize ModuleAutoGen objects of all modules to be built for this platform | |
737 | def _GetModuleAutoGenList(self): | |
738 | if self._ModuleAutoGenList == None: | |
739 | self._GetAutoGenObjectList() | |
740 | return self._ModuleAutoGenList | |
741 | ||
742 | ## Summarize ModuleAutoGen objects of all libraries to be built for this platform | |
743 | def _GetLibraryAutoGenList(self): | |
744 | if self._LibraryAutoGenList == None: | |
745 | self._GetAutoGenObjectList() | |
746 | return self._LibraryAutoGenList | |
747 | ||
748 | ## Test if a module is supported by the platform | |
749 | # | |
750 | # An error will be raised directly if the module or its arch is not supported | |
751 | # by the platform or current configuration | |
752 | # | |
753 | def ValidModule(self, Module): | |
754 | return Module in self.Platform.Modules or Module in self.Platform.LibraryInstances | |
755 | ||
756 | ## Resolve the library classes in a module to library instances | |
757 | # | |
758 | # This method will not only resolve library classes but also sort the library | |
759 | # instances according to the dependency-ship. | |
760 | # | |
761 | # @param Module The module from which the library classes will be resolved | |
762 | # | |
763 | # @retval library_list List of library instances sorted | |
764 | # | |
765 | def ApplyLibraryInstance(self, Module): | |
766 | ModuleType = Module.ModuleType | |
767 | ||
768 | # for overridding library instances with module specific setting | |
769 | PlatformModule = self.Platform.Modules[str(Module)] | |
770 | ||
771 | # add forced library instance | |
772 | for LibraryClass in PlatformModule.LibraryClasses: | |
773 | if LibraryClass.startswith("NULL"): | |
774 | Module.LibraryClasses[LibraryClass] = PlatformModule.LibraryClasses[LibraryClass] | |
775 | ||
776 | # R9 module | |
777 | LibraryConsumerList = [Module] | |
778 | Constructor = [] | |
779 | ConsumedByList = sdict() | |
780 | LibraryInstance = sdict() | |
781 | ||
782 | EdkLogger.verbose("") | |
783 | EdkLogger.verbose("Library instances of module [%s] [%s]:" % (str(Module), self.Arch)) | |
784 | while len(LibraryConsumerList) > 0: | |
785 | M = LibraryConsumerList.pop() | |
786 | for LibraryClassName in M.LibraryClasses: | |
787 | if LibraryClassName not in LibraryInstance: | |
788 | # override library instance for this module | |
789 | if LibraryClassName in PlatformModule.LibraryClasses: | |
790 | LibraryPath = PlatformModule.LibraryClasses[LibraryClassName] | |
791 | else: | |
792 | LibraryPath = self.Platform.LibraryClasses[LibraryClassName, ModuleType] | |
793 | if LibraryPath == None or LibraryPath == "": | |
794 | LibraryPath = M.LibraryClasses[LibraryClassName] | |
795 | if LibraryPath == None or LibraryPath == "": | |
796 | EdkLogger.error("build", RESOURCE_NOT_AVAILABLE, | |
797 | "Instance of library class [%s] is not found" % LibraryClassName, | |
798 | File=self.MetaFile, | |
799 | ExtraData="in [%s] [%s]\n\tconsumed by module [%s]" % (str(M), self.Arch, str(Module))) | |
800 | ||
801 | LibraryModule = self.BuildDatabase[LibraryPath, self.Arch] | |
802 | # for those forced library instance (NULL library), add a fake library class | |
803 | if LibraryClassName.startswith("NULL"): | |
804 | LibraryModule.LibraryClass.append(LibraryClassObject(LibraryClassName, [ModuleType])) | |
805 | elif LibraryModule.LibraryClass == None \ | |
806 | or len(LibraryModule.LibraryClass) == 0 \ | |
807 | or (ModuleType != 'USER_DEFINED' | |
808 | and ModuleType not in LibraryModule.LibraryClass[0].SupModList): | |
809 | # only USER_DEFINED can link against any library instance despite of its SupModList | |
810 | EdkLogger.error("build", OPTION_MISSING, | |
811 | "Module type [%s] is not supported by library instance [%s]" \ | |
812 | % (ModuleType, LibraryPath), File=self.MetaFile, | |
813 | ExtraData="consumed by [%s]" % str(Module)) | |
814 | ||
815 | LibraryInstance[LibraryClassName] = LibraryModule | |
816 | LibraryConsumerList.append(LibraryModule) | |
817 | EdkLogger.verbose("\t" + str(LibraryClassName) + " : " + str(LibraryModule)) | |
818 | else: | |
819 | LibraryModule = LibraryInstance[LibraryClassName] | |
820 | ||
821 | if LibraryModule == None: | |
822 | continue | |
823 | ||
824 | if LibraryModule.ConstructorList != [] and LibraryModule not in Constructor: | |
825 | Constructor.append(LibraryModule) | |
826 | ||
827 | if LibraryModule not in ConsumedByList: | |
828 | ConsumedByList[LibraryModule] = [] | |
829 | # don't add current module itself to consumer list | |
830 | if M != Module: | |
831 | if M in ConsumedByList[LibraryModule]: | |
832 | continue | |
833 | ConsumedByList[LibraryModule].append(M) | |
834 | # | |
835 | # Initialize the sorted output list to the empty set | |
836 | # | |
837 | SortedLibraryList = [] | |
838 | # | |
839 | # Q <- Set of all nodes with no incoming edges | |
840 | # | |
841 | LibraryList = [] #LibraryInstance.values() | |
842 | Q = [] | |
843 | for LibraryClassName in LibraryInstance: | |
844 | M = LibraryInstance[LibraryClassName] | |
845 | LibraryList.append(M) | |
846 | if ConsumedByList[M] == []: | |
847 | Q.insert(0, M) | |
848 | ||
849 | # | |
850 | # start the DAG algorithm | |
851 | # | |
852 | while True: | |
853 | EdgeRemoved = True | |
854 | while Q == [] and EdgeRemoved: | |
855 | EdgeRemoved = False | |
856 | # for each node Item with a Constructor | |
857 | for Item in LibraryList: | |
858 | if Item not in Constructor: | |
859 | continue | |
860 | # for each Node without a constructor with an edge e from Item to Node | |
861 | for Node in ConsumedByList[Item]: | |
862 | if Node in Constructor: | |
863 | continue | |
864 | # remove edge e from the graph if Node has no constructor | |
865 | ConsumedByList[Item].remove(Node) | |
866 | EdgeRemoved = True | |
867 | if ConsumedByList[Item] == []: | |
868 | # insert Item into Q | |
869 | Q.insert(0, Item) | |
870 | break | |
871 | if Q != []: | |
872 | break | |
873 | # DAG is done if there's no more incoming edge for all nodes | |
874 | if Q == []: | |
875 | break | |
876 | ||
877 | # remove node from Q | |
878 | Node = Q.pop() | |
879 | # output Node | |
880 | SortedLibraryList.append(Node) | |
881 | ||
882 | # for each node Item with an edge e from Node to Item do | |
883 | for Item in LibraryList: | |
884 | if Node not in ConsumedByList[Item]: | |
885 | continue | |
886 | # remove edge e from the graph | |
887 | ConsumedByList[Item].remove(Node) | |
888 | ||
889 | if ConsumedByList[Item] != []: | |
890 | continue | |
891 | # insert Item into Q, if Item has no other incoming edges | |
892 | Q.insert(0, Item) | |
893 | ||
894 | # | |
895 | # if any remaining node Item in the graph has a constructor and an incoming edge, then the graph has a cycle | |
896 | # | |
897 | for Item in LibraryList: | |
898 | if ConsumedByList[Item] != [] and Item in Constructor and len(Constructor) > 1: | |
899 | ErrorMessage = "\tconsumed by " + "\n\tconsumed by ".join([str(L) for L in ConsumedByList[Item]]) | |
900 | EdkLogger.error("build", BUILD_ERROR, 'Library [%s] with constructors has a cycle' % str(Item), | |
901 | ExtraData=ErrorMessage, File=self.MetaFile) | |
902 | if Item not in SortedLibraryList: | |
903 | SortedLibraryList.append(Item) | |
904 | ||
905 | # | |
906 | # Build the list of constructor and destructir names | |
907 | # The DAG Topo sort produces the destructor order, so the list of constructors must generated in the reverse order | |
908 | # | |
909 | SortedLibraryList.reverse() | |
910 | return SortedLibraryList | |
911 | ||
912 | ||
913 | ## Override PCD setting (type, value, ...) | |
914 | # | |
915 | # @param ToPcd The PCD to be overrided | |
916 | # @param FromPcd The PCD overrideing from | |
917 | # | |
918 | def _OverridePcd(self, ToPcd, FromPcd, Module=""): | |
919 | # | |
920 | # in case there's PCDs coming from FDF file, which have no type given. | |
921 | # at this point, ToPcd.Type has the type found from dependent | |
922 | # package | |
923 | # | |
924 | if FromPcd != None: | |
925 | if ToPcd.Pending and FromPcd.Type not in [None, '']: | |
926 | ToPcd.Type = FromPcd.Type | |
927 | elif ToPcd.Type not in [None, ''] and FromPcd.Type not in [None, ''] \ | |
928 | and ToPcd.Type != FromPcd.Type: | |
929 | EdkLogger.error("build", OPTION_CONFLICT, "Mismatched PCD type", | |
930 | ExtraData="%s.%s is defined as [%s] in module %s, but as [%s] in platform."\ | |
931 | % (ToPcd.TokenSpaceGuidCName, ToPcd.TokenCName, | |
932 | ToPcd.Type, Module, FromPcd.Type), | |
933 | File=self.MetaFile) | |
934 | ||
935 | if FromPcd.MaxDatumSize not in [None, '']: | |
936 | ToPcd.MaxDatumSize = FromPcd.MaxDatumSize | |
937 | if FromPcd.DefaultValue not in [None, '']: | |
938 | ToPcd.DefaultValue = FromPcd.DefaultValue | |
939 | if FromPcd.TokenValue not in [None, '']: | |
940 | ToPcd.TokenValue = FromPcd.TokenValue | |
941 | if FromPcd.MaxDatumSize not in [None, '']: | |
942 | ToPcd.MaxDatumSize = FromPcd.MaxDatumSize | |
943 | if FromPcd.DatumType not in [None, '']: | |
944 | ToPcd.DatumType = FromPcd.DatumType | |
945 | if FromPcd.SkuInfoList not in [None, '', []]: | |
946 | ToPcd.SkuInfoList = FromPcd.SkuInfoList | |
947 | ||
948 | # check the validation of datum | |
949 | IsValid, Cause = CheckPcdDatum(ToPcd.DatumType, ToPcd.DefaultValue) | |
950 | if not IsValid: | |
951 | EdkLogger.error('build', FORMAT_INVALID, Cause, File=self.MetaFile, | |
952 | ExtraData="%s.%s" % (ToPcd.TokenSpaceGuidCName, ToPcd.TokenCName)) | |
953 | ||
954 | if ToPcd.DatumType == "VOID*" and ToPcd.MaxDatumSize in ['', None]: | |
955 | EdkLogger.debug(EdkLogger.DEBUG_9, "No MaxDatumSize specified for PCD %s.%s" \ | |
956 | % (ToPcd.TokenSpaceGuidCName, ToPcd.TokenCName)) | |
957 | Value = ToPcd.DefaultValue | |
958 | if Value in [None, '']: | |
959 | ToPcd.MaxDatumSize = 1 | |
960 | elif Value[0] == 'L': | |
961 | ToPcd.MaxDatumSize = str(len(Value) * 2) | |
962 | elif Value[0] == '{': | |
963 | ToPcd.MaxDatumSize = str(len(Value.split(','))) | |
964 | else: | |
965 | ToPcd.MaxDatumSize = str(len(Value)) | |
966 | ||
967 | # apply default SKU for dynamic PCDS if specified one is not available | |
968 | if (ToPcd.Type in PCD_DYNAMIC_TYPE_LIST or ToPcd.Type in PCD_DYNAMIC_EX_TYPE_LIST) \ | |
969 | and ToPcd.SkuInfoList in [None, {}, '']: | |
970 | if self.Platform.SkuName in self.Platform.SkuIds: | |
971 | SkuName = self.Platform.SkuName | |
972 | else: | |
973 | SkuName = 'DEFAULT' | |
974 | ToPcd.SkuInfoList = { | |
975 | SkuName : SkuInfoClass(SkuName, self.Platform.SkuIds[SkuName], '', '', '', '', '', ToPcd.DefaultValue) | |
976 | } | |
977 | ||
978 | ## Apply PCD setting defined platform to a module | |
979 | # | |
980 | # @param Module The module from which the PCD setting will be overrided | |
981 | # | |
982 | # @retval PCD_list The list PCDs with settings from platform | |
983 | # | |
984 | def ApplyPcdSetting(self, Module, Pcds): | |
985 | # for each PCD in module | |
986 | for Name,Guid in Pcds: | |
987 | PcdInModule = Pcds[Name,Guid] | |
988 | # find out the PCD setting in platform | |
989 | if (Name,Guid) in self.Platform.Pcds: | |
990 | PcdInPlatform = self.Platform.Pcds[Name,Guid] | |
991 | else: | |
992 | PcdInPlatform = None | |
993 | # then override the settings if any | |
994 | self._OverridePcd(PcdInModule, PcdInPlatform, Module) | |
995 | # resolve the VariableGuid value | |
996 | for SkuId in PcdInModule.SkuInfoList: | |
997 | Sku = PcdInModule.SkuInfoList[SkuId] | |
998 | if Sku.VariableGuid == '': continue | |
999 | Sku.VariableGuidValue = GuidValue(Sku.VariableGuid, self.PackageList) | |
1000 | if Sku.VariableGuidValue == None: | |
1001 | PackageList = "\n\t".join([str(P) for P in self.PackageList]) | |
1002 | EdkLogger.error( | |
1003 | 'build', | |
1004 | RESOURCE_NOT_AVAILABLE, | |
1005 | "Value of GUID [%s] is not found in" % Sku.VariableGuid, | |
1006 | ExtraData=PackageList + "\n\t(used with %s.%s from module %s)" \ | |
1007 | % (Guid, Name, str(Module)), | |
1008 | File=self.MetaFile | |
1009 | ) | |
1010 | ||
1011 | # override PCD settings with module specific setting | |
1012 | if Module in self.Platform.Modules: | |
1013 | PlatformModule = self.Platform.Modules[str(Module)] | |
1014 | for Key in PlatformModule.Pcds: | |
1015 | if Key in Pcds: | |
1016 | self._OverridePcd(Pcds[Key], PlatformModule.Pcds[Key], Module) | |
1017 | return Pcds.values() | |
1018 | ||
1019 | ## Resolve library names to library modules | |
1020 | # | |
1021 | # (for R8.x modules) | |
1022 | # | |
1023 | # @param Module The module from which the library names will be resolved | |
1024 | # | |
1025 | # @retval library_list The list of library modules | |
1026 | # | |
1027 | def ResolveLibraryReference(self, Module): | |
1028 | EdkLogger.verbose("") | |
1029 | EdkLogger.verbose("Library instances of module [%s] [%s]:" % (str(Module), self.Arch)) | |
1030 | LibraryConsumerList = [Module] | |
1031 | ||
1032 | # "CompilerStub" is a must for R8 modules | |
1033 | if Module.Libraries: | |
1034 | Module.Libraries.append("CompilerStub") | |
1035 | LibraryList = [] | |
1036 | while len(LibraryConsumerList) > 0: | |
1037 | M = LibraryConsumerList.pop() | |
1038 | for LibraryName in M.Libraries: | |
1039 | Library = self.Platform.LibraryClasses[LibraryName, ':dummy:'] | |
1040 | if Library == None: | |
1041 | for Key in self.Platform.LibraryClasses.data.keys(): | |
1042 | if LibraryName.upper() == Key.upper(): | |
1043 | Library = self.Platform.LibraryClasses[Key, ':dummy:'] | |
1044 | break | |
1045 | if Library == None: | |
1046 | EdkLogger.warn("build", "Library [%s] is not found" % LibraryName, File=str(M), | |
1047 | ExtraData="\t%s [%s]" % (str(Module), self.Arch)) | |
1048 | continue | |
1049 | ||
1050 | if Library not in LibraryList: | |
1051 | LibraryList.append(Library) | |
1052 | LibraryConsumerList.append(Library) | |
1053 | EdkLogger.verbose("\t" + LibraryName + " : " + str(Library) + ' ' + str(type(Library))) | |
1054 | return LibraryList | |
1055 | ||
1056 | ## Expand * in build option key | |
1057 | # | |
1058 | # @param Options Options to be expanded | |
1059 | # | |
1060 | # @retval options Options expanded | |
1061 | # | |
1062 | def _ExpandBuildOption(self, Options): | |
1063 | BuildOptions = {} | |
1064 | for Key in Options: | |
1065 | Family = Key[0] | |
1066 | Target, Tag, Arch, Tool, Attr = Key[1].split("_") | |
1067 | # if tool chain family doesn't match, skip it | |
1068 | if Family and Tool in self.ToolDefinition and Family != self.ToolDefinition[Tool]["FAMILY"]: | |
1069 | continue | |
1070 | # expand any wildcard | |
1071 | if Target == "*" or Target == self.BuildTarget: | |
1072 | if Tag == "*" or Tag == self.ToolChain: | |
1073 | if Arch == "*" or Arch == self.Arch: | |
1074 | if Tool not in BuildOptions: | |
1075 | BuildOptions[Tool] = {} | |
1076 | if Attr != "FLAGS" or Attr not in BuildOptions[Tool]: | |
1077 | BuildOptions[Tool][Attr] = Options[Key] | |
1078 | else: | |
1079 | # append options for the same tool | |
1080 | BuildOptions[Tool][Attr] += " " + Options[Key] | |
1081 | return BuildOptions | |
1082 | ||
1083 | ## Append build options in platform to a module | |
1084 | # | |
1085 | # @param Module The module to which the build options will be appened | |
1086 | # | |
1087 | # @retval options The options appended with build options in platform | |
1088 | # | |
1089 | def ApplyBuildOption(self, Module): | |
1090 | PlatformOptions = self.BuildOption | |
1091 | ModuleOptions = self._ExpandBuildOption(Module.BuildOptions) | |
1092 | if Module in self.Platform.Modules: | |
1093 | PlatformModule = self.Platform.Modules[str(Module)] | |
1094 | PlatformModuleOptions = self._ExpandBuildOption(PlatformModule.BuildOptions) | |
1095 | else: | |
1096 | PlatformModuleOptions = {} | |
1097 | ||
1098 | AllTools = set(ModuleOptions.keys() + PlatformOptions.keys() + PlatformModuleOptions.keys() + self.ToolDefinition.keys()) | |
1099 | BuildOptions = {} | |
1100 | for Tool in AllTools: | |
1101 | if Tool not in BuildOptions: | |
1102 | BuildOptions[Tool] = {} | |
1103 | ||
1104 | for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, PlatformModuleOptions]: | |
1105 | if Tool not in Options: | |
1106 | continue | |
1107 | for Attr in Options[Tool]: | |
1108 | Value = Options[Tool][Attr] | |
1109 | if Attr not in BuildOptions[Tool]: | |
1110 | BuildOptions[Tool][Attr] = "" | |
1111 | # check if override is indicated | |
1112 | if Value.startswith('='): | |
1113 | BuildOptions[Tool][Attr] = Value[1:] | |
1114 | else: | |
1115 | BuildOptions[Tool][Attr] += " " + Value | |
1116 | return BuildOptions | |
1117 | ||
1118 | Platform = property(_GetPlatform) | |
1119 | Name = property(_GetName) | |
1120 | Guid = property(_GetGuid) | |
1121 | Version = property(_GetVersion) | |
1122 | ||
1123 | OutputDir = property(_GetOutputDir) | |
1124 | BuildDir = property(_GetBuildDir) | |
1125 | MakeFileDir = property(_GetMakeFileDir) | |
1126 | FdfFile = property(_GetFdfFile) | |
1127 | ||
1128 | PcdTokenNumber = property(_GetPcdTokenNumbers) # (TokenCName, TokenSpaceGuidCName) : GeneratedTokenNumber | |
1129 | DynamicPcdList = property(_GetDynamicPcdList) # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...] | |
1130 | NonDynamicPcdList = property(_GetNonDynamicPcdList) # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...] | |
1131 | PackageList = property(_GetPackageList) | |
1132 | ||
1133 | ToolDefinition = property(_GetToolDefinition) # toolcode : tool path | |
1134 | ToolDefinitionFile = property(_GetToolDefFile) # toolcode : lib path | |
1135 | ToolChainFamily = property(_GetToolChainFamily) | |
1136 | BuildRuleFamily = property(_GetBuildRuleFamily) | |
1137 | BuildOption = property(_GetBuildOptions) # toolcode : option | |
1138 | ||
1139 | BuildCommand = property(_GetBuildCommand) | |
1140 | BuildRule = property(_GetBuildRule) | |
1141 | ModuleAutoGenList = property(_GetModuleAutoGenList) | |
1142 | LibraryAutoGenList = property(_GetLibraryAutoGenList) | |
1143 | ||
1144 | ## ModuleAutoGen class | |
1145 | # | |
1146 | # This class encapsules the AutoGen behaviors for the build tools. In addition to | |
1147 | # the generation of AutoGen.h and AutoGen.c, it will generate *.depex file according | |
1148 | # to the [depex] section in module's inf file. | |
1149 | # | |
1150 | class ModuleAutoGen(AutoGen): | |
1151 | ## The real constructor of ModuleAutoGen | |
1152 | # | |
1153 | # This method is not supposed to be called by users of ModuleAutoGen. It's | |
1154 | # only used by factory method __new__() to do real initialization work for an | |
1155 | # object of ModuleAutoGen | |
1156 | # | |
1157 | # @param Workspace EdkIIWorkspaceBuild object | |
1158 | # @param ModuleFile The path of module file | |
1159 | # @param Target Build target (DEBUG, RELEASE) | |
1160 | # @param Toolchain Name of tool chain | |
1161 | # @param Arch The arch the module supports | |
1162 | # @param PlatformFile Platform meta-file | |
1163 | # | |
1164 | def _Init(self, Workspace, ModuleFile, Target, Toolchain, Arch, PlatformFile): | |
1165 | EdkLogger.debug(EdkLogger.DEBUG_9, "AutoGen module [%s] [%s]" % (ModuleFile, Arch)) | |
1166 | GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (ModuleFile, Arch, Toolchain, Target) | |
1167 | ||
1168 | self.Workspace = Workspace | |
1169 | self.WorkspaceDir = Workspace.WorkspaceDir | |
1170 | ||
1171 | self.MetaFile = ModuleFile | |
1172 | self.PlatformInfo = PlatformAutoGen(Workspace, PlatformFile, Target, Toolchain, Arch) | |
1173 | # check if this module is employed by active platform | |
1174 | if not self.PlatformInfo.ValidModule(self.MetaFile): | |
1175 | EdkLogger.verbose("Module [%s] for [%s] is not employed by active platform\n" \ | |
1176 | % (self.MetaFile, Arch)) | |
1177 | return False | |
1178 | ||
1179 | self.SourceDir = self.MetaFile.SubDir | |
1180 | self.SourceOverrideDir = None | |
1181 | # use overrided path defined in DSC file | |
1182 | if self.MetaFile.Key in GlobalData.gOverrideDir: | |
1183 | self.SourceOverrideDir = GlobalData.gOverrideDir[self.MetaFile.Key] | |
1184 | ||
1185 | self.ToolChain = Toolchain | |
1186 | self.BuildTarget = Target | |
1187 | self.Arch = Arch | |
1188 | self.ToolChainFamily = self.PlatformInfo.ToolChainFamily | |
1189 | self.BuildRuleFamily = self.PlatformInfo.BuildRuleFamily | |
1190 | ||
1191 | self.IsMakeFileCreated = False | |
1192 | self.IsCodeFileCreated = False | |
1193 | ||
1194 | self.BuildDatabase = self.Workspace.BuildDatabase | |
1195 | ||
1196 | self._Module = None | |
1197 | self._Name = None | |
1198 | self._Guid = None | |
1199 | self._Version = None | |
1200 | self._ModuleType = None | |
1201 | self._ComponentType = None | |
1202 | self._PcdIsDriver = None | |
1203 | self._AutoGenVersion = None | |
1204 | self._LibraryFlag = None | |
1205 | self._CustomMakefile = None | |
1206 | self._Macro = None | |
1207 | ||
1208 | self._BuildDir = None | |
1209 | self._OutputDir = None | |
1210 | self._DebugDir = None | |
1211 | self._MakeFileDir = None | |
1212 | ||
1213 | self._IncludePathList = None | |
1214 | self._AutoGenFileList = None | |
1215 | self._UnicodeFileList = None | |
1216 | self._SourceFileList = None | |
1217 | self._ObjectFileList = None | |
1218 | self._BinaryFileList = None | |
1219 | ||
1220 | self._DependentPackageList = None | |
1221 | self._DependentLibraryList = None | |
1222 | self._LibraryAutoGenList = None | |
1223 | self._DerivedPackageList = None | |
1224 | self._ModulePcdList = None | |
1225 | self._LibraryPcdList = None | |
1226 | self._GuidList = None | |
1227 | self._ProtocolList = None | |
1228 | self._PpiList = None | |
1229 | self._DepexList = None | |
1230 | self._BuildOption = None | |
1231 | self._BuildTargets = None | |
1232 | self._IntroBuildTargetList = None | |
1233 | self._FinalBuildTargetList = None | |
1234 | self._FileTypes = None | |
1235 | self._BuildRules = None | |
1236 | ||
1237 | return True | |
1238 | ||
1239 | def __repr__(self): | |
1240 | return "%s [%s]" % (self.MetaFile, self.Arch) | |
1241 | ||
1242 | # Macros could be used in build_rule.txt (also Makefile) | |
1243 | def _GetMacros(self): | |
1244 | if self._Macro == None: | |
1245 | self._Macro = sdict() | |
1246 | self._Macro["WORKSPACE" ] = self.WorkspaceDir | |
1247 | self._Macro["MODULE_NAME" ] = self.Name | |
1248 | self._Macro["MODULE_GUID" ] = self.Guid | |
1249 | self._Macro["MODULE_VERSION" ] = self.Version | |
1250 | self._Macro["MODULE_TYPE" ] = self.ModuleType | |
1251 | self._Macro["MODULE_FILE" ] = str(self.MetaFile) | |
1252 | self._Macro["MODULE_FILE_BASE_NAME" ] = self.MetaFile.BaseName | |
1253 | self._Macro["MODULE_RELATIVE_DIR" ] = self.SourceDir | |
1254 | self._Macro["MODULE_DIR" ] = self.SourceDir | |
1255 | ||
1256 | self._Macro["BASE_NAME" ] = self.Name | |
1257 | ||
1258 | self._Macro["ARCH" ] = self.Arch | |
1259 | self._Macro["TOOLCHAIN" ] = self.ToolChain | |
1260 | self._Macro["TOOLCHAIN_TAG" ] = self.ToolChain | |
1261 | self._Macro["TARGET" ] = self.BuildTarget | |
1262 | ||
1263 | self._Macro["BUILD_DIR" ] = self.PlatformInfo.BuildDir | |
1264 | self._Macro["BIN_DIR" ] = os.path.join(self.PlatformInfo.BuildDir, self.Arch) | |
1265 | self._Macro["LIB_DIR" ] = os.path.join(self.PlatformInfo.BuildDir, self.Arch) | |
1266 | self._Macro["MODULE_BUILD_DIR" ] = self.BuildDir | |
1267 | self._Macro["OUTPUT_DIR" ] = self.OutputDir | |
1268 | self._Macro["DEBUG_DIR" ] = self.DebugDir | |
1269 | return self._Macro | |
1270 | ||
1271 | ## Return the module build data object | |
1272 | def _GetModule(self): | |
1273 | if self._Module == None: | |
1274 | self._Module = self.Workspace.BuildDatabase[self.MetaFile, self.Arch] | |
1275 | return self._Module | |
1276 | ||
1277 | ## Return the module name | |
1278 | def _GetBaseName(self): | |
1279 | return self.Module.BaseName | |
1280 | ||
1281 | ## Return the module SourceOverridePath | |
1282 | def _GetSourceOverridePath(self): | |
1283 | return self.Module.SourceOverridePath | |
1284 | ||
1285 | ## Return the module meta-file GUID | |
1286 | def _GetGuid(self): | |
1287 | return self.Module.Guid | |
1288 | ||
1289 | ## Return the module version | |
1290 | def _GetVersion(self): | |
1291 | return self.Module.Version | |
1292 | ||
1293 | ## Return the module type | |
1294 | def _GetModuleType(self): | |
1295 | return self.Module.ModuleType | |
1296 | ||
1297 | ## Return the component type (for R8.x style of module) | |
1298 | def _GetComponentType(self): | |
1299 | return self.Module.ComponentType | |
1300 | ||
1301 | ## Return the build type | |
1302 | def _GetBuildType(self): | |
1303 | return self.Module.BuildType | |
1304 | ||
1305 | ## Return the PCD_IS_DRIVER setting | |
1306 | def _GetPcdIsDriver(self): | |
1307 | return self.Module.PcdIsDriver | |
1308 | ||
1309 | ## Return the autogen version, i.e. module meta-file version | |
1310 | def _GetAutoGenVersion(self): | |
1311 | return self.Module.AutoGenVersion | |
1312 | ||
1313 | ## Check if the module is library or not | |
1314 | def _IsLibrary(self): | |
1315 | if self._LibraryFlag == None: | |
1316 | if self.Module.LibraryClass != None and self.Module.LibraryClass != []: | |
1317 | self._LibraryFlag = True | |
1318 | else: | |
1319 | self._LibraryFlag = False | |
1320 | return self._LibraryFlag | |
1321 | ||
1322 | ## Return the directory to store intermediate files of the module | |
1323 | def _GetBuildDir(self): | |
1324 | if self._BuildDir == None: | |
1325 | self._BuildDir = path.join( | |
1326 | self.PlatformInfo.BuildDir, | |
1327 | self.Arch, | |
1328 | self.SourceDir, | |
1329 | self.MetaFile.BaseName | |
1330 | ) | |
1331 | CreateDirectory(self._BuildDir) | |
1332 | return self._BuildDir | |
1333 | ||
1334 | ## Return the directory to store the intermediate object files of the mdoule | |
1335 | def _GetOutputDir(self): | |
1336 | if self._OutputDir == None: | |
1337 | self._OutputDir = path.join(self.BuildDir, "OUTPUT") | |
1338 | CreateDirectory(self._OutputDir) | |
1339 | return self._OutputDir | |
1340 | ||
1341 | ## Return the directory to store auto-gened source files of the mdoule | |
1342 | def _GetDebugDir(self): | |
1343 | if self._DebugDir == None: | |
1344 | self._DebugDir = path.join(self.BuildDir, "DEBUG") | |
1345 | CreateDirectory(self._DebugDir) | |
1346 | return self._DebugDir | |
1347 | ||
1348 | ## Return the path of custom file | |
1349 | def _GetCustomMakefile(self): | |
1350 | if self._CustomMakefile == None: | |
1351 | self._CustomMakefile = {} | |
1352 | for Type in self.Module.CustomMakefile: | |
1353 | if Type in gMakeTypeMap: | |
1354 | MakeType = gMakeTypeMap[Type] | |
1355 | else: | |
1356 | MakeType = 'nmake' | |
1357 | if self.SourceOverrideDir != None: | |
1358 | File = os.path.join(self.SourceOverrideDir, self.Module.CustomMakefile[Type]) | |
1359 | if not os.path.exists(File): | |
1360 | File = os.path.join(self.SourceDir, self.Module.CustomMakefile[Type]) | |
1361 | else: | |
1362 | File = os.path.join(self.SourceDir, self.Module.CustomMakefile[Type]) | |
1363 | self._CustomMakefile[MakeType] = File | |
1364 | return self._CustomMakefile | |
1365 | ||
1366 | ## Return the directory of the makefile | |
1367 | # | |
1368 | # @retval string The directory string of module's makefile | |
1369 | # | |
1370 | def _GetMakeFileDir(self): | |
1371 | return self.BuildDir | |
1372 | ||
1373 | ## Return build command string | |
1374 | # | |
1375 | # @retval string Build command string | |
1376 | # | |
1377 | def _GetBuildCommand(self): | |
1378 | return self.PlatformInfo.BuildCommand | |
1379 | ||
1380 | ## Get object list of all packages the module and its dependent libraries belong to | |
1381 | # | |
1382 | # @retval list The list of package object | |
1383 | # | |
1384 | def _GetDerivedPackageList(self): | |
1385 | PackageList = [] | |
1386 | for M in [self.Module] + self.DependentLibraryList: | |
1387 | for Package in M.Packages: | |
1388 | if Package in PackageList: | |
1389 | continue | |
1390 | PackageList.append(Package) | |
1391 | return PackageList | |
1392 | ||
1393 | ## Merge dependency expression | |
1394 | # | |
1395 | # @retval list The token list of the dependency expression after parsed | |
1396 | # | |
1397 | def _GetDepexTokenList(self): | |
1398 | if self._DepexList == None: | |
1399 | self._DepexList = {} | |
1400 | if self.IsLibrary or TAB_DEPENDENCY_EXPRESSION_FILE in self.FileTypes: | |
1401 | return self._DepexList | |
1402 | ||
1403 | if self.ModuleType == "DXE_SMM_DRIVER": | |
1404 | self._DepexList["DXE_DRIVER"] = [] | |
1405 | self._DepexList["SMM_DRIVER"] = [] | |
1406 | else: | |
1407 | self._DepexList[self.ModuleType] = [] | |
1408 | ||
1409 | for ModuleType in self._DepexList: | |
1410 | DepexList = self._DepexList[ModuleType] | |
1411 | # | |
1412 | # Append depex from dependent libraries, if not "BEFORE", "AFTER" expresion | |
1413 | # | |
1414 | for M in [self.Module] + self.DependentLibraryList: | |
1415 | Inherited = False | |
1416 | for D in M.Depex[self.Arch, ModuleType]: | |
1417 | if DepexList != []: | |
1418 | DepexList.append('AND') | |
1419 | DepexList.append('(') | |
1420 | DepexList.extend(D) | |
1421 | if DepexList[-1] == 'END': # no need of a END at this time | |
1422 | DepexList.pop() | |
1423 | DepexList.append(')') | |
1424 | Inherited = True | |
1425 | if Inherited: | |
1426 | EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.BaseName, DepexList)) | |
1427 | if 'BEFORE' in DepexList or 'AFTER' in DepexList: | |
1428 | break | |
1429 | if len(DepexList) > 0: | |
1430 | EdkLogger.verbose('') | |
1431 | return self._DepexList | |
1432 | ||
1433 | ## Return the list of specification version required for the module | |
1434 | # | |
1435 | # @retval list The list of specification defined in module file | |
1436 | # | |
1437 | def _GetSpecification(self): | |
1438 | return self.Module.Specification | |
1439 | ||
1440 | ## Tool option for the module build | |
1441 | # | |
1442 | # @param PlatformInfo The object of PlatformBuildInfo | |
1443 | # @retval dict The dict containing valid options | |
1444 | # | |
1445 | def _GetModuleBuildOption(self): | |
1446 | if self._BuildOption == None: | |
1447 | self._BuildOption = self.PlatformInfo.ApplyBuildOption(self.Module) | |
1448 | return self._BuildOption | |
1449 | ||
1450 | ## Return a list of files which can be built from source | |
1451 | # | |
1452 | # What kind of files can be built is determined by build rules in | |
1453 | # $(WORKSPACE)/Conf/build_rule.txt and toolchain family. | |
1454 | # | |
1455 | def _GetSourceFileList(self): | |
1456 | if self._SourceFileList == None: | |
1457 | self._SourceFileList = [] | |
1458 | for F in self.Module.Sources: | |
1459 | # match tool chain | |
1460 | if F.TagName != "" and F.TagName != self.ToolChain: | |
1461 | EdkLogger.debug(EdkLogger.DEBUG_9, "The toolchain [%s] for processing file [%s] is found, " | |
1462 | "but [%s] is needed" % (F.TagName, str(F), self.ToolChain)) | |
1463 | continue | |
1464 | # match tool chain family | |
1465 | if F.ToolChainFamily != "" and F.ToolChainFamily != self.ToolChainFamily: | |
1466 | EdkLogger.debug( | |
1467 | EdkLogger.DEBUG_0, | |
1468 | "The file [%s] must be built by tools of [%s], " \ | |
1469 | "but current toolchain family is [%s]" \ | |
1470 | % (str(F), F.ToolChainFamily, self.ToolChainFamily)) | |
1471 | continue | |
1472 | ||
1473 | # add the file path into search path list for file including | |
1474 | if F.Dir not in self.IncludePathList and self.AutoGenVersion >= 0x00010005: | |
1475 | self.IncludePathList.insert(0, F.Dir) | |
1476 | self._SourceFileList.append(F) | |
1477 | self._ApplyBuildRule(F, TAB_UNKNOWN_FILE) | |
1478 | return self._SourceFileList | |
1479 | ||
1480 | ## Return the list of unicode files | |
1481 | def _GetUnicodeFileList(self): | |
1482 | if self._UnicodeFileList == None: | |
1483 | if TAB_UNICODE_FILE in self.FileTypes: | |
1484 | self._UnicodeFileList = self.FileTypes[TAB_UNICODE_FILE] | |
1485 | else: | |
1486 | self._UnicodeFileList = [] | |
1487 | return self._UnicodeFileList | |
1488 | ||
1489 | ## Return a list of files which can be built from binary | |
1490 | # | |
1491 | # "Build" binary files are just to copy them to build directory. | |
1492 | # | |
1493 | # @retval list The list of files which can be built later | |
1494 | # | |
1495 | def _GetBinaryFiles(self): | |
1496 | if self._BinaryFileList == None: | |
1497 | self._BinaryFileList = [] | |
1498 | for F in self.Module.Binaries: | |
1499 | if F.Target not in ['COMMON', '*'] and F.Target != self.BuildTarget: | |
1500 | continue | |
1501 | self._BinaryFileList.append(F) | |
1502 | self._ApplyBuildRule(F, F.Type) | |
1503 | return self._BinaryFileList | |
1504 | ||
1505 | def _GetBuildRules(self): | |
1506 | if self._BuildRules == None: | |
1507 | BuildRules = {} | |
1508 | BuildRuleDatabase = self.PlatformInfo.BuildRule | |
1509 | for Type in BuildRuleDatabase.FileTypeList: | |
1510 | #first try getting build rule by BuildRuleFamily | |
1511 | RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.BuildRuleFamily] | |
1512 | if not RuleObject: | |
1513 | # build type is always module type, but ... | |
1514 | if self.ModuleType != self.BuildType: | |
1515 | RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.BuildRuleFamily] | |
1516 | #second try getting build rule by ToolChainFamily | |
1517 | if not RuleObject: | |
1518 | RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.ToolChainFamily] | |
1519 | if not RuleObject: | |
1520 | # build type is always module type, but ... | |
1521 | if self.ModuleType != self.BuildType: | |
1522 | RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.ToolChainFamily] | |
1523 | if not RuleObject: | |
1524 | continue | |
1525 | RuleObject = RuleObject.Instantiate(self.Macros) | |
1526 | BuildRules[Type] = RuleObject | |
1527 | for Ext in RuleObject.SourceFileExtList: | |
1528 | BuildRules[Ext] = RuleObject | |
1529 | self._BuildRules = BuildRules | |
1530 | return self._BuildRules | |
1531 | ||
1532 | def _ApplyBuildRule(self, File, FileType): | |
1533 | if self._BuildTargets == None: | |
1534 | self._IntroBuildTargetList = set() | |
1535 | self._FinalBuildTargetList = set() | |
1536 | self._BuildTargets = {} | |
1537 | self._FileTypes = {} | |
1538 | ||
1539 | LastTarget = None | |
1540 | RuleChain = [] | |
1541 | SourceList = [File] | |
1542 | Index = 0 | |
1543 | while Index < len(SourceList): | |
1544 | Source = SourceList[Index] | |
1545 | Index = Index + 1 | |
1546 | ||
1547 | if Source != File: | |
1548 | CreateDirectory(Source.Dir) | |
1549 | ||
1550 | if FileType in self.BuildRules: | |
1551 | RuleObject = self.BuildRules[FileType] | |
1552 | elif Source.Ext in self.BuildRules: | |
1553 | RuleObject = self.BuildRules[Source.Ext] | |
1554 | elif File.IsBinary and File == Source: | |
1555 | RuleObject = self.BuildRules[TAB_DEFAULT_BINARY_FILE] | |
1556 | else: | |
1557 | # stop at no more rules | |
1558 | if LastTarget: | |
1559 | self._FinalBuildTargetList.add(LastTarget) | |
1560 | break | |
1561 | ||
1562 | FileType = RuleObject.SourceFileType | |
1563 | if FileType not in self._FileTypes: | |
1564 | self._FileTypes[FileType] = set() | |
1565 | self._FileTypes[FileType].add(Source) | |
1566 | ||
1567 | # stop at STATIC_LIBRARY for library | |
1568 | if self.IsLibrary and FileType == TAB_STATIC_LIBRARY: | |
1569 | self._FinalBuildTargetList.add(LastTarget) | |
1570 | break | |
1571 | ||
1572 | Target = RuleObject.Apply(Source) | |
1573 | if not Target: | |
1574 | if LastTarget: | |
1575 | self._FinalBuildTargetList.add(LastTarget) | |
1576 | break | |
1577 | elif not Target.Outputs: | |
1578 | # Only do build for target with outputs | |
1579 | self._FinalBuildTargetList.add(Target) | |
1580 | ||
1581 | if FileType not in self._BuildTargets: | |
1582 | self._BuildTargets[FileType] = set() | |
1583 | self._BuildTargets[FileType].add(Target) | |
1584 | ||
1585 | if not Source.IsBinary and Source == File: | |
1586 | self._IntroBuildTargetList.add(Target) | |
1587 | ||
1588 | # to avoid cyclic rule | |
1589 | if FileType in RuleChain: | |
1590 | break | |
1591 | ||
1592 | RuleChain.append(FileType) | |
1593 | SourceList.extend(Target.Outputs) | |
1594 | LastTarget = Target | |
1595 | FileType = TAB_UNKNOWN_FILE | |
1596 | ||
1597 | def _GetTargets(self): | |
1598 | if self._BuildTargets == None: | |
1599 | self._IntroBuildTargetList = set() | |
1600 | self._FinalBuildTargetList = set() | |
1601 | self._BuildTargets = {} | |
1602 | self._FileTypes = {} | |
1603 | ||
1604 | #TRICK: call _GetSourceFileList to apply build rule for binary files | |
1605 | if self.SourceFileList: | |
1606 | pass | |
1607 | ||
1608 | #TRICK: call _GetBinaryFileList to apply build rule for binary files | |
1609 | if self.BinaryFileList: | |
1610 | pass | |
1611 | ||
1612 | return self._BuildTargets | |
1613 | ||
1614 | def _GetIntroTargetList(self): | |
1615 | self._GetTargets() | |
1616 | return self._IntroBuildTargetList | |
1617 | ||
1618 | def _GetFinalTargetList(self): | |
1619 | self._GetTargets() | |
1620 | return self._FinalBuildTargetList | |
1621 | ||
1622 | def _GetFileTypes(self): | |
1623 | self._GetTargets() | |
1624 | return self._FileTypes | |
1625 | ||
1626 | ## Get the list of package object the module depends on | |
1627 | # | |
1628 | # @retval list The package object list | |
1629 | # | |
1630 | def _GetDependentPackageList(self): | |
1631 | return self.Module.Packages | |
1632 | ||
1633 | ## Return the list of auto-generated code file | |
1634 | # | |
1635 | # @retval list The list of auto-generated file | |
1636 | # | |
1637 | def _GetAutoGenFileList(self): | |
1638 | if self._AutoGenFileList == None: | |
1639 | self._AutoGenFileList = {} | |
1640 | AutoGenC = TemplateString() | |
1641 | AutoGenH = TemplateString() | |
1642 | StringH = TemplateString() | |
1643 | GenC.CreateCode(self, AutoGenC, AutoGenH, StringH) | |
1644 | if str(AutoGenC) != "" and TAB_C_CODE_FILE in self.FileTypes: | |
1645 | AutoFile = PathClass(gAutoGenCodeFileName, self.DebugDir) | |
1646 | self._AutoGenFileList[AutoFile] = str(AutoGenC) | |
1647 | self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE) | |
1648 | if str(AutoGenH) != "": | |
1649 | AutoFile = PathClass(gAutoGenHeaderFileName, self.DebugDir) | |
1650 | self._AutoGenFileList[AutoFile] = str(AutoGenH) | |
1651 | self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE) | |
1652 | if str(StringH) != "": | |
1653 | AutoFile = PathClass(gAutoGenStringFileName % {"module_name":self.Name}, self.DebugDir) | |
1654 | self._AutoGenFileList[AutoFile] = str(StringH) | |
1655 | self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE) | |
1656 | return self._AutoGenFileList | |
1657 | ||
1658 | ## Return the list of library modules explicitly or implicityly used by this module | |
1659 | def _GetLibraryList(self): | |
1660 | if self._DependentLibraryList == None: | |
1661 | # only merge library classes and PCD for non-library module | |
1662 | if self.IsLibrary: | |
1663 | self._DependentLibraryList = [] | |
1664 | else: | |
1665 | if self.AutoGenVersion < 0x00010005: | |
1666 | self._DependentLibraryList = self.PlatformInfo.ResolveLibraryReference(self.Module) | |
1667 | else: | |
1668 | self._DependentLibraryList = self.PlatformInfo.ApplyLibraryInstance(self.Module) | |
1669 | return self._DependentLibraryList | |
1670 | ||
1671 | ## Get the list of PCDs from current module | |
1672 | # | |
1673 | # @retval list The list of PCD | |
1674 | # | |
1675 | def _GetModulePcdList(self): | |
1676 | if self._ModulePcdList == None: | |
1677 | # apply PCD settings from platform | |
1678 | self._ModulePcdList = self.PlatformInfo.ApplyPcdSetting(self.Module, self.Module.Pcds) | |
1679 | return self._ModulePcdList | |
1680 | ||
1681 | ## Get the list of PCDs from dependent libraries | |
1682 | # | |
1683 | # @retval list The list of PCD | |
1684 | # | |
1685 | def _GetLibraryPcdList(self): | |
1686 | if self._LibraryPcdList == None: | |
1687 | Pcds = {} | |
1688 | if not self.IsLibrary: | |
1689 | # get PCDs from dependent libraries | |
1690 | for Library in self.DependentLibraryList: | |
1691 | for Key in Library.Pcds: | |
1692 | # skip duplicated PCDs | |
1693 | if Key in self.Module.Pcds or Key in Pcds: | |
1694 | continue | |
1695 | Pcds[Key] = copy.copy(Library.Pcds[Key]) | |
1696 | # apply PCD settings from platform | |
1697 | self._LibraryPcdList = self.PlatformInfo.ApplyPcdSetting(self.Module, Pcds) | |
1698 | else: | |
1699 | self._LibraryPcdList = [] | |
1700 | return self._LibraryPcdList | |
1701 | ||
1702 | ## Get the GUID value mapping | |
1703 | # | |
1704 | # @retval dict The mapping between GUID cname and its value | |
1705 | # | |
1706 | def _GetGuidList(self): | |
1707 | if self._GuidList == None: | |
1708 | self._GuidList = self.Module.Guids | |
1709 | for Library in self.DependentLibraryList: | |
1710 | self._GuidList.update(Library.Guids) | |
1711 | return self._GuidList | |
1712 | ||
1713 | ## Get the protocol value mapping | |
1714 | # | |
1715 | # @retval dict The mapping between protocol cname and its value | |
1716 | # | |
1717 | def _GetProtocolList(self): | |
1718 | if self._ProtocolList == None: | |
1719 | self._ProtocolList = self.Module.Protocols | |
1720 | for Library in self.DependentLibraryList: | |
1721 | self._ProtocolList.update(Library.Protocols) | |
1722 | return self._ProtocolList | |
1723 | ||
1724 | ## Get the PPI value mapping | |
1725 | # | |
1726 | # @retval dict The mapping between PPI cname and its value | |
1727 | # | |
1728 | def _GetPpiList(self): | |
1729 | if self._PpiList == None: | |
1730 | self._PpiList = self.Module.Ppis | |
1731 | for Library in self.DependentLibraryList: | |
1732 | self._PpiList.update(Library.Ppis) | |
1733 | return self._PpiList | |
1734 | ||
1735 | ## Get the list of include search path | |
1736 | # | |
1737 | # @retval list The list path | |
1738 | # | |
1739 | def _GetIncludePathList(self): | |
1740 | if self._IncludePathList == None: | |
1741 | self._IncludePathList = [] | |
1742 | if self.AutoGenVersion < 0x00010005: | |
1743 | for Inc in self.Module.Includes: | |
1744 | if Inc not in self._IncludePathList: | |
1745 | self._IncludePathList.append(Inc) | |
1746 | # for r8 modules | |
1747 | Inc = path.join(Inc, self.Arch.capitalize()) | |
1748 | if os.path.exists(Inc) and Inc not in self._IncludePathList: | |
1749 | self._IncludePathList.append(Inc) | |
1750 | # r8 module needs to put DEBUG_DIR at the end of search path and not to use SOURCE_DIR all the time | |
1751 | self._IncludePathList.append(self.DebugDir) | |
1752 | else: | |
1753 | self._IncludePathList.append(self.MetaFile.Dir) | |
1754 | self._IncludePathList.append(self.DebugDir) | |
1755 | ||
1756 | for Package in self.Module.Packages: | |
1757 | PackageDir = path.join(self.WorkspaceDir, Package.MetaFile.Dir) | |
1758 | if PackageDir not in self._IncludePathList: | |
1759 | self._IncludePathList.append(PackageDir) | |
1760 | for Inc in Package.Includes: | |
1761 | if Inc not in self._IncludePathList: | |
1762 | self._IncludePathList.append(str(Inc)) | |
1763 | return self._IncludePathList | |
1764 | ||
1765 | ## Create makefile for the module and its dependent libraries | |
1766 | # | |
1767 | # @param CreateLibraryMakeFile Flag indicating if or not the makefiles of | |
1768 | # dependent libraries will be created | |
1769 | # | |
1770 | def CreateMakeFile(self, CreateLibraryMakeFile=True): | |
1771 | if self.IsMakeFileCreated: | |
1772 | return | |
1773 | ||
1774 | if not self.IsLibrary and CreateLibraryMakeFile: | |
1775 | for LibraryAutoGen in self.LibraryAutoGenList: | |
1776 | LibraryAutoGen.CreateMakeFile() | |
1777 | ||
1778 | if len(self.CustomMakefile) == 0: | |
1779 | Makefile = GenMake.ModuleMakefile(self) | |
1780 | else: | |
1781 | Makefile = GenMake.CustomMakefile(self) | |
1782 | if Makefile.Generate(): | |
1783 | EdkLogger.debug(EdkLogger.DEBUG_9, "Generated makefile for module %s [%s]" % | |
1784 | (self.Name, self.Arch)) | |
1785 | else: | |
1786 | EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of makefile for module %s [%s]" % | |
1787 | (self.Name, self.Arch)) | |
1788 | ||
1789 | self.IsMakeFileCreated = True | |
1790 | ||
1791 | ## Create autogen code for the module and its dependent libraries | |
1792 | # | |
1793 | # @param CreateLibraryCodeFile Flag indicating if or not the code of | |
1794 | # dependent libraries will be created | |
1795 | # | |
1796 | def CreateCodeFile(self, CreateLibraryCodeFile=True): | |
1797 | if self.IsCodeFileCreated: | |
1798 | return | |
1799 | ||
1800 | if not self.IsLibrary and CreateLibraryCodeFile: | |
1801 | for LibraryAutoGen in self.LibraryAutoGenList: | |
1802 | LibraryAutoGen.CreateCodeFile() | |
1803 | ||
1804 | AutoGenList = [] | |
1805 | IgoredAutoGenList = [] | |
1806 | ||
1807 | for File in self.AutoGenFileList: | |
1808 | if GenC.Generate(File.Path, self.AutoGenFileList[File]): | |
1809 | #Ignore R8 AutoGen.c | |
1810 | if self.AutoGenVersion < 0x00010005 and File.Name == 'AutoGen.c': | |
1811 | continue | |
1812 | ||
1813 | AutoGenList.append(str(File)) | |
1814 | else: | |
1815 | IgoredAutoGenList.append(str(File)) | |
1816 | ||
1817 | for ModuleType in self.DepexList: | |
1818 | if len(self.DepexList[ModuleType]) == 0: | |
1819 | continue | |
1820 | Dpx = GenDepex.DependencyExpression(self.DepexList[ModuleType], ModuleType, True) | |
1821 | if ModuleType == 'SMM_DRIVER': | |
1822 | DpxFile = gAutoGenSmmDepexFileName % {"module_name" : self.Name} | |
1823 | else: | |
1824 | DpxFile = gAutoGenDepexFileName % {"module_name" : self.Name} | |
1825 | ||
1826 | if Dpx.Generate(path.join(self.OutputDir, DpxFile)): | |
1827 | AutoGenList.append(str(DpxFile)) | |
1828 | else: | |
1829 | IgoredAutoGenList.append(str(DpxFile)) | |
1830 | ||
1831 | if IgoredAutoGenList == []: | |
1832 | EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] files for module %s [%s]" % | |
1833 | (" ".join(AutoGenList), self.Name, self.Arch)) | |
1834 | elif AutoGenList == []: | |
1835 | EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of [%s] files for module %s [%s]" % | |
1836 | (" ".join(IgoredAutoGenList), self.Name, self.Arch)) | |
1837 | else: | |
1838 | EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] (skipped %s) files for module %s [%s]" % | |
1839 | (" ".join(AutoGenList), " ".join(IgoredAutoGenList), self.Name, self.Arch)) | |
1840 | ||
1841 | self.IsCodeFileCreated = True | |
1842 | return AutoGenList | |
1843 | ||
1844 | ## Summarize the ModuleAutoGen objects of all libraries used by this module | |
1845 | def _GetLibraryAutoGenList(self): | |
1846 | if self._LibraryAutoGenList == None: | |
1847 | self._LibraryAutoGenList = [] | |
1848 | for Library in self.DependentLibraryList: | |
1849 | La = ModuleAutoGen( | |
1850 | self.Workspace, | |
1851 | Library.MetaFile, | |
1852 | self.BuildTarget, | |
1853 | self.ToolChain, | |
1854 | self.Arch, | |
1855 | self.PlatformInfo.MetaFile | |
1856 | ) | |
1857 | if La not in self._LibraryAutoGenList: | |
1858 | self._LibraryAutoGenList.append(La) | |
1859 | for Lib in La.CodaTargetList: | |
1860 | self._ApplyBuildRule(Lib.Target, TAB_UNKNOWN_FILE) | |
1861 | return self._LibraryAutoGenList | |
1862 | ||
1863 | ## Return build command string | |
1864 | # | |
1865 | # @retval string Build command string | |
1866 | # | |
1867 | def _GetBuildCommand(self): | |
1868 | return self.PlatformInfo.BuildCommand | |
1869 | ||
1870 | ||
1871 | Module = property(_GetModule) | |
1872 | Name = property(_GetBaseName) | |
1873 | Guid = property(_GetGuid) | |
1874 | Version = property(_GetVersion) | |
1875 | ModuleType = property(_GetModuleType) | |
1876 | ComponentType = property(_GetComponentType) | |
1877 | BuildType = property(_GetBuildType) | |
1878 | PcdIsDriver = property(_GetPcdIsDriver) | |
1879 | AutoGenVersion = property(_GetAutoGenVersion) | |
1880 | Macros = property(_GetMacros) | |
1881 | Specification = property(_GetSpecification) | |
1882 | ||
1883 | IsLibrary = property(_IsLibrary) | |
1884 | ||
1885 | BuildDir = property(_GetBuildDir) | |
1886 | OutputDir = property(_GetOutputDir) | |
1887 | DebugDir = property(_GetDebugDir) | |
1888 | MakeFileDir = property(_GetMakeFileDir) | |
1889 | CustomMakefile = property(_GetCustomMakefile) | |
1890 | ||
1891 | IncludePathList = property(_GetIncludePathList) | |
1892 | AutoGenFileList = property(_GetAutoGenFileList) | |
1893 | UnicodeFileList = property(_GetUnicodeFileList) | |
1894 | SourceFileList = property(_GetSourceFileList) | |
1895 | BinaryFileList = property(_GetBinaryFiles) # FileType : [File List] | |
1896 | Targets = property(_GetTargets) | |
1897 | IntroTargetList = property(_GetIntroTargetList) | |
1898 | CodaTargetList = property(_GetFinalTargetList) | |
1899 | FileTypes = property(_GetFileTypes) | |
1900 | BuildRules = property(_GetBuildRules) | |
1901 | ||
1902 | DependentPackageList = property(_GetDependentPackageList) | |
1903 | DependentLibraryList = property(_GetLibraryList) | |
1904 | LibraryAutoGenList = property(_GetLibraryAutoGenList) | |
1905 | DerivedPackageList = property(_GetDerivedPackageList) | |
1906 | ||
1907 | ModulePcdList = property(_GetModulePcdList) | |
1908 | LibraryPcdList = property(_GetLibraryPcdList) | |
1909 | GuidList = property(_GetGuidList) | |
1910 | ProtocolList = property(_GetProtocolList) | |
1911 | PpiList = property(_GetPpiList) | |
1912 | DepexList = property(_GetDepexTokenList) | |
1913 | BuildOption = property(_GetModuleBuildOption) | |
1914 | BuildCommand = property(_GetBuildCommand) | |
1915 | ||
1916 | # This acts like the main() function for the script, unless it is 'import'ed into another script. | |
1917 | if __name__ == '__main__': | |
1918 | pass | |
1919 |