diff --git a/BaseTools/Source/Python/Common/BuildToolError.py b/BaseTools/Source/Python/Common/BuildToolError.py index 0a393fec60..bee5850fc5 100644 --- a/BaseTools/Source/Python/Common/BuildToolError.py +++ b/BaseTools/Source/Python/Common/BuildToolError.py @@ -1,7 +1,7 @@ ## @file # Standardized Error Hanlding infrastructures. # -# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -78,6 +78,8 @@ BUILD_ERROR = 0xF002 GENFDS_ERROR = 0xF003 ECC_ERROR = 0xF004 EOT_ERROR = 0xF005 +PREBUILD_ERROR = 0xF007 +POSTBUILD_ERROR = 0xF008 DDC_ERROR = 0xF009 WARNING_AS_ERROR = 0xF006 MIGRATION_ERROR = 0xF010 diff --git a/BaseTools/Source/Python/Common/DataType.py b/BaseTools/Source/Python/Common/DataType.py index 4fd46edab9..1fe1ee458b 100644 --- a/BaseTools/Source/Python/Common/DataType.py +++ b/BaseTools/Source/Python/Common/DataType.py @@ -1,7 +1,7 @@ ## @file # This file is used to define common static strings used by INF/DEC/DSC files # -# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.
# Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -410,7 +410,8 @@ TAB_DSC_DEFINES_DEFINE = 'DEFINE' TAB_DSC_DEFINES_VPD_TOOL_GUID = 'VPD_TOOL_GUID' TAB_FIX_LOAD_TOP_MEMORY_ADDRESS = 'FIX_LOAD_TOP_MEMORY_ADDRESS' TAB_DSC_DEFINES_EDKGLOBAL = 'EDK_GLOBAL' - +TAB_DSC_PREBUILD = 'PREBUILD' +TAB_DSC_POSTBUILD = 'POSTBUILD' # # TargetTxt Definitions # diff --git a/BaseTools/Source/Python/Common/DscClassObject.py b/BaseTools/Source/Python/Common/DscClassObject.py index 788a75e267..c2fa1c275a 100644 --- a/BaseTools/Source/Python/Common/DscClassObject.py +++ b/BaseTools/Source/Python/Common/DscClassObject.py @@ -1,7 +1,7 @@ ## @file # This file is used to define each component of DSC file # -# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -98,11 +98,10 @@ class Dsc(DscObject): self.UserExtensions = '' self.WorkspaceDir = WorkspaceDir self.IsToDatabase = IsToDatabase - - self.Cur = Database.Cur - self.TblFile = Database.TblFile - self.TblDsc = Database.TblDsc - + if Database: + self.Cur = Database.Cur + self.TblFile = Database.TblFile + self.TblDsc = Database.TblDsc self.KeyList = [ TAB_SKUIDS, TAB_LIBRARIES, TAB_LIBRARY_CLASSES, TAB_BUILD_OPTIONS, TAB_PCDS_FIXED_AT_BUILD_NULL, \ @@ -252,6 +251,12 @@ class Dsc(DscObject): Fdf = PlatformFlashDefinitionFileClass() Fdf.FilePath = NormPath(QueryDefinesItem(self.TblDsc, TAB_DSC_DEFINES_FLASH_DEFINITION, Arch, self.FileID)[0]) self.Platform.FlashDefinitionFile = Fdf + Prebuild = BuildScriptClass() + Prebuild.FilePath = NormPath(QueryDefinesItem(self.TblDsc, TAB_DSC_PREBUILD, Arch, self.FileID)[0]) + self.Platform.Prebuild = Prebuild + Postbuild = BuildScriptClass() + Postbuild.FilePath = NormPath(QueryDefinesItem(self.TblDsc, TAB_DSC_POSTBUILD, Arch, self.FileID)[0]) + self.Platform.Postbuild = Postbuild ## GenBuildOptions # diff --git a/BaseTools/Source/Python/Common/GlobalData.py b/BaseTools/Source/Python/Common/GlobalData.py index c3439ebbfc..51e370925d 100644 --- a/BaseTools/Source/Python/Common/GlobalData.py +++ b/BaseTools/Source/Python/Common/GlobalData.py @@ -23,6 +23,7 @@ gEcpSource = "EdkCompatibilityPkg" gOptions = None gCaseInsensitive = False gAllFiles = None +gCommand = None gGlobalDefines = {} gPlatformDefines = {} diff --git a/BaseTools/Source/Python/CommonDataClass/PlatformClass.py b/BaseTools/Source/Python/CommonDataClass/PlatformClass.py index a95ec068b1..a93d1ce2a1 100644 --- a/BaseTools/Source/Python/CommonDataClass/PlatformClass.py +++ b/BaseTools/Source/Python/CommonDataClass/PlatformClass.py @@ -1,7 +1,7 @@ ## @file # This file is used to define a class object to describe a platform # -# Copyright (c) 2007, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -86,6 +86,24 @@ class PlatformFlashDefinitionFileClass(object): self.Preferred = False self.FilePath = '' +## BuildScriptClass +# +# This class defined PREBUILD/POSTBUILD item used in platform file +# +# @param object: Inherited from object class +# +# @var Id: To store value for Id +# @var UiName: To store value for UiName +# @var Preferred: To store value for Preferred +# @var FilePath: To store value for FilePath +# +class BuildScriptClass(object): + def __init__(self): + self.Id = '' + self.UiName = '' + self.Preferred = False + self.FilePath = '' + ## PlatformFvImageOptionClass # # This class defined FvImageOption item used in platform file @@ -401,6 +419,10 @@ class PlatformModuleClasses(IncludeStatementClass): # PlatformModuleClasses # @var FlashDefinitionFile: To store value for FlashDefinitionFile, it is a structure as # PlatformFlashDefinitionFileClass +# @var Prebuild: To store value for PREBUILD, it is a structure as +# BuildScriptClass +# @var Postbuild: To store value for POSTBUILD, it is a structure as +# BuildScriptClass # @var BuildOptions: To store value for BuildOptions, it is a structure as # PlatformBuildOptionClasses # @var DynamicPcdBuildDefinitions: To store value for DynamicPcdBuildDefinitions, it is a list structure as @@ -418,6 +440,8 @@ class PlatformClass(object): self.LibraryClasses = PlatformLibraryClasses() self.Modules = PlatformModuleClasses() self.FlashDefinitionFile = PlatformFlashDefinitionFileClass() + self.Prebuild = BuildScriptClass() + self.Postbuild = BuildScriptClass() self.BuildOptions = PlatformBuildOptionClasses() self.DynamicPcdBuildDefinitions = [] self.Fdf = [] diff --git a/BaseTools/Source/Python/Workspace/MetaFileParser.py b/BaseTools/Source/Python/Workspace/MetaFileParser.py index 451d8547d2..3b6a3c0dfa 100644 --- a/BaseTools/Source/Python/Workspace/MetaFileParser.py +++ b/BaseTools/Source/Python/Workspace/MetaFileParser.py @@ -1,7 +1,7 @@ ## @file # This file is used to parse meta files # -# Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.
+# Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.
# Copyright (c) 2015, Hewlett Packard Enterprise Development, L.P.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -831,7 +831,9 @@ class DscParser(MetaFileParser): "ISO_LANGUAGES", "TIME_STAMP_FILE", "VPD_TOOL_GUID", - "FIX_LOAD_TOP_MEMORY_ADDRESS" + "FIX_LOAD_TOP_MEMORY_ADDRESS", + "PREBUILD", + "POSTBUILD" ] SubSectionDefineKeywords = [ diff --git a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py index 1f236e83ff..b2c4d6e4da 100644 --- a/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py +++ b/BaseTools/Source/Python/Workspace/WorkspaceDatabase.py @@ -1,7 +1,7 @@ ## @file # This file is used to create a database used by build tool # -# Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.
+# Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.
# This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License # which accompanies this distribution. The full text of the license may be found at @@ -137,6 +137,8 @@ class DscBuildData(PlatformBuildClassObject): self._PcdInfoFlag = None self._VarCheckFlag = None self._FlashDefinition = None + self._Prebuild = None + self._Postbuild = None self._BuildNumber = None self._MakefileName = None self._BsBaseAddress = None @@ -227,6 +229,10 @@ class DscBuildData(PlatformBuildClassObject): if ErrorCode != 0: EdkLogger.error('build', ErrorCode, File=self.MetaFile, Line=Record[-1], ExtraData=ErrorInfo) + elif Name == TAB_DSC_PREBUILD: + self._Prebuild = PathClass(NormPath(Record[2], self._Macros), GlobalData.gWorkspace) + elif Name == TAB_DSC_POSTBUILD: + self._Postbuild = PathClass(NormPath(Record[2], self._Macros), GlobalData.gWorkspace) elif Name == TAB_DSC_DEFINES_SUPPORTED_ARCHITECTURES: self._SupArchList = GetSplitValueList(Record[2], TAB_VALUE_SPLIT) elif Name == TAB_DSC_DEFINES_BUILD_TARGETS: @@ -399,6 +405,22 @@ class DscBuildData(PlatformBuildClassObject): self._FlashDefinition = '' return self._FlashDefinition + def _GetPrebuild(self): + if self._Prebuild == None: + if self._Header == None: + self._GetHeaderInfo() + if self._Prebuild == None: + self._Prebuild = '' + return self._Prebuild + + def _GetPostbuild(self): + if self._Postbuild == None: + if self._Header == None: + self._GetHeaderInfo() + if self._Postbuild == None: + self._Postbuild = '' + return self._Postbuild + ## Retrieve FLASH_DEFINITION def _GetBuildNumber(self): if self._BuildNumber == None: @@ -1207,6 +1229,8 @@ class DscBuildData(PlatformBuildClassObject): PcdInfoFlag = property(_GetPcdInfoFlag) VarCheckFlag = property(_GetVarCheckFlag) FlashDefinition = property(_GetFdfFile) + Prebuild = property(_GetPrebuild) + Postbuild = property(_GetPostbuild) BuildNumber = property(_GetBuildNumber) MakefileName = property(_GetMakefileName) BsBaseAddress = property(_GetBsBaseAddress) @@ -2979,6 +3003,13 @@ determine whether database file is out of date!\n") PlatformList.append(Platform) return PlatformList + def _MapPlatform(self, Dscfile): + try: + Platform = self.BuildObject[PathClass(Dscfile), 'COMMON'] + except: + Platform = None + return Platform + PlatformList = property(_GetPlatformList) ## diff --git a/BaseTools/Source/Python/build/build.py b/BaseTools/Source/Python/build/build.py index ece79ea109..37afe52ac2 100644 --- a/BaseTools/Source/Python/build/build.py +++ b/BaseTools/Source/Python/build/build.py @@ -25,6 +25,7 @@ import time import platform import traceback import encodings.ascii +import itertools from struct import * from threading import * @@ -782,15 +783,16 @@ class Build(): self.LoadFixAddress = 0 self.UniFlag = BuildOptions.Flag self.BuildModules = [] - + self.Db_Flag = False + self.LaunchPrebuildFlag = False + self.PrebuildScript = '' + self.PostbuildScript = '' + self.PlatformBuildPath = os.path.join(GlobalData.gConfDirectory,'.cache', '.PlatformBuild') if BuildOptions.CommandLength: GlobalData.gCommandMaxLength = BuildOptions.CommandLength # print dot character during doing some time-consuming work self.Progress = Utils.Progressor() - - self.InitBuild() - # print current build environment and configuration EdkLogger.quiet("%-16s = %s" % ("WORKSPACE", os.environ["WORKSPACE"])) if "PACKAGES_PATH" in os.environ: @@ -804,8 +806,18 @@ class Build(): # Print the same path style with WORKSPACE env. EdkLogger.quiet("%-16s = %s" % ("EDK_TOOLS_BIN", os.path.normcase(os.path.normpath(os.environ["EDK_TOOLS_BIN"])))) - EdkLogger.info("") + self.InitPreBuild() + self.InitPostBuild() + if self.PrebuildScript: + EdkLogger.quiet("%-16s = %s" % ("PREBUILD", self.PrebuildScript)) + if self.PostbuildScript: + EdkLogger.quiet("%-16s = %s" % ("POSTBUILD", self.PostbuildScript)) + if self.PrebuildScript: + self.LaunchPrebuild() + if not (self.LaunchPrebuildFlag and os.path.exists(self.PlatformBuildPath)): + self.InitBuild() + EdkLogger.info("") os.chdir(self.WorkspaceDir) ## Load configuration @@ -903,8 +915,169 @@ class Build(): EdkLogger.error("build", ErrorCode, ExtraData=ErrorInfo) # create metafile database - self.Db.InitDatabase() + if not self.Db_Flag: + self.Db.InitDatabase() + def InitPreBuild(self): + self.LoadConfiguration() + if self.BuildTargetList: + GlobalData.gGlobalDefines['TARGET'] = self.BuildTargetList[0] + if self.ArchList: + GlobalData.gGlobalDefines['ARCH'] = self.ArchList[0] + if self.ToolChainList: + GlobalData.gGlobalDefines['TOOLCHAIN'] = self.ToolChainList[0] + GlobalData.gGlobalDefines['TOOL_CHAIN_TAG'] = self.ToolChainList[0] + if 'PREBUILD' in GlobalData.gCommandLineDefines.keys(): + self.Prebuild = GlobalData.gCommandLineDefines.get('PREBUILD') + else: + self.Db.InitDatabase() + self.Db_Flag = True + Platform = self.Db._MapPlatform(str(self.PlatformFile)) + self.Prebuild = str(Platform.Prebuild) + if self.Prebuild: + PrebuildList = self.Prebuild.split() + if not os.path.isabs(PrebuildList[0]): + PrebuildList[0] = mws.join(self.WorkspaceDir, PrebuildList[0]) + if os.path.isfile(PrebuildList[0]): + self.PrebuildScript = PrebuildList[0] + self.Prebuild = ' '.join(PrebuildList) + self.Prebuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList) + #self.LaunchPrebuild() + else: + EdkLogger.error("Prebuild", PREBUILD_ERROR, "the prebuild script %s is not exist.\n If you'd like to disable the Prebuild process, please use the format: -D PREBUILD=\"\" " %(PrebuildList[0])) + + def InitPostBuild(self): + if 'POSTBUILD' in GlobalData.gCommandLineDefines.keys(): + self.Postbuild = GlobalData.gCommandLineDefines.get('POSTBUILD') + else: + Platform = self.Db._MapPlatform(str(self.PlatformFile)) + self.Postbuild = str(Platform.Postbuild) + if self.Postbuild: + PostbuildList = self.Postbuild.split() + if not os.path.isabs(PostbuildList[0]): + PostbuildList[0] = mws.join(self.WorkspaceDir, PostbuildList[0]) + if os.path.isfile(PostbuildList[0]): + self.PostbuildScript = PostbuildList[0] + self.Postbuild = ' '.join(PostbuildList) + self.Postbuild += self.PassCommandOption(self.BuildTargetList, self.ArchList, self.ToolChainList) + #self.LanuchPostbuild() + else: + EdkLogger.error("Postbuild", POSTBUILD_ERROR, "the postbuild script %s is not exist.\n If you'd like to disable the Postbuild process, please use the format: -D POSTBUILD=\"\" " %(PostbuildList[0])) + + def PassCommandOption(self, BuildTarget, TargetArch, ToolChain): + BuildStr = '' + if GlobalData.gCommand and isinstance(GlobalData.gCommand, list): + BuildStr += ' ' + ' '.join(GlobalData.gCommand) + TargetFlag = False + ArchFlag = False + ToolChainFlag = False + + if GlobalData.gOptions and not GlobalData.gOptions.BuildTarget: + TargetFlag = True + if GlobalData.gOptions and not GlobalData.gOptions.TargetArch: + ArchFlag = True + if GlobalData.gOptions and not GlobalData.gOptions.ToolChain: + ToolChainFlag = True + + if TargetFlag and BuildTarget: + if isinstance(BuildTarget, list) or isinstance(BuildTarget, tuple): + BuildStr += ' -b ' + ' -b '.join(BuildTarget) + elif isinstance(BuildTarget, str): + BuildStr += ' -b ' + BuildTarget + if ArchFlag and TargetArch: + if isinstance(TargetArch, list) or isinstance(TargetArch, tuple): + BuildStr += ' -a ' + ' -a '.join(TargetArch) + elif isinstance(TargetArch, str): + BuildStr += ' -a ' + TargetArch + if ToolChainFlag and ToolChain: + if isinstance(ToolChain, list) or isinstance(ToolChain, tuple): + BuildStr += ' -t ' + ' -t '.join(ToolChain) + elif isinstance(ToolChain, str): + BuildStr += ' -t ' + ToolChain + + return BuildStr + + def LaunchPrebuild(self): + if self.Prebuild: + EdkLogger.info("\n- Prebuild Start -\n") + self.LaunchPrebuildFlag = True + PrebuildEnvFile = os.path.join(GlobalData.gConfDirectory,'.cache','.PrebuildEnv') + if os.path.isfile(PrebuildEnvFile): + os.remove(PrebuildEnvFile) + if os.path.isfile(self.PlatformBuildPath): + os.remove(self.PlatformBuildPath) + if sys.platform == "win32": + args = ' && '.join((self.Prebuild, 'set > ' + PrebuildEnvFile)) + Process = Popen(args, stdout=PIPE, stderr=PIPE) + else: + args = ' && '.join((self.Prebuild, 'env > ' + PrebuildEnvFile)) + Process = Popen(args, stdout=PIPE, stderr=PIPE, shell=True, executable="/bin/bash") + + # launch two threads to read the STDOUT and STDERR + EndOfProcedure = Event() + EndOfProcedure.clear() + if Process.stdout: + StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure)) + StdOutThread.setName("STDOUT-Redirector") + StdOutThread.setDaemon(False) + StdOutThread.start() + + if Process.stderr: + StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure)) + StdErrThread.setName("STDERR-Redirector") + StdErrThread.setDaemon(False) + StdErrThread.start() + # waiting for program exit + Process.wait() + + if Process.stdout: + StdOutThread.join() + if Process.stderr: + StdErrThread.join() + if Process.returncode != 0 : + EdkLogger.error("Prebuild", PREBUILD_ERROR, 'Prebuild process is not success!') + + if os.path.exists(PrebuildEnvFile): + f = open(PrebuildEnvFile) + envs = f.readlines() + f.close() + envs = itertools.imap(lambda l: l.split('=',1), envs) + envs = itertools.ifilter(lambda l: len(l) == 2, envs) + envs = itertools.imap(lambda l: [i.strip() for i in l], envs) + os.environ.update(dict(envs)) + EdkLogger.info("\n- Prebuild Done -\n") + + def LanuchPostbuild(self): + if self.Postbuild: + EdkLogger.info("\n- Postbuild Start -\n") + if sys.platform == "win32": + Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE) + else: + Process = Popen(self.Postbuild, stdout=PIPE, stderr=PIPE, shell=True, executable="/bin/bash") + # launch two threads to read the STDOUT and STDERR + EndOfProcedure = Event() + EndOfProcedure.clear() + if Process.stdout: + StdOutThread = Thread(target=ReadMessage, args=(Process.stdout, EdkLogger.info, EndOfProcedure)) + StdOutThread.setName("STDOUT-Redirector") + StdOutThread.setDaemon(False) + StdOutThread.start() + + if Process.stderr: + StdErrThread = Thread(target=ReadMessage, args=(Process.stderr, EdkLogger.quiet, EndOfProcedure)) + StdErrThread.setName("STDERR-Redirector") + StdErrThread.setDaemon(False) + StdErrThread.start() + # waiting for program exit + Process.wait() + + if Process.stdout: + StdOutThread.join() + if Process.stderr: + StdErrThread.join() + if Process.returncode != 0 : + EdkLogger.error("Postbuild", POSTBUILD_ERROR, 'Postbuild process is not success!') + EdkLogger.info("\n- Postbuild Done -\n") ## Build a module or platform # # Create autogen code and makefile for a module or platform, and the launch @@ -1414,6 +1587,7 @@ class Build(): ## Build active platform for different build targets and different tool chains # def _BuildPlatform(self): + SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False) for BuildTarget in self.BuildTargetList: GlobalData.gGlobalDefines['TARGET'] = BuildTarget for ToolChain in self.ToolChainList: @@ -1587,6 +1761,7 @@ class Build(): ## Build a platform in multi-thread mode # def _MultiThreadBuildPlatform(self): + SaveFileOnChange(self.PlatformBuildPath, '# DO NOT EDIT \n# FILE auto-generated\n', False) for BuildTarget in self.BuildTargetList: GlobalData.gGlobalDefines['TARGET'] = BuildTarget for ToolChain in self.ToolChainList: @@ -1961,7 +2136,7 @@ def Main(): # Initialize log system EdkLogger.Initialize() - + GlobalData.gCommand = sys.argv[1:] # # Parse the options and args # @@ -2059,7 +2234,8 @@ def Main(): MyBuild = Build(Target, Workspace, Option) GlobalData.gCommandLineDefines['ARCH'] = ' '.join(MyBuild.ArchList) - MyBuild.Launch() + if not (MyBuild.LaunchPrebuildFlag and os.path.exists(MyBuild.PlatformBuildPath)): + MyBuild.Launch() # Drop temp tables to avoid database locked. for TmpTableName in TmpTableDict: SqlCommand = """drop table IF EXISTS %s""" % TmpTableName @@ -2116,7 +2292,11 @@ def Main(): Utils.ClearDuplicatedInf() if ReturnCode == 0: - Conclusion = "Done" + try: + MyBuild.LanuchPostbuild() + Conclusion = "Done" + except: + Conclusion = "Failed" elif ReturnCode == ABORT_ERROR: Conclusion = "Aborted" else: