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