from Common.MultipleWorkspace import MultipleWorkspace as mws\r
import InfSectionParser\r
import datetime\r
+import hashlib\r
\r
## Regular expression for splitting Dependency Expression string into tokens\r
gDepexTokenPattern = re.compile("(\(|\)|\w+| \S+\.inf)")\r
\r
${depexsection_item}\r
\r
+${userextension_tianocore_item}\r
+\r
${tail_comments}\r
\r
[BuildOptions.${module_arch}]\r
self.FvTargetList = Fvs\r
self.CapTargetList = Caps\r
self.AutoGenObjectList = []\r
+ self._BuildDir = None\r
+ self._FvDir = None\r
+ self._MakeFileDir = None\r
+ self._BuildCommand = None\r
\r
# there's many relative directory operations, so ...\r
os.chdir(self.WorkspaceDir)\r
Pa.CollectFixedAtBuildPcds()\r
self.AutoGenObjectList.append(Pa)\r
\r
+ #\r
+ # Generate Package level hash value\r
+ #\r
+ GlobalData.gPackageHash[Arch] = {}\r
+ if GlobalData.gUseHashCache:\r
+ for Pkg in Pkgs:\r
+ self._GenPkgLevelHash(Pkg)\r
+\r
#\r
# Check PCDs token value conflict in each DEC file.\r
#\r
# if self.FdfFile:\r
# self._CheckDuplicateInFV(Fdf)\r
\r
- self._BuildDir = None\r
- self._FvDir = None\r
- self._MakeFileDir = None\r
- self._BuildCommand = None\r
-\r
#\r
- # Create BuildOptions Macro & PCD metafile.\r
+ # Create BuildOptions Macro & PCD metafile, also add the Active Platform and FDF file.\r
#\r
content = 'gCommandLineDefines: '\r
content += str(GlobalData.gCommandLineDefines)\r
content += os.linesep\r
content += 'BuildOptionPcd: '\r
content += str(GlobalData.BuildOptionPcd)\r
+ content += os.linesep\r
+ content += 'Active Platform: '\r
+ content += str(self.Platform)\r
+ content += os.linesep\r
+ if self.FdfFile:\r
+ content += 'Flash Image Definition: '\r
+ content += str(self.FdfFile)\r
+ content += os.linesep\r
+ if GlobalData.gBinCacheDest:\r
+ content += 'Cache of .efi location: '\r
+ content += str(GlobalData.gBinCacheDest)\r
SaveFileOnChange(os.path.join(self.BuildDir, 'BuildOptions'), content, False)\r
\r
+ #\r
+ # Create PcdToken Number file for Dynamic/DynamicEx Pcd.\r
+ #\r
+ PcdTokenNumber = 'PcdTokenNumber: '\r
+ if Pa.PcdTokenNumber:\r
+ if Pa.DynamicPcdList:\r
+ for Pcd in Pa.DynamicPcdList:\r
+ PcdTokenNumber += os.linesep\r
+ PcdTokenNumber += str((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))\r
+ PcdTokenNumber += ' : '\r
+ PcdTokenNumber += str(Pa.PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName])\r
+ SaveFileOnChange(os.path.join(self.BuildDir, 'PcdTokenNumber'), PcdTokenNumber, False)\r
+\r
#\r
# Get set of workspace metafiles\r
#\r
SrcTimeStamp = os.stat(f)[8]\r
self._SrcTimeStamp = SrcTimeStamp\r
\r
+ if GlobalData.gUseHashCache:\r
+ m = hashlib.md5()\r
+ for files in AllWorkSpaceMetaFiles:\r
+ if files.endswith('.dec'):\r
+ continue\r
+ f = open(files, 'r')\r
+ Content = f.read()\r
+ f.close()\r
+ m.update(Content)\r
+ SaveFileOnChange(os.path.join(self.BuildDir, 'AutoGen.hash'), m.hexdigest(), True)\r
+ GlobalData.gPlatformHash = m.hexdigest()\r
+\r
#\r
# Write metafile list to build directory\r
#\r
print >> file, f\r
return True\r
\r
+ def _GenPkgLevelHash(self, Pkg):\r
+ PkgDir = os.path.join(self.BuildDir, Pkg.Arch, Pkg.PackageName)\r
+ CreateDirectory(PkgDir)\r
+ HashFile = os.path.join(PkgDir, Pkg.PackageName + '.hash')\r
+ m = hashlib.md5()\r
+ # Get .dec file's hash value\r
+ f = open(Pkg.MetaFile.Path, 'r')\r
+ Content = f.read()\r
+ f.close()\r
+ m.update(Content)\r
+ # Get include files hash value\r
+ if Pkg.Includes:\r
+ for inc in Pkg.Includes:\r
+ for Root, Dirs, Files in os.walk(str(inc)):\r
+ for File in Files:\r
+ File_Path = os.path.join(Root, File)\r
+ f = open(File_Path, 'r')\r
+ Content = f.read()\r
+ f.close()\r
+ m.update(Content)\r
+ SaveFileOnChange(HashFile, m.hexdigest(), True)\r
+ if Pkg.PackageName not in GlobalData.gPackageHash[Pkg.Arch]:\r
+ GlobalData.gPackageHash[Pkg.Arch][Pkg.PackageName] = m.hexdigest()\r
\r
def _GetMetaFiles(self, Target, Toolchain, Arch):\r
AllWorkSpaceMetaFiles = set()\r
#\r
AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'BuildOptions'))\r
\r
+ # add PcdToken Number file for Dynamic/DynamicEx Pcd\r
+ #\r
+ AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'PcdTokenNumber'))\r
+\r
for Arch in self.ArchList:\r
Platform = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]\r
PGen = PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch)\r
\r
## Return the directory to store all intermediate and final files built\r
def _GetBuildDir(self):\r
- return self.AutoGenObjectList[0].BuildDir\r
+ if self._BuildDir == None:\r
+ return self.AutoGenObjectList[0].BuildDir\r
\r
## Return the build output directory platform specifies\r
def _GetOutputDir(self):\r
self.OutputDir,\r
self.BuildTarget + "_" + self.ToolChain,\r
)\r
+ GlobalData.gBuildDirectory = self._BuildDir\r
return self._BuildDir\r
\r
## Return directory of platform makefile\r
if Module in self.Platform.Modules:\r
PlatformModule = self.Platform.Modules[str(Module)]\r
for Key in PlatformModule.Pcds:\r
+ Flag = False\r
if Key in Pcds:\r
- self._OverridePcd(Pcds[Key], PlatformModule.Pcds[Key], Module)\r
+ ToPcd = Pcds[Key]\r
+ Flag = True\r
+ elif Key in GlobalData.MixedPcd:\r
+ for PcdItem in GlobalData.MixedPcd[Key]:\r
+ if PcdItem in Pcds:\r
+ ToPcd = Pcds[PcdItem]\r
+ Flag = True\r
+ break\r
+ if Flag:\r
+ self._OverridePcd(ToPcd, PlatformModule.Pcds[Key], Module)\r
return Pcds.values()\r
\r
## Resolve library names to library modules\r
\r
self.BuildDatabase = self.Workspace.BuildDatabase\r
self.BuildRuleOrder = None\r
+ self.BuildTime = 0\r
\r
self._Module = None\r
self._Name = None\r
self._DepexExpressionList[ModuleType] = DepexExpressionList\r
return self._DepexExpressionList\r
\r
+ # Get the tiano core user extension, it is contain dependent library.\r
+ # @retval: a list contain tiano core userextension.\r
+ #\r
+ def _GetTianoCoreUserExtensionList(self):\r
+ TianoCoreUserExtentionList = []\r
+ for M in [self.Module] + self.DependentLibraryList:\r
+ Filename = M.MetaFile.Path\r
+ InfObj = InfSectionParser.InfSectionParser(Filename)\r
+ TianoCoreUserExtenList = InfObj.GetUserExtensionTianoCore()\r
+ for TianoCoreUserExtent in TianoCoreUserExtenList:\r
+ for Section in TianoCoreUserExtent.keys():\r
+ ItemList = Section.split(TAB_SPLIT)\r
+ Arch = self.Arch\r
+ if len(ItemList) == 4:\r
+ Arch = ItemList[3]\r
+ if Arch.upper() == TAB_ARCH_COMMON or Arch.upper() == self.Arch.upper():\r
+ TianoCoreList = []\r
+ TianoCoreList.extend([TAB_SECTION_START + Section + TAB_SECTION_END])\r
+ TianoCoreList.extend(TianoCoreUserExtent[Section][:])\r
+ TianoCoreList.append('\n')\r
+ TianoCoreUserExtentionList.append(TianoCoreList)\r
+\r
+ return TianoCoreUserExtentionList\r
+\r
## Return the list of specification version required for the module\r
#\r
# @retval list The list of specification defined in module file\r
EdkLogger.debug(EdkLogger.DEBUG_9, "The toolchain [%s] for processing file [%s] is found, "\r
"but [%s] is needed" % (F.TagName, str(F), self.ToolChain))\r
continue\r
- # match tool chain family\r
- if F.ToolChainFamily not in ("", "*", self.ToolChainFamily):\r
+ # match tool chain family or build rule family\r
+ if F.ToolChainFamily not in ("", "*", self.ToolChainFamily, self.BuildRuleFamily):\r
EdkLogger.debug(\r
EdkLogger.DEBUG_0,\r
"The file [%s] must be built by tools of [%s], " \\r
- "but current toolchain family is [%s]" \\r
- % (str(F), F.ToolChainFamily, self.ToolChainFamily))\r
+ "but current toolchain family is [%s], buildrule family is [%s]" \\r
+ % (str(F), F.ToolChainFamily, self.ToolChainFamily, self.BuildRuleFamily))\r
continue\r
\r
# add the file path into search path list for file including\r
'libraryclasses_item' : []\r
}\r
\r
+ if 'MODULE_UNI_FILE' in MDefs:\r
+ UNIFile = os.path.join(self.MetaFile.Dir, MDefs['MODULE_UNI_FILE'])\r
+ if os.path.isfile(UNIFile):\r
+ shutil.copy2(UNIFile, self.OutputDir)\r
+\r
if self.AutoGenVersion > int(gInfSpecVersion, 0):\r
AsBuiltInfDict['module_inf_version'] = '0x%08x' % self.AutoGenVersion\r
else:\r
AsBuiltInfDict['module_pi_specification_version'] += [self.Specification['PI_SPECIFICATION_VERSION']]\r
\r
OutputDir = self.OutputDir.replace('\\', '/').strip('/')\r
-\r
+ self.OutputFile = []\r
for Item in self.CodaTargetList:\r
File = Item.Target.Path.replace('\\', '/').strip('/').replace(OutputDir, '').strip('/')\r
+ if File not in self.OutputFile:\r
+ self.OutputFile.append(File)\r
if Item.Target.Ext.lower() == '.aml':\r
AsBuiltInfDict['binary_item'] += ['ASL|' + File]\r
elif Item.Target.Ext.lower() == '.acpi':\r
else:\r
AsBuiltInfDict['binary_item'] += ['BIN|' + File]\r
if self.DepexGenerated:\r
+ if self.Name + '.depex' not in self.OutputFile:\r
+ self.OutputFile.append(self.Name + '.depex')\r
if self.ModuleType in ['PEIM']:\r
AsBuiltInfDict['binary_item'] += ['PEI_DEPEX|' + self.Name + '.depex']\r
if self.ModuleType in ['DXE_DRIVER', 'DXE_RUNTIME_DRIVER', 'DXE_SAL_DRIVER', 'UEFI_DRIVER']:\r
Bin = self._GenOffsetBin()\r
if Bin:\r
AsBuiltInfDict['binary_item'] += ['BIN|%s' % Bin]\r
+ if Bin not in self.OutputFile:\r
+ self.OutputFile.append(Bin)\r
\r
for Root, Dirs, Files in os.walk(OutputDir):\r
for File in Files:\r
if File.lower().endswith('.pdb'):\r
AsBuiltInfDict['binary_item'] += ['DISPOSABLE|' + File]\r
+ if File not in self.OutputFile:\r
+ self.OutputFile.append(File)\r
HeaderComments = self.Module.HeaderComments\r
StartPos = 0\r
for Index in range(len(HeaderComments)):\r
for Library in self.LibraryAutoGenList:\r
AsBuiltInfDict['libraryclasses_item'] += [Library.MetaFile.File.replace('\\', '/')]\r
\r
+ # Generated UserExtensions TianoCore section.\r
+ # All tianocore user extensions are copied.\r
+ UserExtStr = ''\r
+ for TianoCore in self._GetTianoCoreUserExtensionList():\r
+ UserExtStr += '\n'.join(TianoCore)\r
+ ExtensionFile = os.path.join(self.MetaFile.Dir, TianoCore[1])\r
+ if os.path.isfile(ExtensionFile):\r
+ shutil.copy2(ExtensionFile, self.OutputDir)\r
+ AsBuiltInfDict['userextension_tianocore_item'] = UserExtStr\r
+\r
# Generated depex expression section in comments.\r
AsBuiltInfDict['depexsection_item'] = ''\r
DepexExpresion = self._GetDepexExpresionString()\r
SaveFileOnChange(os.path.join(self.OutputDir, self.Name + '.inf'), str(AsBuiltInf), False)\r
\r
self.IsAsBuiltInfCreated = True\r
- \r
+ if GlobalData.gBinCacheDest:\r
+ self.CopyModuleToCache()\r
+\r
+ def CopyModuleToCache(self):\r
+ FileDir = path.join(GlobalData.gBinCacheDest, self.Arch, self.SourceDir, self.MetaFile.BaseName)\r
+ CreateDirectory (FileDir)\r
+ HashFile = path.join(self.BuildDir, self.Name + '.hash')\r
+ ModuleFile = path.join(self.OutputDir, self.Name + '.inf')\r
+ if os.path.exists(HashFile):\r
+ shutil.copy2(HashFile, FileDir)\r
+ if os.path.exists(ModuleFile):\r
+ shutil.copy2(ModuleFile, FileDir)\r
+ if self.OutputFile:\r
+ for File in self.OutputFile:\r
+ if not os.path.isabs(File):\r
+ File = os.path.join(self.OutputDir, File)\r
+ if os.path.exists(File):\r
+ shutil.copy2(File, FileDir)\r
+\r
+ def AttemptModuleCacheCopy(self):\r
+ if self.IsBinaryModule:\r
+ return False\r
+ FileDir = path.join(GlobalData.gBinCacheSource, self.Arch, self.SourceDir, self.MetaFile.BaseName)\r
+ HashFile = path.join(FileDir, self.Name + '.hash')\r
+ if os.path.exists(HashFile):\r
+ f = open(HashFile, 'r')\r
+ CacheHash = f.read()\r
+ f.close()\r
+ if GlobalData.gModuleHash[self.Arch][self.Name]:\r
+ if CacheHash == GlobalData.gModuleHash[self.Arch][self.Name]:\r
+ for root, dir, files in os.walk(FileDir):\r
+ for f in files:\r
+ if self.Name + '.hash' in f:\r
+ shutil.copy2(HashFile, self.BuildDir)\r
+ else:\r
+ File = path.join(root, f)\r
+ shutil.copy2(File, self.OutputDir)\r
+ if self.Name == "PcdPeim" or self.Name == "PcdDxe":\r
+ CreatePcdDatabaseCode(self, TemplateString(), TemplateString())\r
+ return True\r
+ return False\r
+\r
## Create makefile for the module and its dependent libraries\r
#\r
# @param CreateLibraryMakeFile Flag indicating if or not the makefiles of\r
\r
if self.IsMakeFileCreated:\r
return\r
- if self.CanSkip():\r
- return\r
\r
if not self.IsLibrary and CreateLibraryMakeFile:\r
for LibraryAutoGen in self.LibraryAutoGenList:\r
LibraryAutoGen.CreateMakeFile()\r
\r
+ if self.CanSkip():\r
+ return\r
+\r
if len(self.CustomMakefile) == 0:\r
Makefile = GenMake.ModuleMakefile(self)\r
else:\r
def CreateCodeFile(self, CreateLibraryCodeFile=True):\r
if self.IsCodeFileCreated:\r
return\r
- if self.CanSkip():\r
- return\r
\r
# Need to generate PcdDatabase even PcdDriver is binarymodule\r
if self.IsBinaryModule and self.PcdIsDriver != '':\r
for LibraryAutoGen in self.LibraryAutoGenList:\r
LibraryAutoGen.CreateCodeFile()\r
\r
+ if self.CanSkip():\r
+ return\r
+\r
AutoGenList = []\r
IgoredAutoGenList = []\r
\r
self._ApplyBuildRule(Lib.Target, TAB_UNKNOWN_FILE)\r
return self._LibraryAutoGenList\r
\r
+ def GenModuleHash(self):\r
+ if self.Arch not in GlobalData.gModuleHash:\r
+ GlobalData.gModuleHash[self.Arch] = {}\r
+ m = hashlib.md5()\r
+ # Add Platform level hash\r
+ m.update(GlobalData.gPlatformHash)\r
+ # Add Package level hash\r
+ if self.DependentPackageList:\r
+ for Pkg in self.DependentPackageList:\r
+ if Pkg.PackageName in GlobalData.gPackageHash[self.Arch]:\r
+ m.update(GlobalData.gPackageHash[self.Arch][Pkg.PackageName])\r
+\r
+ # Add Library hash\r
+ if self.LibraryAutoGenList:\r
+ for Lib in self.LibraryAutoGenList:\r
+ if Lib.Name not in GlobalData.gModuleHash[self.Arch]:\r
+ Lib.GenModuleHash()\r
+ m.update(GlobalData.gModuleHash[self.Arch][Lib.Name])\r
+\r
+ # Add Module self\r
+ f = open(str(self.MetaFile), 'r')\r
+ Content = f.read()\r
+ f.close()\r
+ m.update(Content)\r
+ # Add Module's source files\r
+ if self.SourceFileList:\r
+ for File in self.SourceFileList:\r
+ f = open(str(File), 'r')\r
+ Content = f.read()\r
+ f.close()\r
+ m.update(Content)\r
+\r
+ ModuleHashFile = path.join(self.BuildDir, self.Name + ".hash")\r
+ if self.Name not in GlobalData.gModuleHash[self.Arch]:\r
+ GlobalData.gModuleHash[self.Arch][self.Name] = m.hexdigest()\r
+ if GlobalData.gBinCacheSource:\r
+ CacheValid = self.AttemptModuleCacheCopy()\r
+ if CacheValid:\r
+ return False\r
+ return SaveFileOnChange(ModuleHashFile, m.hexdigest(), True)\r
+\r
## Decide whether we can skip the ModuleAutoGen process\r
- # If any source file is newer than the modeule than we cannot skip\r
+ def CanSkipbyHash(self):\r
+ if GlobalData.gUseHashCache:\r
+ return not self.GenModuleHash()\r
+\r
+ ## Decide whether we can skip the ModuleAutoGen process\r
+ # If any source file is newer than the module than we cannot skip\r
#\r
def CanSkip(self):\r
if not os.path.exists(self.GetTimeStampPath()):\r
with open(self.GetTimeStampPath(),'r') as f:\r
for source in f:\r
source = source.rstrip('\n')\r
+ if not os.path.exists(source):\r
+ return False\r
if source not in ModuleAutoGen.TimeDict :\r
ModuleAutoGen.TimeDict[source] = os.stat(source)[8]\r
if ModuleAutoGen.TimeDict[source] > DstTimeStamp:\r