]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/AutoGen/ModuleAutoGen.py
MdeModulePkg/DxeIplPeim: Relocate operation of PageMapLevel5Entry++
[mirror_edk2.git] / BaseTools / Source / Python / AutoGen / ModuleAutoGen.py
CommitLineData
e8449e1d
FB
1## @file\r
2# Create makefile for MS nmake and GNU make\r
3#\r
4# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
5# SPDX-License-Identifier: BSD-2-Clause-Patent\r
6#\r
7from __future__ import absolute_import\r
8from AutoGen.AutoGen import AutoGen\r
9from Common.LongFilePathSupport import CopyLongFilePath\r
10from Common.BuildToolError import *\r
11from Common.DataType import *\r
12from Common.Misc import *\r
13from Common.StringUtils import NormPath,GetSplitList\r
14from collections import defaultdict\r
15from Workspace.WorkspaceCommon import OrderedListDict\r
16import os.path as path\r
17import copy\r
18import hashlib\r
19from . import InfSectionParser\r
20from . import GenC\r
21from . import GenMake\r
22from . import GenDepex\r
23from io import BytesIO\r
24from GenPatchPcdTable.GenPatchPcdTable import parsePcdInfoFromMapFile\r
25from Workspace.MetaFileCommentParser import UsageList\r
26from .GenPcdDb import CreatePcdDatabaseCode\r
27from Common.caching import cached_class_function\r
28from AutoGen.ModuleAutoGenHelper import PlatformInfo,WorkSpaceInfo\r
29\r
30## Mapping Makefile type\r
31gMakeTypeMap = {TAB_COMPILER_MSFT:"nmake", "GCC":"gmake"}\r
32#\r
33# Regular expression for finding Include Directories, the difference between MSFT and INTEL/GCC/RVCT\r
34# is the former use /I , the Latter used -I to specify include directories\r
35#\r
36gBuildOptIncludePatternMsft = re.compile(r"(?:.*?)/I[ \t]*([^ ]*)", re.MULTILINE | re.DOTALL)\r
37gBuildOptIncludePatternOther = re.compile(r"(?:.*?)-I[ \t]*([^ ]*)", re.MULTILINE | re.DOTALL)\r
38\r
39## default file name for AutoGen\r
40gAutoGenCodeFileName = "AutoGen.c"\r
41gAutoGenHeaderFileName = "AutoGen.h"\r
42gAutoGenStringFileName = "%(module_name)sStrDefs.h"\r
43gAutoGenStringFormFileName = "%(module_name)sStrDefs.hpk"\r
44gAutoGenDepexFileName = "%(module_name)s.depex"\r
45gAutoGenImageDefFileName = "%(module_name)sImgDefs.h"\r
46gAutoGenIdfFileName = "%(module_name)sIdf.hpk"\r
47gInfSpecVersion = "0x00010017"\r
48\r
49#\r
50# Match name = variable\r
51#\r
52gEfiVarStoreNamePattern = re.compile("\s*name\s*=\s*(\w+)")\r
53#\r
54# The format of guid in efivarstore statement likes following and must be correct:\r
55# guid = {0xA04A27f4, 0xDF00, 0x4D42, {0xB5, 0x52, 0x39, 0x51, 0x13, 0x02, 0x11, 0x3D}}\r
56#\r
57gEfiVarStoreGuidPattern = re.compile("\s*guid\s*=\s*({.*?{.*?}\s*})")\r
58\r
59#\r
60# Template string to generic AsBuilt INF\r
61#\r
62gAsBuiltInfHeaderString = TemplateString("""${header_comments}\r
63\r
64# DO NOT EDIT\r
65# FILE auto-generated\r
66\r
67[Defines]\r
68 INF_VERSION = ${module_inf_version}\r
69 BASE_NAME = ${module_name}\r
70 FILE_GUID = ${module_guid}\r
71 MODULE_TYPE = ${module_module_type}${BEGIN}\r
72 VERSION_STRING = ${module_version_string}${END}${BEGIN}\r
73 PCD_IS_DRIVER = ${pcd_is_driver_string}${END}${BEGIN}\r
74 UEFI_SPECIFICATION_VERSION = ${module_uefi_specification_version}${END}${BEGIN}\r
75 PI_SPECIFICATION_VERSION = ${module_pi_specification_version}${END}${BEGIN}\r
76 ENTRY_POINT = ${module_entry_point}${END}${BEGIN}\r
77 UNLOAD_IMAGE = ${module_unload_image}${END}${BEGIN}\r
78 CONSTRUCTOR = ${module_constructor}${END}${BEGIN}\r
79 DESTRUCTOR = ${module_destructor}${END}${BEGIN}\r
80 SHADOW = ${module_shadow}${END}${BEGIN}\r
81 PCI_VENDOR_ID = ${module_pci_vendor_id}${END}${BEGIN}\r
82 PCI_DEVICE_ID = ${module_pci_device_id}${END}${BEGIN}\r
83 PCI_CLASS_CODE = ${module_pci_class_code}${END}${BEGIN}\r
84 PCI_REVISION = ${module_pci_revision}${END}${BEGIN}\r
85 BUILD_NUMBER = ${module_build_number}${END}${BEGIN}\r
86 SPEC = ${module_spec}${END}${BEGIN}\r
87 UEFI_HII_RESOURCE_SECTION = ${module_uefi_hii_resource_section}${END}${BEGIN}\r
88 MODULE_UNI_FILE = ${module_uni_file}${END}\r
89\r
90[Packages.${module_arch}]${BEGIN}\r
91 ${package_item}${END}\r
92\r
93[Binaries.${module_arch}]${BEGIN}\r
94 ${binary_item}${END}\r
95\r
96[PatchPcd.${module_arch}]${BEGIN}\r
97 ${patchablepcd_item}\r
98${END}\r
99\r
100[Protocols.${module_arch}]${BEGIN}\r
101 ${protocol_item}\r
102${END}\r
103\r
104[Ppis.${module_arch}]${BEGIN}\r
105 ${ppi_item}\r
106${END}\r
107\r
108[Guids.${module_arch}]${BEGIN}\r
109 ${guid_item}\r
110${END}\r
111\r
112[PcdEx.${module_arch}]${BEGIN}\r
113 ${pcd_item}\r
114${END}\r
115\r
116[LibraryClasses.${module_arch}]\r
117## @LIB_INSTANCES${BEGIN}\r
118# ${libraryclasses_item}${END}\r
119\r
120${depexsection_item}\r
121\r
122${userextension_tianocore_item}\r
123\r
124${tail_comments}\r
125\r
126[BuildOptions.${module_arch}]\r
127## @AsBuilt${BEGIN}\r
128## ${flags_item}${END}\r
129""")\r
130#\r
131# extend lists contained in a dictionary with lists stored in another dictionary\r
132# if CopyToDict is not derived from DefaultDict(list) then this may raise exception\r
133#\r
134def ExtendCopyDictionaryLists(CopyToDict, CopyFromDict):\r
135 for Key in CopyFromDict:\r
136 CopyToDict[Key].extend(CopyFromDict[Key])\r
137\r
138# Create a directory specified by a set of path elements and return the full path\r
139def _MakeDir(PathList):\r
140 RetVal = path.join(*PathList)\r
141 CreateDirectory(RetVal)\r
142 return RetVal\r
143\r
144#\r
145# Convert string to C format array\r
146#\r
147def _ConvertStringToByteArray(Value):\r
148 Value = Value.strip()\r
149 if not Value:\r
150 return None\r
151 if Value[0] == '{':\r
152 if not Value.endswith('}'):\r
153 return None\r
154 Value = Value.replace(' ', '').replace('{', '').replace('}', '')\r
155 ValFields = Value.split(',')\r
156 try:\r
157 for Index in range(len(ValFields)):\r
158 ValFields[Index] = str(int(ValFields[Index], 0))\r
159 except ValueError:\r
160 return None\r
161 Value = '{' + ','.join(ValFields) + '}'\r
162 return Value\r
163\r
164 Unicode = False\r
165 if Value.startswith('L"'):\r
166 if not Value.endswith('"'):\r
167 return None\r
168 Value = Value[1:]\r
169 Unicode = True\r
170 elif not Value.startswith('"') or not Value.endswith('"'):\r
171 return None\r
172\r
173 Value = eval(Value) # translate escape character\r
174 NewValue = '{'\r
175 for Index in range(0, len(Value)):\r
176 if Unicode:\r
177 NewValue = NewValue + str(ord(Value[Index]) % 0x10000) + ','\r
178 else:\r
179 NewValue = NewValue + str(ord(Value[Index]) % 0x100) + ','\r
180 Value = NewValue + '0}'\r
181 return Value\r
182\r
183## ModuleAutoGen class\r
184#\r
185# This class encapsules the AutoGen behaviors for the build tools. In addition to\r
186# the generation of AutoGen.h and AutoGen.c, it will generate *.depex file according\r
187# to the [depex] section in module's inf file.\r
188#\r
189class ModuleAutoGen(AutoGen):\r
190 # call super().__init__ then call the worker function with different parameter count\r
191 def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):\r
192 if not hasattr(self, "_Init"):\r
193 self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch, *args)\r
194 self._Init = True\r
195\r
196 ## Cache the timestamps of metafiles of every module in a class attribute\r
197 #\r
198 TimeDict = {}\r
199\r
200 def __new__(cls, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):\r
201# check if this module is employed by active platform\r
202 if not PlatformInfo(Workspace, args[0], Target, Toolchain, Arch,args[-1]).ValidModule(MetaFile):\r
203 EdkLogger.verbose("Module [%s] for [%s] is not employed by active platform\n" \\r
204 % (MetaFile, Arch))\r
205 return None\r
206 return super(ModuleAutoGen, cls).__new__(cls, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)\r
207\r
208 ## Initialize ModuleAutoGen\r
209 #\r
210 # @param Workspace EdkIIWorkspaceBuild object\r
211 # @param ModuleFile The path of module file\r
212 # @param Target Build target (DEBUG, RELEASE)\r
213 # @param Toolchain Name of tool chain\r
214 # @param Arch The arch the module supports\r
215 # @param PlatformFile Platform meta-file\r
216 #\r
217 def _InitWorker(self, Workspace, ModuleFile, Target, Toolchain, Arch, PlatformFile,DataPipe):\r
218 EdkLogger.debug(EdkLogger.DEBUG_9, "AutoGen module [%s] [%s]" % (ModuleFile, Arch))\r
219 GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (ModuleFile, Arch, Toolchain, Target)\r
220\r
221 self.Workspace = None\r
222 self.WorkspaceDir = ""\r
223 self.PlatformInfo = None\r
224 self.DataPipe = DataPipe\r
225 self.__init_platform_info__()\r
226 self.MetaFile = ModuleFile\r
227 self.SourceDir = self.MetaFile.SubDir\r
228 self.SourceDir = mws.relpath(self.SourceDir, self.WorkspaceDir)\r
229\r
230 self.ToolChain = Toolchain\r
231 self.BuildTarget = Target\r
232 self.Arch = Arch\r
233 self.ToolChainFamily = self.PlatformInfo.ToolChainFamily\r
234 self.BuildRuleFamily = self.PlatformInfo.BuildRuleFamily\r
235\r
236 self.IsCodeFileCreated = False\r
237 self.IsAsBuiltInfCreated = False\r
238 self.DepexGenerated = False\r
239\r
240 self.BuildDatabase = self.Workspace.BuildDatabase\r
241 self.BuildRuleOrder = None\r
242 self.BuildTime = 0\r
243\r
244 self._GuidComments = OrderedListDict()\r
245 self._ProtocolComments = OrderedListDict()\r
246 self._PpiComments = OrderedListDict()\r
247 self._BuildTargets = None\r
248 self._IntroBuildTargetList = None\r
249 self._FinalBuildTargetList = None\r
250 self._FileTypes = None\r
251\r
252 self.AutoGenDepSet = set()\r
253 self.ReferenceModules = []\r
254 self.ConstPcd = {}\r
255\r
256 def __init_platform_info__(self):\r
257 pinfo = self.DataPipe.Get("P_Info")\r
258 self.Workspace = WorkSpaceInfo(pinfo.get("WorkspaceDir"),pinfo.get("ActivePlatform"),pinfo.get("Target"),pinfo.get("ToolChain"),pinfo.get("ArchList"))\r
259 self.WorkspaceDir = pinfo.get("WorkspaceDir")\r
260 self.PlatformInfo = PlatformInfo(self.Workspace,pinfo.get("ActivePlatform"),pinfo.get("Target"),pinfo.get("ToolChain"),pinfo.get("Arch"),self.DataPipe)\r
261 ## hash() operator of ModuleAutoGen\r
262 #\r
263 # The module file path and arch string will be used to represent\r
264 # hash value of this object\r
265 #\r
266 # @retval int Hash value of the module file path and arch\r
267 #\r
268 @cached_class_function\r
269 def __hash__(self):\r
270 return hash((self.MetaFile, self.Arch))\r
271 def __repr__(self):\r
272 return "%s [%s]" % (self.MetaFile, self.Arch)\r
273\r
274 # Get FixedAtBuild Pcds of this Module\r
275 @cached_property\r
276 def FixedAtBuildPcds(self):\r
277 RetVal = []\r
278 for Pcd in self.ModulePcdList:\r
279 if Pcd.Type != TAB_PCDS_FIXED_AT_BUILD:\r
280 continue\r
281 if Pcd not in RetVal:\r
282 RetVal.append(Pcd)\r
283 return RetVal\r
284\r
285 @cached_property\r
286 def FixedVoidTypePcds(self):\r
287 RetVal = {}\r
288 for Pcd in self.FixedAtBuildPcds:\r
289 if Pcd.DatumType == TAB_VOID:\r
290 if '.'.join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName)) not in RetVal:\r
291 RetVal['.'.join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))] = Pcd.DefaultValue\r
292 return RetVal\r
293\r
294 @property\r
295 def UniqueBaseName(self):\r
296 ModuleNames = self.DataPipe.Get("M_Name")\r
297 if not ModuleNames:\r
298 return self.Name\r
299 return ModuleNames.get(self.Name,self.Name)\r
300\r
301 # Macros could be used in build_rule.txt (also Makefile)\r
302 @cached_property\r
303 def Macros(self):\r
304 return OrderedDict((\r
305 ("WORKSPACE" ,self.WorkspaceDir),\r
306 ("MODULE_NAME" ,self.Name),\r
307 ("MODULE_NAME_GUID" ,self.UniqueBaseName),\r
308 ("MODULE_GUID" ,self.Guid),\r
309 ("MODULE_VERSION" ,self.Version),\r
310 ("MODULE_TYPE" ,self.ModuleType),\r
311 ("MODULE_FILE" ,str(self.MetaFile)),\r
312 ("MODULE_FILE_BASE_NAME" ,self.MetaFile.BaseName),\r
313 ("MODULE_RELATIVE_DIR" ,self.SourceDir),\r
314 ("MODULE_DIR" ,self.SourceDir),\r
315 ("BASE_NAME" ,self.Name),\r
316 ("ARCH" ,self.Arch),\r
317 ("TOOLCHAIN" ,self.ToolChain),\r
318 ("TOOLCHAIN_TAG" ,self.ToolChain),\r
319 ("TOOL_CHAIN_TAG" ,self.ToolChain),\r
320 ("TARGET" ,self.BuildTarget),\r
321 ("BUILD_DIR" ,self.PlatformInfo.BuildDir),\r
322 ("BIN_DIR" ,os.path.join(self.PlatformInfo.BuildDir, self.Arch)),\r
323 ("LIB_DIR" ,os.path.join(self.PlatformInfo.BuildDir, self.Arch)),\r
324 ("MODULE_BUILD_DIR" ,self.BuildDir),\r
325 ("OUTPUT_DIR" ,self.OutputDir),\r
326 ("DEBUG_DIR" ,self.DebugDir),\r
327 ("DEST_DIR_OUTPUT" ,self.OutputDir),\r
328 ("DEST_DIR_DEBUG" ,self.DebugDir),\r
329 ("PLATFORM_NAME" ,self.PlatformInfo.Name),\r
330 ("PLATFORM_GUID" ,self.PlatformInfo.Guid),\r
331 ("PLATFORM_VERSION" ,self.PlatformInfo.Version),\r
332 ("PLATFORM_RELATIVE_DIR" ,self.PlatformInfo.SourceDir),\r
333 ("PLATFORM_DIR" ,mws.join(self.WorkspaceDir, self.PlatformInfo.SourceDir)),\r
334 ("PLATFORM_OUTPUT_DIR" ,self.PlatformInfo.OutputDir),\r
335 ("FFS_OUTPUT_DIR" ,self.FfsOutputDir)\r
336 ))\r
337\r
338 ## Return the module build data object\r
339 @cached_property\r
340 def Module(self):\r
341 return self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]\r
342\r
343 ## Return the module name\r
344 @cached_property\r
345 def Name(self):\r
346 return self.Module.BaseName\r
347\r
348 ## Return the module DxsFile if exist\r
349 @cached_property\r
350 def DxsFile(self):\r
351 return self.Module.DxsFile\r
352\r
353 ## Return the module meta-file GUID\r
354 @cached_property\r
355 def Guid(self):\r
356 #\r
357 # To build same module more than once, the module path with FILE_GUID overridden has\r
358 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path\r
359 # in DSC. The overridden GUID can be retrieved from file name\r
360 #\r
361 if os.path.basename(self.MetaFile.File) != os.path.basename(self.MetaFile.Path):\r
362 #\r
363 # Length of GUID is 36\r
364 #\r
365 return os.path.basename(self.MetaFile.Path)[:36]\r
366 return self.Module.Guid\r
367\r
368 ## Return the module version\r
369 @cached_property\r
370 def Version(self):\r
371 return self.Module.Version\r
372\r
373 ## Return the module type\r
374 @cached_property\r
375 def ModuleType(self):\r
376 return self.Module.ModuleType\r
377\r
378 ## Return the component type (for Edk.x style of module)\r
379 @cached_property\r
380 def ComponentType(self):\r
381 return self.Module.ComponentType\r
382\r
383 ## Return the build type\r
384 @cached_property\r
385 def BuildType(self):\r
386 return self.Module.BuildType\r
387\r
388 ## Return the PCD_IS_DRIVER setting\r
389 @cached_property\r
390 def PcdIsDriver(self):\r
391 return self.Module.PcdIsDriver\r
392\r
393 ## Return the autogen version, i.e. module meta-file version\r
394 @cached_property\r
395 def AutoGenVersion(self):\r
396 return self.Module.AutoGenVersion\r
397\r
398 ## Check if the module is library or not\r
399 @cached_property\r
400 def IsLibrary(self):\r
401 return bool(self.Module.LibraryClass)\r
402\r
403 ## Check if the module is binary module or not\r
404 @cached_property\r
405 def IsBinaryModule(self):\r
406 return self.Module.IsBinaryModule\r
407\r
408 ## Return the directory to store intermediate files of the module\r
409 @cached_property\r
410 def BuildDir(self):\r
411 return _MakeDir((\r
412 self.PlatformInfo.BuildDir,\r
413 self.Arch,\r
414 self.SourceDir,\r
415 self.MetaFile.BaseName\r
416 ))\r
417\r
418 ## Return the directory to store the intermediate object files of the module\r
419 @cached_property\r
420 def OutputDir(self):\r
421 return _MakeDir((self.BuildDir, "OUTPUT"))\r
422\r
423 ## Return the directory path to store ffs file\r
424 @cached_property\r
425 def FfsOutputDir(self):\r
426 if GlobalData.gFdfParser:\r
427 return path.join(self.PlatformInfo.BuildDir, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name)\r
428 return ''\r
429\r
430 ## Return the directory to store auto-gened source files of the module\r
431 @cached_property\r
432 def DebugDir(self):\r
433 return _MakeDir((self.BuildDir, "DEBUG"))\r
434\r
435 ## Return the path of custom file\r
436 @cached_property\r
437 def CustomMakefile(self):\r
438 RetVal = {}\r
439 for Type in self.Module.CustomMakefile:\r
440 MakeType = gMakeTypeMap[Type] if Type in gMakeTypeMap else 'nmake'\r
441 File = os.path.join(self.SourceDir, self.Module.CustomMakefile[Type])\r
442 RetVal[MakeType] = File\r
443 return RetVal\r
444\r
445 ## Return the directory of the makefile\r
446 #\r
447 # @retval string The directory string of module's makefile\r
448 #\r
449 @cached_property\r
450 def MakeFileDir(self):\r
451 return self.BuildDir\r
452\r
453 ## Return build command string\r
454 #\r
455 # @retval string Build command string\r
456 #\r
457 @cached_property\r
458 def BuildCommand(self):\r
459 return self.PlatformInfo.BuildCommand\r
460\r
461 ## Get object list of all packages the module and its dependent libraries belong to\r
462 #\r
463 # @retval list The list of package object\r
464 #\r
465 @cached_property\r
466 def DerivedPackageList(self):\r
467 PackageList = []\r
468 for M in [self.Module] + self.DependentLibraryList:\r
469 for Package in M.Packages:\r
470 if Package in PackageList:\r
471 continue\r
472 PackageList.append(Package)\r
473 return PackageList\r
474\r
475 ## Get the depex string\r
476 #\r
477 # @return : a string contain all depex expression.\r
478 def _GetDepexExpresionString(self):\r
479 DepexStr = ''\r
480 DepexList = []\r
481 ## DPX_SOURCE IN Define section.\r
482 if self.Module.DxsFile:\r
483 return DepexStr\r
484 for M in [self.Module] + self.DependentLibraryList:\r
485 Filename = M.MetaFile.Path\r
486 InfObj = InfSectionParser.InfSectionParser(Filename)\r
487 DepexExpressionList = InfObj.GetDepexExpresionList()\r
488 for DepexExpression in DepexExpressionList:\r
489 for key in DepexExpression:\r
490 Arch, ModuleType = key\r
491 DepexExpr = [x for x in DepexExpression[key] if not str(x).startswith('#')]\r
492 # the type of build module is USER_DEFINED.\r
493 # All different DEPEX section tags would be copied into the As Built INF file\r
494 # and there would be separate DEPEX section tags\r
495 if self.ModuleType.upper() == SUP_MODULE_USER_DEFINED or self.ModuleType.upper() == SUP_MODULE_HOST_APPLICATION:\r
496 if (Arch.upper() == self.Arch.upper()) and (ModuleType.upper() != TAB_ARCH_COMMON):\r
497 DepexList.append({(Arch, ModuleType): DepexExpr})\r
498 else:\r
499 if Arch.upper() == TAB_ARCH_COMMON or \\r
500 (Arch.upper() == self.Arch.upper() and \\r
501 ModuleType.upper() in [TAB_ARCH_COMMON, self.ModuleType.upper()]):\r
502 DepexList.append({(Arch, ModuleType): DepexExpr})\r
503\r
504 #the type of build module is USER_DEFINED.\r
505 if self.ModuleType.upper() == SUP_MODULE_USER_DEFINED or self.ModuleType.upper() == SUP_MODULE_HOST_APPLICATION:\r
506 for Depex in DepexList:\r
507 for key in Depex:\r
508 DepexStr += '[Depex.%s.%s]\n' % key\r
509 DepexStr += '\n'.join('# '+ val for val in Depex[key])\r
510 DepexStr += '\n\n'\r
511 if not DepexStr:\r
512 return '[Depex.%s]\n' % self.Arch\r
513 return DepexStr\r
514\r
515 #the type of build module not is USER_DEFINED.\r
516 Count = 0\r
517 for Depex in DepexList:\r
518 Count += 1\r
519 if DepexStr != '':\r
520 DepexStr += ' AND '\r
521 DepexStr += '('\r
522 for D in Depex.values():\r
523 DepexStr += ' '.join(val for val in D)\r
524 Index = DepexStr.find('END')\r
525 if Index > -1 and Index == len(DepexStr) - 3:\r
526 DepexStr = DepexStr[:-3]\r
527 DepexStr = DepexStr.strip()\r
528 DepexStr += ')'\r
529 if Count == 1:\r
530 DepexStr = DepexStr.lstrip('(').rstrip(')').strip()\r
531 if not DepexStr:\r
532 return '[Depex.%s]\n' % self.Arch\r
533 return '[Depex.%s]\n# ' % self.Arch + DepexStr\r
534\r
535 ## Merge dependency expression\r
536 #\r
537 # @retval list The token list of the dependency expression after parsed\r
538 #\r
539 @cached_property\r
540 def DepexList(self):\r
541 if self.DxsFile or self.IsLibrary or TAB_DEPENDENCY_EXPRESSION_FILE in self.FileTypes:\r
542 return {}\r
543\r
544 DepexList = []\r
545 #\r
546 # Append depex from dependent libraries, if not "BEFORE", "AFTER" expression\r
547 #\r
548 FixedVoidTypePcds = {}\r
549 for M in [self] + self.LibraryAutoGenList:\r
550 FixedVoidTypePcds.update(M.FixedVoidTypePcds)\r
551 for M in [self] + self.LibraryAutoGenList:\r
552 Inherited = False\r
553 for D in M.Module.Depex[self.Arch, self.ModuleType]:\r
554 if DepexList != []:\r
555 DepexList.append('AND')\r
556 DepexList.append('(')\r
557 #replace D with value if D is FixedAtBuild PCD\r
558 NewList = []\r
559 for item in D:\r
560 if '.' not in item:\r
561 NewList.append(item)\r
562 else:\r
563 try:\r
564 Value = FixedVoidTypePcds[item]\r
565 if len(Value.split(',')) != 16:\r
566 EdkLogger.error("build", FORMAT_INVALID,\r
567 "{} used in [Depex] section should be used as FixedAtBuild type and VOID* datum type and 16 bytes in the module.".format(item))\r
568 NewList.append(Value)\r
569 except:\r
570 EdkLogger.error("build", FORMAT_INVALID, "{} used in [Depex] section should be used as FixedAtBuild type and VOID* datum type in the module.".format(item))\r
571\r
572 DepexList.extend(NewList)\r
573 if DepexList[-1] == 'END': # no need of a END at this time\r
574 DepexList.pop()\r
575 DepexList.append(')')\r
576 Inherited = True\r
577 if Inherited:\r
578 EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.Module.BaseName, DepexList))\r
579 if 'BEFORE' in DepexList or 'AFTER' in DepexList:\r
580 break\r
581 if len(DepexList) > 0:\r
582 EdkLogger.verbose('')\r
583 return {self.ModuleType:DepexList}\r
584\r
585 ## Merge dependency expression\r
586 #\r
587 # @retval list The token list of the dependency expression after parsed\r
588 #\r
589 @cached_property\r
590 def DepexExpressionDict(self):\r
591 if self.DxsFile or self.IsLibrary or TAB_DEPENDENCY_EXPRESSION_FILE in self.FileTypes:\r
592 return {}\r
593\r
594 DepexExpressionString = ''\r
595 #\r
596 # Append depex from dependent libraries, if not "BEFORE", "AFTER" expresion\r
597 #\r
598 for M in [self.Module] + self.DependentLibraryList:\r
599 Inherited = False\r
600 for D in M.DepexExpression[self.Arch, self.ModuleType]:\r
601 if DepexExpressionString != '':\r
602 DepexExpressionString += ' AND '\r
603 DepexExpressionString += '('\r
604 DepexExpressionString += D\r
605 DepexExpressionString = DepexExpressionString.rstrip('END').strip()\r
606 DepexExpressionString += ')'\r
607 Inherited = True\r
608 if Inherited:\r
609 EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.BaseName, DepexExpressionString))\r
610 if 'BEFORE' in DepexExpressionString or 'AFTER' in DepexExpressionString:\r
611 break\r
612 if len(DepexExpressionString) > 0:\r
613 EdkLogger.verbose('')\r
614\r
615 return {self.ModuleType:DepexExpressionString}\r
616\r
617 # Get the tiano core user extension, it is contain dependent library.\r
618 # @retval: a list contain tiano core userextension.\r
619 #\r
620 def _GetTianoCoreUserExtensionList(self):\r
621 TianoCoreUserExtentionList = []\r
622 for M in [self.Module] + self.DependentLibraryList:\r
623 Filename = M.MetaFile.Path\r
624 InfObj = InfSectionParser.InfSectionParser(Filename)\r
625 TianoCoreUserExtenList = InfObj.GetUserExtensionTianoCore()\r
626 for TianoCoreUserExtent in TianoCoreUserExtenList:\r
627 for Section in TianoCoreUserExtent:\r
628 ItemList = Section.split(TAB_SPLIT)\r
629 Arch = self.Arch\r
630 if len(ItemList) == 4:\r
631 Arch = ItemList[3]\r
632 if Arch.upper() == TAB_ARCH_COMMON or Arch.upper() == self.Arch.upper():\r
633 TianoCoreList = []\r
634 TianoCoreList.extend([TAB_SECTION_START + Section + TAB_SECTION_END])\r
635 TianoCoreList.extend(TianoCoreUserExtent[Section][:])\r
636 TianoCoreList.append('\n')\r
637 TianoCoreUserExtentionList.append(TianoCoreList)\r
638\r
639 return TianoCoreUserExtentionList\r
640\r
641 ## Return the list of specification version required for the module\r
642 #\r
643 # @retval list The list of specification defined in module file\r
644 #\r
645 @cached_property\r
646 def Specification(self):\r
647 return self.Module.Specification\r
648\r
649 ## Tool option for the module build\r
650 #\r
651 # @param PlatformInfo The object of PlatformBuildInfo\r
652 # @retval dict The dict containing valid options\r
653 #\r
654 @cached_property\r
655 def BuildOption(self):\r
656 RetVal, self.BuildRuleOrder = self.PlatformInfo.ApplyBuildOption(self.Module)\r
657 if self.BuildRuleOrder:\r
658 self.BuildRuleOrder = ['.%s' % Ext for Ext in self.BuildRuleOrder.split()]\r
659 return RetVal\r
660\r
661 ## Get include path list from tool option for the module build\r
662 #\r
663 # @retval list The include path list\r
664 #\r
665 @cached_property\r
666 def BuildOptionIncPathList(self):\r
667 #\r
668 # Regular expression for finding Include Directories, the difference between MSFT and INTEL/GCC/RVCT\r
669 # is the former use /I , the Latter used -I to specify include directories\r
670 #\r
671 if self.PlatformInfo.ToolChainFamily in (TAB_COMPILER_MSFT):\r
672 BuildOptIncludeRegEx = gBuildOptIncludePatternMsft\r
673 elif self.PlatformInfo.ToolChainFamily in ('INTEL', 'GCC', 'RVCT'):\r
674 BuildOptIncludeRegEx = gBuildOptIncludePatternOther\r
675 else:\r
676 #\r
677 # New ToolChainFamily, don't known whether there is option to specify include directories\r
678 #\r
679 return []\r
680\r
681 RetVal = []\r
682 for Tool in ('CC', 'PP', 'VFRPP', 'ASLPP', 'ASLCC', 'APP', 'ASM'):\r
683 try:\r
684 FlagOption = self.BuildOption[Tool]['FLAGS']\r
685 except KeyError:\r
686 FlagOption = ''\r
687\r
688 if self.ToolChainFamily != 'RVCT':\r
689 IncPathList = [NormPath(Path, self.Macros) for Path in BuildOptIncludeRegEx.findall(FlagOption)]\r
690 else:\r
691 #\r
692 # RVCT may specify a list of directory seperated by commas\r
693 #\r
694 IncPathList = []\r
695 for Path in BuildOptIncludeRegEx.findall(FlagOption):\r
696 PathList = GetSplitList(Path, TAB_COMMA_SPLIT)\r
697 IncPathList.extend(NormPath(PathEntry, self.Macros) for PathEntry in PathList)\r
698\r
699 #\r
700 # EDK II modules must not reference header files outside of the packages they depend on or\r
701 # within the module's directory tree. Report error if violation.\r
702 #\r
703 if GlobalData.gDisableIncludePathCheck == False:\r
704 for Path in IncPathList:\r
705 if (Path not in self.IncludePathList) and (CommonPath([Path, self.MetaFile.Dir]) != self.MetaFile.Dir):\r
706 ErrMsg = "The include directory for the EDK II module in this line is invalid %s specified in %s FLAGS '%s'" % (Path, Tool, FlagOption)\r
707 EdkLogger.error("build",\r
708 PARAMETER_INVALID,\r
709 ExtraData=ErrMsg,\r
710 File=str(self.MetaFile))\r
711 RetVal += IncPathList\r
712 return RetVal\r
713\r
714 ## Return a list of files which can be built from source\r
715 #\r
716 # What kind of files can be built is determined by build rules in\r
717 # $(CONF_DIRECTORY)/build_rule.txt and toolchain family.\r
718 #\r
719 @cached_property\r
720 def SourceFileList(self):\r
721 RetVal = []\r
722 ToolChainTagSet = {"", TAB_STAR, self.ToolChain}\r
723 ToolChainFamilySet = {"", TAB_STAR, self.ToolChainFamily, self.BuildRuleFamily}\r
724 for F in self.Module.Sources:\r
725 # match tool chain\r
726 if F.TagName not in ToolChainTagSet:\r
727 EdkLogger.debug(EdkLogger.DEBUG_9, "The toolchain [%s] for processing file [%s] is found, "\r
728 "but [%s] is currently used" % (F.TagName, str(F), self.ToolChain))\r
729 continue\r
730 # match tool chain family or build rule family\r
731 if F.ToolChainFamily not in ToolChainFamilySet:\r
732 EdkLogger.debug(\r
733 EdkLogger.DEBUG_0,\r
734 "The file [%s] must be built by tools of [%s], " \\r
735 "but current toolchain family is [%s], buildrule family is [%s]" \\r
736 % (str(F), F.ToolChainFamily, self.ToolChainFamily, self.BuildRuleFamily))\r
737 continue\r
738\r
739 # add the file path into search path list for file including\r
740 if F.Dir not in self.IncludePathList:\r
741 self.IncludePathList.insert(0, F.Dir)\r
742 RetVal.append(F)\r
743\r
744 self._MatchBuildRuleOrder(RetVal)\r
745\r
746 for F in RetVal:\r
747 self._ApplyBuildRule(F, TAB_UNKNOWN_FILE)\r
748 return RetVal\r
749\r
750 def _MatchBuildRuleOrder(self, FileList):\r
751 Order_Dict = {}\r
752 self.BuildOption\r
753 for SingleFile in FileList:\r
754 if self.BuildRuleOrder and SingleFile.Ext in self.BuildRuleOrder and SingleFile.Ext in self.BuildRules:\r
755 key = SingleFile.Path.rsplit(SingleFile.Ext,1)[0]\r
756 if key in Order_Dict:\r
757 Order_Dict[key].append(SingleFile.Ext)\r
758 else:\r
759 Order_Dict[key] = [SingleFile.Ext]\r
760\r
761 RemoveList = []\r
762 for F in Order_Dict:\r
763 if len(Order_Dict[F]) > 1:\r
764 Order_Dict[F].sort(key=lambda i: self.BuildRuleOrder.index(i))\r
765 for Ext in Order_Dict[F][1:]:\r
766 RemoveList.append(F + Ext)\r
767\r
768 for item in RemoveList:\r
769 FileList.remove(item)\r
770\r
771 return FileList\r
772\r
773 ## Return the list of unicode files\r
774 @cached_property\r
775 def UnicodeFileList(self):\r
776 return self.FileTypes.get(TAB_UNICODE_FILE,[])\r
777\r
778 ## Return the list of vfr files\r
779 @cached_property\r
780 def VfrFileList(self):\r
781 return self.FileTypes.get(TAB_VFR_FILE, [])\r
782\r
783 ## Return the list of Image Definition files\r
784 @cached_property\r
785 def IdfFileList(self):\r
786 return self.FileTypes.get(TAB_IMAGE_FILE,[])\r
787\r
788 ## Return a list of files which can be built from binary\r
789 #\r
790 # "Build" binary files are just to copy them to build directory.\r
791 #\r
792 # @retval list The list of files which can be built later\r
793 #\r
794 @cached_property\r
795 def BinaryFileList(self):\r
796 RetVal = []\r
797 for F in self.Module.Binaries:\r
798 if F.Target not in [TAB_ARCH_COMMON, TAB_STAR] and F.Target != self.BuildTarget:\r
799 continue\r
800 RetVal.append(F)\r
801 self._ApplyBuildRule(F, F.Type, BinaryFileList=RetVal)\r
802 return RetVal\r
803\r
804 @cached_property\r
805 def BuildRules(self):\r
806 RetVal = {}\r
807 BuildRuleDatabase = self.PlatformInfo.BuildRule\r
808 for Type in BuildRuleDatabase.FileTypeList:\r
809 #first try getting build rule by BuildRuleFamily\r
810 RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.BuildRuleFamily]\r
811 if not RuleObject:\r
812 # build type is always module type, but ...\r
813 if self.ModuleType != self.BuildType:\r
814 RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.BuildRuleFamily]\r
815 #second try getting build rule by ToolChainFamily\r
816 if not RuleObject:\r
817 RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.ToolChainFamily]\r
818 if not RuleObject:\r
819 # build type is always module type, but ...\r
820 if self.ModuleType != self.BuildType:\r
821 RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.ToolChainFamily]\r
822 if not RuleObject:\r
823 continue\r
824 RuleObject = RuleObject.Instantiate(self.Macros)\r
825 RetVal[Type] = RuleObject\r
826 for Ext in RuleObject.SourceFileExtList:\r
827 RetVal[Ext] = RuleObject\r
828 return RetVal\r
829\r
830 def _ApplyBuildRule(self, File, FileType, BinaryFileList=None):\r
831 if self._BuildTargets is None:\r
832 self._IntroBuildTargetList = set()\r
833 self._FinalBuildTargetList = set()\r
834 self._BuildTargets = defaultdict(set)\r
835 self._FileTypes = defaultdict(set)\r
836\r
837 if not BinaryFileList:\r
838 BinaryFileList = self.BinaryFileList\r
839\r
840 SubDirectory = os.path.join(self.OutputDir, File.SubDir)\r
841 if not os.path.exists(SubDirectory):\r
842 CreateDirectory(SubDirectory)\r
843 LastTarget = None\r
844 RuleChain = set()\r
845 SourceList = [File]\r
846 Index = 0\r
847 #\r
848 # Make sure to get build rule order value\r
849 #\r
850 self.BuildOption\r
851\r
852 while Index < len(SourceList):\r
853 Source = SourceList[Index]\r
854 Index = Index + 1\r
855\r
856 if Source != File:\r
857 CreateDirectory(Source.Dir)\r
858\r
859 if File.IsBinary and File == Source and File in BinaryFileList:\r
860 # Skip all files that are not binary libraries\r
861 if not self.IsLibrary:\r
862 continue\r
863 RuleObject = self.BuildRules[TAB_DEFAULT_BINARY_FILE]\r
864 elif FileType in self.BuildRules:\r
865 RuleObject = self.BuildRules[FileType]\r
866 elif Source.Ext in self.BuildRules:\r
867 RuleObject = self.BuildRules[Source.Ext]\r
868 else:\r
869 # stop at no more rules\r
870 if LastTarget:\r
871 self._FinalBuildTargetList.add(LastTarget)\r
872 break\r
873\r
874 FileType = RuleObject.SourceFileType\r
875 self._FileTypes[FileType].add(Source)\r
876\r
877 # stop at STATIC_LIBRARY for library\r
878 if self.IsLibrary and FileType == TAB_STATIC_LIBRARY:\r
879 if LastTarget:\r
880 self._FinalBuildTargetList.add(LastTarget)\r
881 break\r
882\r
883 Target = RuleObject.Apply(Source, self.BuildRuleOrder)\r
884 if not Target:\r
885 if LastTarget:\r
886 self._FinalBuildTargetList.add(LastTarget)\r
887 break\r
888 elif not Target.Outputs:\r
889 # Only do build for target with outputs\r
890 self._FinalBuildTargetList.add(Target)\r
891\r
892 self._BuildTargets[FileType].add(Target)\r
893\r
894 if not Source.IsBinary and Source == File:\r
895 self._IntroBuildTargetList.add(Target)\r
896\r
897 # to avoid cyclic rule\r
898 if FileType in RuleChain:\r
899 break\r
900\r
901 RuleChain.add(FileType)\r
902 SourceList.extend(Target.Outputs)\r
903 LastTarget = Target\r
904 FileType = TAB_UNKNOWN_FILE\r
905\r
906 @cached_property\r
907 def Targets(self):\r
908 if self._BuildTargets is None:\r
909 self._IntroBuildTargetList = set()\r
910 self._FinalBuildTargetList = set()\r
911 self._BuildTargets = defaultdict(set)\r
912 self._FileTypes = defaultdict(set)\r
913\r
914 #TRICK: call SourceFileList property to apply build rule for source files\r
915 self.SourceFileList\r
916\r
917 #TRICK: call _GetBinaryFileList to apply build rule for binary files\r
918 self.BinaryFileList\r
919\r
920 return self._BuildTargets\r
921\r
922 @cached_property\r
923 def IntroTargetList(self):\r
924 self.Targets\r
925 return self._IntroBuildTargetList\r
926\r
927 @cached_property\r
928 def CodaTargetList(self):\r
929 self.Targets\r
930 return self._FinalBuildTargetList\r
931\r
932 @cached_property\r
933 def FileTypes(self):\r
934 self.Targets\r
935 return self._FileTypes\r
936\r
937 ## Get the list of package object the module depends on\r
938 #\r
939 # @retval list The package object list\r
940 #\r
941 @cached_property\r
942 def DependentPackageList(self):\r
943 return self.Module.Packages\r
944\r
945 ## Return the list of auto-generated code file\r
946 #\r
947 # @retval list The list of auto-generated file\r
948 #\r
949 @cached_property\r
950 def AutoGenFileList(self):\r
951 AutoGenUniIdf = self.BuildType != 'UEFI_HII'\r
952 UniStringBinBuffer = BytesIO()\r
953 IdfGenBinBuffer = BytesIO()\r
954 RetVal = {}\r
955 AutoGenC = TemplateString()\r
956 AutoGenH = TemplateString()\r
957 StringH = TemplateString()\r
958 StringIdf = TemplateString()\r
959 GenC.CreateCode(self, AutoGenC, AutoGenH, StringH, AutoGenUniIdf, UniStringBinBuffer, StringIdf, AutoGenUniIdf, IdfGenBinBuffer)\r
960 #\r
961 # AutoGen.c is generated if there are library classes in inf, or there are object files\r
962 #\r
963 if str(AutoGenC) != "" and (len(self.Module.LibraryClasses) > 0\r
964 or TAB_OBJECT_FILE in self.FileTypes):\r
965 AutoFile = PathClass(gAutoGenCodeFileName, self.DebugDir)\r
966 RetVal[AutoFile] = str(AutoGenC)\r
967 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)\r
968 if str(AutoGenH) != "":\r
969 AutoFile = PathClass(gAutoGenHeaderFileName, self.DebugDir)\r
970 RetVal[AutoFile] = str(AutoGenH)\r
971 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)\r
972 if str(StringH) != "":\r
973 AutoFile = PathClass(gAutoGenStringFileName % {"module_name":self.Name}, self.DebugDir)\r
974 RetVal[AutoFile] = str(StringH)\r
975 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)\r
976 if UniStringBinBuffer is not None and UniStringBinBuffer.getvalue() != b"":\r
977 AutoFile = PathClass(gAutoGenStringFormFileName % {"module_name":self.Name}, self.OutputDir)\r
978 RetVal[AutoFile] = UniStringBinBuffer.getvalue()\r
979 AutoFile.IsBinary = True\r
980 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)\r
981 if UniStringBinBuffer is not None:\r
982 UniStringBinBuffer.close()\r
983 if str(StringIdf) != "":\r
984 AutoFile = PathClass(gAutoGenImageDefFileName % {"module_name":self.Name}, self.DebugDir)\r
985 RetVal[AutoFile] = str(StringIdf)\r
986 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)\r
987 if IdfGenBinBuffer is not None and IdfGenBinBuffer.getvalue() != b"":\r
988 AutoFile = PathClass(gAutoGenIdfFileName % {"module_name":self.Name}, self.OutputDir)\r
989 RetVal[AutoFile] = IdfGenBinBuffer.getvalue()\r
990 AutoFile.IsBinary = True\r
991 self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)\r
992 if IdfGenBinBuffer is not None:\r
993 IdfGenBinBuffer.close()\r
994 return RetVal\r
995\r
996 ## Return the list of library modules explicitly or implicitly used by this module\r
997 @cached_property\r
998 def DependentLibraryList(self):\r
999 # only merge library classes and PCD for non-library module\r
1000 if self.IsLibrary:\r
1001 return []\r
1002 return self.PlatformInfo.ApplyLibraryInstance(self.Module)\r
1003\r
1004 ## Get the list of PCDs from current module\r
1005 #\r
1006 # @retval list The list of PCD\r
1007 #\r
1008 @cached_property\r
1009 def ModulePcdList(self):\r
1010 # apply PCD settings from platform\r
1011 RetVal = self.PlatformInfo.ApplyPcdSetting(self.Module, self.Module.Pcds)\r
1012\r
1013 return RetVal\r
1014 @cached_property\r
1015 def _PcdComments(self):\r
1016 ReVal = OrderedListDict()\r
1017 ExtendCopyDictionaryLists(ReVal, self.Module.PcdComments)\r
1018 if not self.IsLibrary:\r
1019 for Library in self.DependentLibraryList:\r
1020 ExtendCopyDictionaryLists(ReVal, Library.PcdComments)\r
1021 return ReVal\r
1022\r
1023 ## Get the list of PCDs from dependent libraries\r
1024 #\r
1025 # @retval list The list of PCD\r
1026 #\r
1027 @cached_property\r
1028 def LibraryPcdList(self):\r
1029 if self.IsLibrary:\r
1030 return []\r
1031 RetVal = []\r
1032 Pcds = set()\r
1033 # get PCDs from dependent libraries\r
1034 for Library in self.DependentLibraryList:\r
1035 PcdsInLibrary = OrderedDict()\r
1036 for Key in Library.Pcds:\r
1037 # skip duplicated PCDs\r
1038 if Key in self.Module.Pcds or Key in Pcds:\r
1039 continue\r
1040 Pcds.add(Key)\r
1041 PcdsInLibrary[Key] = copy.copy(Library.Pcds[Key])\r
1042 RetVal.extend(self.PlatformInfo.ApplyPcdSetting(self.Module, PcdsInLibrary, Library=Library))\r
1043 return RetVal\r
1044\r
1045 ## Get the GUID value mapping\r
1046 #\r
1047 # @retval dict The mapping between GUID cname and its value\r
1048 #\r
1049 @cached_property\r
1050 def GuidList(self):\r
1051 RetVal = self.Module.Guids\r
1052 for Library in self.DependentLibraryList:\r
1053 RetVal.update(Library.Guids)\r
1054 ExtendCopyDictionaryLists(self._GuidComments, Library.GuidComments)\r
1055 ExtendCopyDictionaryLists(self._GuidComments, self.Module.GuidComments)\r
1056 return RetVal\r
1057\r
1058 @cached_property\r
1059 def GetGuidsUsedByPcd(self):\r
1060 RetVal = OrderedDict(self.Module.GetGuidsUsedByPcd())\r
1061 for Library in self.DependentLibraryList:\r
1062 RetVal.update(Library.GetGuidsUsedByPcd())\r
1063 return RetVal\r
1064 ## Get the protocol value mapping\r
1065 #\r
1066 # @retval dict The mapping between protocol cname and its value\r
1067 #\r
1068 @cached_property\r
1069 def ProtocolList(self):\r
1070 RetVal = OrderedDict(self.Module.Protocols)\r
1071 for Library in self.DependentLibraryList:\r
1072 RetVal.update(Library.Protocols)\r
1073 ExtendCopyDictionaryLists(self._ProtocolComments, Library.ProtocolComments)\r
1074 ExtendCopyDictionaryLists(self._ProtocolComments, self.Module.ProtocolComments)\r
1075 return RetVal\r
1076\r
1077 ## Get the PPI value mapping\r
1078 #\r
1079 # @retval dict The mapping between PPI cname and its value\r
1080 #\r
1081 @cached_property\r
1082 def PpiList(self):\r
1083 RetVal = OrderedDict(self.Module.Ppis)\r
1084 for Library in self.DependentLibraryList:\r
1085 RetVal.update(Library.Ppis)\r
1086 ExtendCopyDictionaryLists(self._PpiComments, Library.PpiComments)\r
1087 ExtendCopyDictionaryLists(self._PpiComments, self.Module.PpiComments)\r
1088 return RetVal\r
1089\r
1090 ## Get the list of include search path\r
1091 #\r
1092 # @retval list The list path\r
1093 #\r
1094 @cached_property\r
1095 def IncludePathList(self):\r
1096 RetVal = []\r
1097 RetVal.append(self.MetaFile.Dir)\r
1098 RetVal.append(self.DebugDir)\r
1099\r
1100 for Package in self.Module.Packages:\r
1101 PackageDir = mws.join(self.WorkspaceDir, Package.MetaFile.Dir)\r
1102 if PackageDir not in RetVal:\r
1103 RetVal.append(PackageDir)\r
1104 IncludesList = Package.Includes\r
1105 if Package._PrivateIncludes:\r
1106 if not self.MetaFile.OriginalPath.Path.startswith(PackageDir):\r
1107 IncludesList = list(set(Package.Includes).difference(set(Package._PrivateIncludes)))\r
1108 for Inc in IncludesList:\r
1109 if Inc not in RetVal:\r
1110 RetVal.append(str(Inc))\r
1111 return RetVal\r
1112\r
1113 @cached_property\r
1114 def IncludePathLength(self):\r
1115 return sum(len(inc)+1 for inc in self.IncludePathList)\r
1116\r
1117 ## Get HII EX PCDs which maybe used by VFR\r
1118 #\r
1119 # efivarstore used by VFR may relate with HII EX PCDs\r
1120 # Get the variable name and GUID from efivarstore and HII EX PCD\r
1121 # List the HII EX PCDs in As Built INF if both name and GUID match.\r
1122 #\r
1123 # @retval list HII EX PCDs\r
1124 #\r
1125 def _GetPcdsMaybeUsedByVfr(self):\r
1126 if not self.SourceFileList:\r
1127 return []\r
1128\r
1129 NameGuids = set()\r
1130 for SrcFile in self.SourceFileList:\r
1131 if SrcFile.Ext.lower() != '.vfr':\r
1132 continue\r
1133 Vfri = os.path.join(self.OutputDir, SrcFile.BaseName + '.i')\r
1134 if not os.path.exists(Vfri):\r
1135 continue\r
1136 VfriFile = open(Vfri, 'r')\r
1137 Content = VfriFile.read()\r
1138 VfriFile.close()\r
1139 Pos = Content.find('efivarstore')\r
1140 while Pos != -1:\r
1141 #\r
1142 # Make sure 'efivarstore' is the start of efivarstore statement\r
1143 # In case of the value of 'name' (name = efivarstore) is equal to 'efivarstore'\r
1144 #\r
1145 Index = Pos - 1\r
1146 while Index >= 0 and Content[Index] in ' \t\r\n':\r
1147 Index -= 1\r
1148 if Index >= 0 and Content[Index] != ';':\r
1149 Pos = Content.find('efivarstore', Pos + len('efivarstore'))\r
1150 continue\r
1151 #\r
1152 # 'efivarstore' must be followed by name and guid\r
1153 #\r
1154 Name = gEfiVarStoreNamePattern.search(Content, Pos)\r
1155 if not Name:\r
1156 break\r
1157 Guid = gEfiVarStoreGuidPattern.search(Content, Pos)\r
1158 if not Guid:\r
1159 break\r
1160 NameArray = _ConvertStringToByteArray('L"' + Name.group(1) + '"')\r
1161 NameGuids.add((NameArray, GuidStructureStringToGuidString(Guid.group(1))))\r
1162 Pos = Content.find('efivarstore', Name.end())\r
1163 if not NameGuids:\r
1164 return []\r
1165 HiiExPcds = []\r
1166 for Pcd in self.PlatformInfo.Pcds.values():\r
1167 if Pcd.Type != TAB_PCDS_DYNAMIC_EX_HII:\r
1168 continue\r
1169 for SkuInfo in Pcd.SkuInfoList.values():\r
1170 Value = GuidValue(SkuInfo.VariableGuid, self.PlatformInfo.PackageList, self.MetaFile.Path)\r
1171 if not Value:\r
1172 continue\r
1173 Name = _ConvertStringToByteArray(SkuInfo.VariableName)\r
1174 Guid = GuidStructureStringToGuidString(Value)\r
1175 if (Name, Guid) in NameGuids and Pcd not in HiiExPcds:\r
1176 HiiExPcds.append(Pcd)\r
1177 break\r
1178\r
1179 return HiiExPcds\r
1180\r
1181 def _GenOffsetBin(self):\r
1182 VfrUniBaseName = {}\r
1183 for SourceFile in self.Module.Sources:\r
1184 if SourceFile.Type.upper() == ".VFR" :\r
1185 #\r
1186 # search the .map file to find the offset of vfr binary in the PE32+/TE file.\r
1187 #\r
1188 VfrUniBaseName[SourceFile.BaseName] = (SourceFile.BaseName + "Bin")\r
1189 elif SourceFile.Type.upper() == ".UNI" :\r
1190 #\r
1191 # search the .map file to find the offset of Uni strings binary in the PE32+/TE file.\r
1192 #\r
1193 VfrUniBaseName["UniOffsetName"] = (self.Name + "Strings")\r
1194\r
1195 if not VfrUniBaseName:\r
1196 return None\r
1197 MapFileName = os.path.join(self.OutputDir, self.Name + ".map")\r
1198 EfiFileName = os.path.join(self.OutputDir, self.Name + ".efi")\r
1199 VfrUniOffsetList = GetVariableOffset(MapFileName, EfiFileName, list(VfrUniBaseName.values()))\r
1200 if not VfrUniOffsetList:\r
1201 return None\r
1202\r
1203 OutputName = '%sOffset.bin' % self.Name\r
1204 UniVfrOffsetFileName = os.path.join( self.OutputDir, OutputName)\r
1205\r
1206 try:\r
1207 fInputfile = open(UniVfrOffsetFileName, "wb+", 0)\r
1208 except:\r
1209 EdkLogger.error("build", FILE_OPEN_FAILURE, "File open failed for %s" % UniVfrOffsetFileName, None)\r
1210\r
1211 # Use a instance of BytesIO to cache data\r
1212 fStringIO = BytesIO()\r
1213\r
1214 for Item in VfrUniOffsetList:\r
1215 if (Item[0].find("Strings") != -1):\r
1216 #\r
1217 # UNI offset in image.\r
1218 # GUID + Offset\r
1219 # { 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }\r
1220 #\r
1221 UniGuid = b'\xe0\xc5\x13\x89\xf63\x86M\x9b\xf1C\xef\x89\xfc\x06f'\r
1222 fStringIO.write(UniGuid)\r
1223 UniValue = pack ('Q', int (Item[1], 16))\r
1224 fStringIO.write (UniValue)\r
1225 else:\r
1226 #\r
1227 # VFR binary offset in image.\r
1228 # GUID + Offset\r
1229 # { 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } };\r
1230 #\r
1231 VfrGuid = b'\xb4|\xbc\xd0Gj_I\xaa\x11q\x07F\xda\x06\xa2'\r
1232 fStringIO.write(VfrGuid)\r
1233 VfrValue = pack ('Q', int (Item[1], 16))\r
1234 fStringIO.write (VfrValue)\r
1235 #\r
1236 # write data into file.\r
1237 #\r
1238 try :\r
1239 fInputfile.write (fStringIO.getvalue())\r
1240 except:\r
1241 EdkLogger.error("build", FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the "\r
1242 "file been locked or using by other applications." %UniVfrOffsetFileName, None)\r
1243\r
1244 fStringIO.close ()\r
1245 fInputfile.close ()\r
1246 return OutputName\r
1247 @cached_property\r
1248 def OutputFile(self):\r
1249 retVal = set()\r
1250 OutputDir = self.OutputDir.replace('\\', '/').strip('/')\r
1251 DebugDir = self.DebugDir.replace('\\', '/').strip('/')\r
1252 for Item in self.CodaTargetList:\r
1253 File = Item.Target.Path.replace('\\', '/').strip('/').replace(DebugDir, '').replace(OutputDir, '').strip('/')\r
1254 retVal.add(File)\r
1255 if self.DepexGenerated:\r
1256 retVal.add(self.Name + '.depex')\r
1257\r
1258 Bin = self._GenOffsetBin()\r
1259 if Bin:\r
1260 retVal.add(Bin)\r
1261\r
1262 for Root, Dirs, Files in os.walk(OutputDir):\r
1263 for File in Files:\r
1264 if File.lower().endswith('.pdb'):\r
1265 retVal.add(File)\r
1266\r
1267 return retVal\r
1268\r
1269 ## Create AsBuilt INF file the module\r
1270 #\r
1271 def CreateAsBuiltInf(self):\r
1272\r
1273 if self.IsAsBuiltInfCreated:\r
1274 return\r
1275\r
1276 # Skip INF file generation for libraries\r
1277 if self.IsLibrary:\r
1278 return\r
1279\r
1280 # Skip the following code for modules with no source files\r
1281 if not self.SourceFileList:\r
1282 return\r
1283\r
1284 # Skip the following code for modules without any binary files\r
1285 if self.BinaryFileList:\r
1286 return\r
1287\r
1288 ### TODO: How to handles mixed source and binary modules\r
1289\r
1290 # Find all DynamicEx and PatchableInModule PCDs used by this module and dependent libraries\r
1291 # Also find all packages that the DynamicEx PCDs depend on\r
1292 Pcds = []\r
1293 PatchablePcds = []\r
1294 Packages = []\r
1295 PcdCheckList = []\r
1296 PcdTokenSpaceList = []\r
1297 for Pcd in self.ModulePcdList + self.LibraryPcdList:\r
1298 if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE:\r
1299 PatchablePcds.append(Pcd)\r
1300 PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_PATCHABLE_IN_MODULE))\r
1301 elif Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:\r
1302 if Pcd not in Pcds:\r
1303 Pcds.append(Pcd)\r
1304 PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC_EX))\r
1305 PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC))\r
1306 PcdTokenSpaceList.append(Pcd.TokenSpaceGuidCName)\r
1307 GuidList = OrderedDict(self.GuidList)\r
1308 for TokenSpace in self.GetGuidsUsedByPcd:\r
1309 # If token space is not referred by patch PCD or Ex PCD, remove the GUID from GUID list\r
1310 # The GUIDs in GUIDs section should really be the GUIDs in source INF or referred by Ex an patch PCDs\r
1311 if TokenSpace not in PcdTokenSpaceList and TokenSpace in GuidList:\r
1312 GuidList.pop(TokenSpace)\r
1313 CheckList = (GuidList, self.PpiList, self.ProtocolList, PcdCheckList)\r
1314 for Package in self.DerivedPackageList:\r
1315 if Package in Packages:\r
1316 continue\r
1317 BeChecked = (Package.Guids, Package.Ppis, Package.Protocols, Package.Pcds)\r
1318 Found = False\r
1319 for Index in range(len(BeChecked)):\r
1320 for Item in CheckList[Index]:\r
1321 if Item in BeChecked[Index]:\r
1322 Packages.append(Package)\r
1323 Found = True\r
1324 break\r
1325 if Found:\r
1326 break\r
1327\r
1328 VfrPcds = self._GetPcdsMaybeUsedByVfr()\r
1329 for Pkg in self.PlatformInfo.PackageList:\r
1330 if Pkg in Packages:\r
1331 continue\r
1332 for VfrPcd in VfrPcds:\r
1333 if ((VfrPcd.TokenCName, VfrPcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC_EX) in Pkg.Pcds or\r
1334 (VfrPcd.TokenCName, VfrPcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC) in Pkg.Pcds):\r
1335 Packages.append(Pkg)\r
1336 break\r
1337\r
1338 ModuleType = SUP_MODULE_DXE_DRIVER if self.ModuleType == SUP_MODULE_UEFI_DRIVER and self.DepexGenerated else self.ModuleType\r
1339 DriverType = self.PcdIsDriver if self.PcdIsDriver else ''\r
1340 Guid = self.Guid\r
1341 MDefs = self.Module.Defines\r
1342\r
1343 AsBuiltInfDict = {\r
1344 'module_name' : self.Name,\r
1345 'module_guid' : Guid,\r
1346 'module_module_type' : ModuleType,\r
1347 'module_version_string' : [MDefs['VERSION_STRING']] if 'VERSION_STRING' in MDefs else [],\r
1348 'pcd_is_driver_string' : [],\r
1349 'module_uefi_specification_version' : [],\r
1350 'module_pi_specification_version' : [],\r
1351 'module_entry_point' : self.Module.ModuleEntryPointList,\r
1352 'module_unload_image' : self.Module.ModuleUnloadImageList,\r
1353 'module_constructor' : self.Module.ConstructorList,\r
1354 'module_destructor' : self.Module.DestructorList,\r
1355 'module_shadow' : [MDefs['SHADOW']] if 'SHADOW' in MDefs else [],\r
1356 'module_pci_vendor_id' : [MDefs['PCI_VENDOR_ID']] if 'PCI_VENDOR_ID' in MDefs else [],\r
1357 'module_pci_device_id' : [MDefs['PCI_DEVICE_ID']] if 'PCI_DEVICE_ID' in MDefs else [],\r
1358 'module_pci_class_code' : [MDefs['PCI_CLASS_CODE']] if 'PCI_CLASS_CODE' in MDefs else [],\r
1359 'module_pci_revision' : [MDefs['PCI_REVISION']] if 'PCI_REVISION' in MDefs else [],\r
1360 'module_build_number' : [MDefs['BUILD_NUMBER']] if 'BUILD_NUMBER' in MDefs else [],\r
1361 'module_spec' : [MDefs['SPEC']] if 'SPEC' in MDefs else [],\r
1362 'module_uefi_hii_resource_section' : [MDefs['UEFI_HII_RESOURCE_SECTION']] if 'UEFI_HII_RESOURCE_SECTION' in MDefs else [],\r
1363 'module_uni_file' : [MDefs['MODULE_UNI_FILE']] if 'MODULE_UNI_FILE' in MDefs else [],\r
1364 'module_arch' : self.Arch,\r
1365 'package_item' : [Package.MetaFile.File.replace('\\', '/') for Package in Packages],\r
1366 'binary_item' : [],\r
1367 'patchablepcd_item' : [],\r
1368 'pcd_item' : [],\r
1369 'protocol_item' : [],\r
1370 'ppi_item' : [],\r
1371 'guid_item' : [],\r
1372 'flags_item' : [],\r
1373 'libraryclasses_item' : []\r
1374 }\r
1375\r
1376 if 'MODULE_UNI_FILE' in MDefs:\r
1377 UNIFile = os.path.join(self.MetaFile.Dir, MDefs['MODULE_UNI_FILE'])\r
1378 if os.path.isfile(UNIFile):\r
1379 shutil.copy2(UNIFile, self.OutputDir)\r
1380\r
1381 if self.AutoGenVersion > int(gInfSpecVersion, 0):\r
1382 AsBuiltInfDict['module_inf_version'] = '0x%08x' % self.AutoGenVersion\r
1383 else:\r
1384 AsBuiltInfDict['module_inf_version'] = gInfSpecVersion\r
1385\r
1386 if DriverType:\r
1387 AsBuiltInfDict['pcd_is_driver_string'].append(DriverType)\r
1388\r
1389 if 'UEFI_SPECIFICATION_VERSION' in self.Specification:\r
1390 AsBuiltInfDict['module_uefi_specification_version'].append(self.Specification['UEFI_SPECIFICATION_VERSION'])\r
1391 if 'PI_SPECIFICATION_VERSION' in self.Specification:\r
1392 AsBuiltInfDict['module_pi_specification_version'].append(self.Specification['PI_SPECIFICATION_VERSION'])\r
1393\r
1394 OutputDir = self.OutputDir.replace('\\', '/').strip('/')\r
1395 DebugDir = self.DebugDir.replace('\\', '/').strip('/')\r
1396 for Item in self.CodaTargetList:\r
1397 File = Item.Target.Path.replace('\\', '/').strip('/').replace(DebugDir, '').replace(OutputDir, '').strip('/')\r
1398 if os.path.isabs(File):\r
1399 File = File.replace('\\', '/').strip('/').replace(OutputDir, '').strip('/')\r
1400 if Item.Target.Ext.lower() == '.aml':\r
1401 AsBuiltInfDict['binary_item'].append('ASL|' + File)\r
1402 elif Item.Target.Ext.lower() == '.acpi':\r
1403 AsBuiltInfDict['binary_item'].append('ACPI|' + File)\r
1404 elif Item.Target.Ext.lower() == '.efi':\r
1405 AsBuiltInfDict['binary_item'].append('PE32|' + self.Name + '.efi')\r
1406 else:\r
1407 AsBuiltInfDict['binary_item'].append('BIN|' + File)\r
1408 if not self.DepexGenerated:\r
1409 DepexFile = os.path.join(self.OutputDir, self.Name + '.depex')\r
1410 if os.path.exists(DepexFile):\r
1411 self.DepexGenerated = True\r
1412 if self.DepexGenerated:\r
1413 if self.ModuleType in [SUP_MODULE_PEIM]:\r
1414 AsBuiltInfDict['binary_item'].append('PEI_DEPEX|' + self.Name + '.depex')\r
1415 elif self.ModuleType in [SUP_MODULE_DXE_DRIVER, SUP_MODULE_DXE_RUNTIME_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, SUP_MODULE_UEFI_DRIVER]:\r
1416 AsBuiltInfDict['binary_item'].append('DXE_DEPEX|' + self.Name + '.depex')\r
1417 elif self.ModuleType in [SUP_MODULE_DXE_SMM_DRIVER]:\r
1418 AsBuiltInfDict['binary_item'].append('SMM_DEPEX|' + self.Name + '.depex')\r
1419\r
1420 Bin = self._GenOffsetBin()\r
1421 if Bin:\r
1422 AsBuiltInfDict['binary_item'].append('BIN|%s' % Bin)\r
1423\r
1424 for Root, Dirs, Files in os.walk(OutputDir):\r
1425 for File in Files:\r
1426 if File.lower().endswith('.pdb'):\r
1427 AsBuiltInfDict['binary_item'].append('DISPOSABLE|' + File)\r
1428 HeaderComments = self.Module.HeaderComments\r
1429 StartPos = 0\r
1430 for Index in range(len(HeaderComments)):\r
1431 if HeaderComments[Index].find('@BinaryHeader') != -1:\r
1432 HeaderComments[Index] = HeaderComments[Index].replace('@BinaryHeader', '@file')\r
1433 StartPos = Index\r
1434 break\r
1435 AsBuiltInfDict['header_comments'] = '\n'.join(HeaderComments[StartPos:]).replace(':#', '://')\r
1436 AsBuiltInfDict['tail_comments'] = '\n'.join(self.Module.TailComments)\r
1437\r
1438 GenList = [\r
1439 (self.ProtocolList, self._ProtocolComments, 'protocol_item'),\r
1440 (self.PpiList, self._PpiComments, 'ppi_item'),\r
1441 (GuidList, self._GuidComments, 'guid_item')\r
1442 ]\r
1443 for Item in GenList:\r
1444 for CName in Item[0]:\r
1445 Comments = '\n '.join(Item[1][CName]) if CName in Item[1] else ''\r
1446 Entry = Comments + '\n ' + CName if Comments else CName\r
1447 AsBuiltInfDict[Item[2]].append(Entry)\r
1448 PatchList = parsePcdInfoFromMapFile(\r
1449 os.path.join(self.OutputDir, self.Name + '.map'),\r
1450 os.path.join(self.OutputDir, self.Name + '.efi')\r
1451 )\r
1452 if PatchList:\r
1453 for Pcd in PatchablePcds:\r
1454 TokenCName = Pcd.TokenCName\r
1455 for PcdItem in GlobalData.MixedPcd:\r
1456 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:\r
1457 TokenCName = PcdItem[0]\r
1458 break\r
1459 for PatchPcd in PatchList:\r
1460 if TokenCName == PatchPcd[0]:\r
1461 break\r
1462 else:\r
1463 continue\r
1464 PcdValue = ''\r
1465 if Pcd.DatumType == 'BOOLEAN':\r
1466 BoolValue = Pcd.DefaultValue.upper()\r
1467 if BoolValue == 'TRUE':\r
1468 Pcd.DefaultValue = '1'\r
1469 elif BoolValue == 'FALSE':\r
1470 Pcd.DefaultValue = '0'\r
1471\r
1472 if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:\r
1473 HexFormat = '0x%02x'\r
1474 if Pcd.DatumType == TAB_UINT16:\r
1475 HexFormat = '0x%04x'\r
1476 elif Pcd.DatumType == TAB_UINT32:\r
1477 HexFormat = '0x%08x'\r
1478 elif Pcd.DatumType == TAB_UINT64:\r
1479 HexFormat = '0x%016x'\r
1480 PcdValue = HexFormat % int(Pcd.DefaultValue, 0)\r
1481 else:\r
1482 if Pcd.MaxDatumSize is None or Pcd.MaxDatumSize == '':\r
1483 EdkLogger.error("build", AUTOGEN_ERROR,\r
1484 "Unknown [MaxDatumSize] of PCD [%s.%s]" % (Pcd.TokenSpaceGuidCName, TokenCName)\r
1485 )\r
1486 ArraySize = int(Pcd.MaxDatumSize, 0)\r
1487 PcdValue = Pcd.DefaultValue\r
1488 if PcdValue[0] != '{':\r
1489 Unicode = False\r
1490 if PcdValue[0] == 'L':\r
1491 Unicode = True\r
1492 PcdValue = PcdValue.lstrip('L')\r
1493 PcdValue = eval(PcdValue)\r
1494 NewValue = '{'\r
1495 for Index in range(0, len(PcdValue)):\r
1496 if Unicode:\r
1497 CharVal = ord(PcdValue[Index])\r
1498 NewValue = NewValue + '0x%02x' % (CharVal & 0x00FF) + ', ' \\r
1499 + '0x%02x' % (CharVal >> 8) + ', '\r
1500 else:\r
1501 NewValue = NewValue + '0x%02x' % (ord(PcdValue[Index]) % 0x100) + ', '\r
1502 Padding = '0x00, '\r
1503 if Unicode:\r
1504 Padding = Padding * 2\r
1505 ArraySize = ArraySize // 2\r
1506 if ArraySize < (len(PcdValue) + 1):\r
1507 if Pcd.MaxSizeUserSet:\r
1508 EdkLogger.error("build", AUTOGEN_ERROR,\r
1509 "The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)\r
1510 )\r
1511 else:\r
1512 ArraySize = len(PcdValue) + 1\r
1513 if ArraySize > len(PcdValue) + 1:\r
1514 NewValue = NewValue + Padding * (ArraySize - len(PcdValue) - 1)\r
1515 PcdValue = NewValue + Padding.strip().rstrip(',') + '}'\r
1516 elif len(PcdValue.split(',')) <= ArraySize:\r
1517 PcdValue = PcdValue.rstrip('}') + ', 0x00' * (ArraySize - len(PcdValue.split(',')))\r
1518 PcdValue += '}'\r
1519 else:\r
1520 if Pcd.MaxSizeUserSet:\r
1521 EdkLogger.error("build", AUTOGEN_ERROR,\r
1522 "The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)\r
1523 )\r
1524 else:\r
1525 ArraySize = len(PcdValue) + 1\r
1526 PcdItem = '%s.%s|%s|0x%X' % \\r
1527 (Pcd.TokenSpaceGuidCName, TokenCName, PcdValue, PatchPcd[1])\r
1528 PcdComments = ''\r
1529 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:\r
1530 PcdComments = '\n '.join(self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName])\r
1531 if PcdComments:\r
1532 PcdItem = PcdComments + '\n ' + PcdItem\r
1533 AsBuiltInfDict['patchablepcd_item'].append(PcdItem)\r
1534\r
1535 for Pcd in Pcds + VfrPcds:\r
1536 PcdCommentList = []\r
1537 HiiInfo = ''\r
1538 TokenCName = Pcd.TokenCName\r
1539 for PcdItem in GlobalData.MixedPcd:\r
1540 if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:\r
1541 TokenCName = PcdItem[0]\r
1542 break\r
1543 if Pcd.Type == TAB_PCDS_DYNAMIC_EX_HII:\r
1544 for SkuName in Pcd.SkuInfoList:\r
1545 SkuInfo = Pcd.SkuInfoList[SkuName]\r
1546 HiiInfo = '## %s|%s|%s' % (SkuInfo.VariableName, SkuInfo.VariableGuid, SkuInfo.VariableOffset)\r
1547 break\r
1548 if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:\r
1549 PcdCommentList = self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName][:]\r
1550 if HiiInfo:\r
1551 UsageIndex = -1\r
1552 UsageStr = ''\r
1553 for Index, Comment in enumerate(PcdCommentList):\r
1554 for Usage in UsageList:\r
1555 if Comment.find(Usage) != -1:\r
1556 UsageStr = Usage\r
1557 UsageIndex = Index\r
1558 break\r
1559 if UsageIndex != -1:\r
1560 PcdCommentList[UsageIndex] = '## %s %s %s' % (UsageStr, HiiInfo, PcdCommentList[UsageIndex].replace(UsageStr, ''))\r
1561 else:\r
1562 PcdCommentList.append('## UNDEFINED ' + HiiInfo)\r
1563 PcdComments = '\n '.join(PcdCommentList)\r
1564 PcdEntry = Pcd.TokenSpaceGuidCName + '.' + TokenCName\r
1565 if PcdComments:\r
1566 PcdEntry = PcdComments + '\n ' + PcdEntry\r
1567 AsBuiltInfDict['pcd_item'].append(PcdEntry)\r
1568 for Item in self.BuildOption:\r
1569 if 'FLAGS' in self.BuildOption[Item]:\r
1570 AsBuiltInfDict['flags_item'].append('%s:%s_%s_%s_%s_FLAGS = %s' % (self.ToolChainFamily, self.BuildTarget, self.ToolChain, self.Arch, Item, self.BuildOption[Item]['FLAGS'].strip()))\r
1571\r
1572 # Generated LibraryClasses section in comments.\r
1573 for Library in self.LibraryAutoGenList:\r
1574 AsBuiltInfDict['libraryclasses_item'].append(Library.MetaFile.File.replace('\\', '/'))\r
1575\r
1576 # Generated UserExtensions TianoCore section.\r
1577 # All tianocore user extensions are copied.\r
1578 UserExtStr = ''\r
1579 for TianoCore in self._GetTianoCoreUserExtensionList():\r
1580 UserExtStr += '\n'.join(TianoCore)\r
1581 ExtensionFile = os.path.join(self.MetaFile.Dir, TianoCore[1])\r
1582 if os.path.isfile(ExtensionFile):\r
1583 shutil.copy2(ExtensionFile, self.OutputDir)\r
1584 AsBuiltInfDict['userextension_tianocore_item'] = UserExtStr\r
1585\r
1586 # Generated depex expression section in comments.\r
1587 DepexExpression = self._GetDepexExpresionString()\r
1588 AsBuiltInfDict['depexsection_item'] = DepexExpression if DepexExpression else ''\r
1589\r
1590 AsBuiltInf = TemplateString()\r
1591 AsBuiltInf.Append(gAsBuiltInfHeaderString.Replace(AsBuiltInfDict))\r
1592\r
1593 SaveFileOnChange(os.path.join(self.OutputDir, self.Name + '.inf'), str(AsBuiltInf), False)\r
1594\r
1595 self.IsAsBuiltInfCreated = True\r
1596\r
1597 def CopyModuleToCache(self):\r
1598 FileDir = path.join(GlobalData.gBinCacheDest, self.PlatformInfo.Name, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName)\r
1599 CreateDirectory (FileDir)\r
1600 HashFile = path.join(self.BuildDir, self.Name + '.hash')\r
1601 if os.path.exists(HashFile):\r
1602 CopyFileOnChange(HashFile, FileDir)\r
1603 ModuleFile = path.join(self.OutputDir, self.Name + '.inf')\r
1604 if os.path.exists(ModuleFile):\r
1605 CopyFileOnChange(ModuleFile, FileDir)\r
1606 if not self.OutputFile:\r
1607 Ma = self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]\r
1608 self.OutputFile = Ma.Binaries\r
1609 for File in self.OutputFile:\r
1610 File = str(File)\r
1611 if not os.path.isabs(File):\r
1612 File = os.path.join(self.OutputDir, File)\r
1613 if os.path.exists(File):\r
1614 sub_dir = os.path.relpath(File, self.OutputDir)\r
1615 destination_file = os.path.join(FileDir, sub_dir)\r
1616 destination_dir = os.path.dirname(destination_file)\r
1617 CreateDirectory(destination_dir)\r
1618 CopyFileOnChange(File, destination_dir)\r
1619\r
1620 def AttemptModuleCacheCopy(self):\r
1621 # If library or Module is binary do not skip by hash\r
1622 if self.IsBinaryModule:\r
1623 return False\r
1624 # .inc is contains binary information so do not skip by hash as well\r
1625 for f_ext in self.SourceFileList:\r
1626 if '.inc' in str(f_ext):\r
1627 return False\r
1628 FileDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.Name, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName)\r
1629 HashFile = path.join(FileDir, self.Name + '.hash')\r
1630 if os.path.exists(HashFile):\r
1631 f = open(HashFile, 'r')\r
1632 CacheHash = f.read()\r
1633 f.close()\r
1634 self.GenModuleHash()\r
1635 if GlobalData.gModuleHash[self.Arch][self.Name]:\r
1636 if CacheHash == GlobalData.gModuleHash[self.Arch][self.Name]:\r
1637 for root, dir, files in os.walk(FileDir):\r
1638 for f in files:\r
1639 if self.Name + '.hash' in f:\r
1640 CopyFileOnChange(HashFile, self.BuildDir)\r
1641 else:\r
1642 File = path.join(root, f)\r
1643 sub_dir = os.path.relpath(File, FileDir)\r
1644 destination_file = os.path.join(self.OutputDir, sub_dir)\r
1645 destination_dir = os.path.dirname(destination_file)\r
1646 CreateDirectory(destination_dir)\r
1647 CopyFileOnChange(File, destination_dir)\r
1648 if self.Name == "PcdPeim" or self.Name == "PcdDxe":\r
1649 CreatePcdDatabaseCode(self, TemplateString(), TemplateString())\r
1650 return True\r
1651 return False\r
1652\r
1653 ## Create makefile for the module and its dependent libraries\r
1654 #\r
1655 # @param CreateLibraryMakeFile Flag indicating if or not the makefiles of\r
1656 # dependent libraries will be created\r
1657 #\r
1658 @cached_class_function\r
1659 def CreateMakeFile(self, CreateLibraryMakeFile=True, GenFfsList = []):\r
1660 # nest this function inside it's only caller.\r
1661 def CreateTimeStamp():\r
1662 FileSet = {self.MetaFile.Path}\r
1663\r
1664 for SourceFile in self.Module.Sources:\r
1665 FileSet.add (SourceFile.Path)\r
1666\r
1667 for Lib in self.DependentLibraryList:\r
1668 FileSet.add (Lib.MetaFile.Path)\r
1669\r
1670 for f in self.AutoGenDepSet:\r
1671 FileSet.add (f.Path)\r
1672\r
1673 if os.path.exists (self.TimeStampPath):\r
1674 os.remove (self.TimeStampPath)\r
1675 with open(self.TimeStampPath, 'w+') as fd:\r
1676 for f in FileSet:\r
1677 fd.write(f)\r
1678 fd.write("\n")\r
1679\r
1680 # Ignore generating makefile when it is a binary module\r
1681 if self.IsBinaryModule:\r
1682 return\r
1683\r
1684 self.GenFfsList = GenFfsList\r
1685\r
1686 if not self.IsLibrary and CreateLibraryMakeFile:\r
1687 for LibraryAutoGen in self.LibraryAutoGenList:\r
1688 LibraryAutoGen.CreateMakeFile()\r
673d09a2 1689\r
e8449e1d
FB
1690 # Don't enable if hash feature enabled, CanSkip uses timestamps to determine build skipping\r
1691 if not GlobalData.gUseHashCache and self.CanSkip():\r
1692 return\r
1693\r
1694 if len(self.CustomMakefile) == 0:\r
1695 Makefile = GenMake.ModuleMakefile(self)\r
1696 else:\r
1697 Makefile = GenMake.CustomMakefile(self)\r
1698 if Makefile.Generate():\r
1699 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated makefile for module %s [%s]" %\r
1700 (self.Name, self.Arch))\r
1701 else:\r
1702 EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of makefile for module %s [%s]" %\r
1703 (self.Name, self.Arch))\r
1704\r
1705 CreateTimeStamp()\r
1706\r
1707 def CopyBinaryFiles(self):\r
1708 for File in self.Module.Binaries:\r
1709 SrcPath = File.Path\r
1710 DstPath = os.path.join(self.OutputDir, os.path.basename(SrcPath))\r
1711 CopyLongFilePath(SrcPath, DstPath)\r
1712 ## Create autogen code for the module and its dependent libraries\r
1713 #\r
1714 # @param CreateLibraryCodeFile Flag indicating if or not the code of\r
1715 # dependent libraries will be created\r
1716 #\r
1717 def CreateCodeFile(self, CreateLibraryCodeFile=True):\r
1718 if self.IsCodeFileCreated:\r
1719 return\r
1720\r
1721 # Need to generate PcdDatabase even PcdDriver is binarymodule\r
1722 if self.IsBinaryModule and self.PcdIsDriver != '':\r
1723 CreatePcdDatabaseCode(self, TemplateString(), TemplateString())\r
1724 return\r
1725 if self.IsBinaryModule:\r
1726 if self.IsLibrary:\r
1727 self.CopyBinaryFiles()\r
1728 return\r
1729\r
1730 if not self.IsLibrary and CreateLibraryCodeFile:\r
1731 for LibraryAutoGen in self.LibraryAutoGenList:\r
1732 LibraryAutoGen.CreateCodeFile()\r
e8449e1d
FB
1733 # Don't enable if hash feature enabled, CanSkip uses timestamps to determine build skipping\r
1734 if not GlobalData.gUseHashCache and self.CanSkip():\r
1735 return\r
1736\r
1737 AutoGenList = []\r
1738 IgoredAutoGenList = []\r
1739\r
1740 for File in self.AutoGenFileList:\r
1741 if GenC.Generate(File.Path, self.AutoGenFileList[File], File.IsBinary):\r
1742 AutoGenList.append(str(File))\r
1743 else:\r
1744 IgoredAutoGenList.append(str(File))\r
1745\r
1746\r
1747 for ModuleType in self.DepexList:\r
1748 # Ignore empty [depex] section or [depex] section for SUP_MODULE_USER_DEFINED module\r
1749 if len(self.DepexList[ModuleType]) == 0 or ModuleType == SUP_MODULE_USER_DEFINED or ModuleType == SUP_MODULE_HOST_APPLICATION:\r
1750 continue\r
1751\r
1752 Dpx = GenDepex.DependencyExpression(self.DepexList[ModuleType], ModuleType, True)\r
1753 DpxFile = gAutoGenDepexFileName % {"module_name" : self.Name}\r
1754\r
1755 if len(Dpx.PostfixNotation) != 0:\r
1756 self.DepexGenerated = True\r
1757\r
1758 if Dpx.Generate(path.join(self.OutputDir, DpxFile)):\r
1759 AutoGenList.append(str(DpxFile))\r
1760 else:\r
1761 IgoredAutoGenList.append(str(DpxFile))\r
1762\r
1763 if IgoredAutoGenList == []:\r
1764 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] files for module %s [%s]" %\r
1765 (" ".join(AutoGenList), self.Name, self.Arch))\r
1766 elif AutoGenList == []:\r
1767 EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of [%s] files for module %s [%s]" %\r
1768 (" ".join(IgoredAutoGenList), self.Name, self.Arch))\r
1769 else:\r
1770 EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] (skipped %s) files for module %s [%s]" %\r
1771 (" ".join(AutoGenList), " ".join(IgoredAutoGenList), self.Name, self.Arch))\r
1772\r
1773 self.IsCodeFileCreated = True\r
1774 return AutoGenList\r
1775\r
1776 ## Summarize the ModuleAutoGen objects of all libraries used by this module\r
1777 @cached_property\r
1778 def LibraryAutoGenList(self):\r
1779 RetVal = []\r
1780 for Library in self.DependentLibraryList:\r
1781 La = ModuleAutoGen(\r
1782 self.Workspace,\r
1783 Library.MetaFile,\r
1784 self.BuildTarget,\r
1785 self.ToolChain,\r
1786 self.Arch,\r
1787 self.PlatformInfo.MetaFile,\r
1788 self.DataPipe\r
1789 )\r
1790 La.IsLibrary = True\r
1791 if La not in RetVal:\r
1792 RetVal.append(La)\r
1793 for Lib in La.CodaTargetList:\r
1794 self._ApplyBuildRule(Lib.Target, TAB_UNKNOWN_FILE)\r
1795 return RetVal\r
1796\r
1797 def GenModuleHash(self):\r
1798 # Initialize a dictionary for each arch type\r
1799 if self.Arch not in GlobalData.gModuleHash:\r
1800 GlobalData.gModuleHash[self.Arch] = {}\r
1801\r
1802 # Early exit if module or library has been hashed and is in memory\r
1803 if self.Name in GlobalData.gModuleHash[self.Arch]:\r
1804 return GlobalData.gModuleHash[self.Arch][self.Name].encode('utf-8')\r
1805\r
1806 # Initialze hash object\r
1807 m = hashlib.md5()\r
1808\r
1809 # Add Platform level hash\r
1810 m.update(GlobalData.gPlatformHash.encode('utf-8'))\r
1811\r
1812 # Add Package level hash\r
1813 if self.DependentPackageList:\r
1814 for Pkg in sorted(self.DependentPackageList, key=lambda x: x.PackageName):\r
1815 if Pkg.PackageName in GlobalData.gPackageHash:\r
1816 m.update(GlobalData.gPackageHash[Pkg.PackageName].encode('utf-8'))\r
1817\r
1818 # Add Library hash\r
1819 if self.LibraryAutoGenList:\r
1820 for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.Name):\r
1821 if Lib.Name not in GlobalData.gModuleHash[self.Arch]:\r
1822 Lib.GenModuleHash()\r
1823 m.update(GlobalData.gModuleHash[self.Arch][Lib.Name].encode('utf-8'))\r
1824\r
1825 # Add Module self\r
1826 f = open(str(self.MetaFile), 'rb')\r
1827 Content = f.read()\r
1828 f.close()\r
1829 m.update(Content)\r
1830\r
1831 # Add Module's source files\r
1832 if self.SourceFileList:\r
1833 for File in sorted(self.SourceFileList, key=lambda x: str(x)):\r
1834 f = open(str(File), 'rb')\r
1835 Content = f.read()\r
1836 f.close()\r
1837 m.update(Content)\r
1838\r
1839 GlobalData.gModuleHash[self.Arch][self.Name] = m.hexdigest()\r
1840\r
1841 return GlobalData.gModuleHash[self.Arch][self.Name].encode('utf-8')\r
1842\r
1843 ## Decide whether we can skip the ModuleAutoGen process\r
1844 def CanSkipbyHash(self):\r
1845 # Hashing feature is off\r
1846 if not GlobalData.gUseHashCache:\r
1847 return False\r
1848\r
1849 # Initialize a dictionary for each arch type\r
1850 if self.Arch not in GlobalData.gBuildHashSkipTracking:\r
1851 GlobalData.gBuildHashSkipTracking[self.Arch] = dict()\r
1852\r
1853 # If library or Module is binary do not skip by hash\r
1854 if self.IsBinaryModule:\r
1855 return False\r
1856\r
1857 # .inc is contains binary information so do not skip by hash as well\r
1858 for f_ext in self.SourceFileList:\r
1859 if '.inc' in str(f_ext):\r
1860 return False\r
1861\r
1862 # Use Cache, if exists and if Module has a copy in cache\r
1863 if GlobalData.gBinCacheSource and self.AttemptModuleCacheCopy():\r
1864 return True\r
1865\r
1866 # Early exit for libraries that haven't yet finished building\r
1867 HashFile = path.join(self.BuildDir, self.Name + ".hash")\r
1868 if self.IsLibrary and not os.path.exists(HashFile):\r
1869 return False\r
1870\r
1871 # Return a Boolean based on if can skip by hash, either from memory or from IO.\r
1872 if self.Name not in GlobalData.gBuildHashSkipTracking[self.Arch]:\r
1873 # If hashes are the same, SaveFileOnChange() will return False.\r
1874 GlobalData.gBuildHashSkipTracking[self.Arch][self.Name] = not SaveFileOnChange(HashFile, self.GenModuleHash(), True)\r
1875 return GlobalData.gBuildHashSkipTracking[self.Arch][self.Name]\r
1876 else:\r
1877 return GlobalData.gBuildHashSkipTracking[self.Arch][self.Name]\r
1878\r
1879 ## Decide whether we can skip the ModuleAutoGen process\r
1880 # If any source file is newer than the module than we cannot skip\r
1881 #\r
1882 def CanSkip(self):\r
1883 if self.MakeFileDir in GlobalData.gSikpAutoGenCache:\r
1884 return True\r
1885 if not os.path.exists(self.TimeStampPath):\r
1886 return False\r
1887 #last creation time of the module\r
1888 DstTimeStamp = os.stat(self.TimeStampPath)[8]\r
1889\r
1890 SrcTimeStamp = self.Workspace._SrcTimeStamp\r
1891 if SrcTimeStamp > DstTimeStamp:\r
1892 return False\r
1893\r
1894 with open(self.TimeStampPath,'r') as f:\r
1895 for source in f:\r
1896 source = source.rstrip('\n')\r
1897 if not os.path.exists(source):\r
1898 return False\r
1899 if source not in ModuleAutoGen.TimeDict :\r
1900 ModuleAutoGen.TimeDict[source] = os.stat(source)[8]\r
1901 if ModuleAutoGen.TimeDict[source] > DstTimeStamp:\r
1902 return False\r
1903 GlobalData.gSikpAutoGenCache.add(self.MakeFileDir)\r
1904 return True\r
1905\r
1906 @cached_property\r
1907 def TimeStampPath(self):\r
1908 return os.path.join(self.MakeFileDir, 'AutoGenTimeStamp')\r