summaryrefslogtreecommitdiff
path: root/BaseTools/Source/Python/build
diff options
context:
space:
mode:
authorYonghong Zhu <yonghong.zhu@intel.com>2016-03-31 14:05:59 +0800
committerHao Wu <hao.a.wu@intel.com>2016-07-13 09:31:23 +0800
commit170591e02fa4c2022fcd042a45713e976445b5d0 (patch)
tree7a0362deb2719f1aeec5dc36bedf6a13659a3a70 /BaseTools/Source/Python/build
parent13fde91deab96c7a267fc27796e00ea6bceb7724 (diff)
downloadedk2-platforms-170591e02fa4c2022fcd042a45713e976445b5d0.tar.xz
BaseTools: Add support to merge Prebuild and Postbuild into build Process
This feature is enhance build tool to incorporate execution of prebuild and postbuild. 1.Prebuild script a.DEFINE PREBUILD in DSC [Defines] section b.Build command -D PREBUILD to override the one in DSC [Defines] section 1)If PREBUILD is a file, then this file will be used as prebuild script. 2)If PREBUILD is empty, then prebuild script will be disabled. 3)If PREBUILD is not defined in [Defines] section and not passed in on command line, then prebuild script is also disabled. 2.Prebuild option a.All options of build tool b.TARGET, ARCH and TOOL_CHAIN_TAG value, Those value will be from target.txt file if they are not in build command line. c.Additional options following prebuild definition. Quotes are needed when these additional options are present. d.Quotes would also be required if the path to the prebuild command contains space or special characters. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu <yonghong.zhu@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> (cherry picked from commit f0dc69e61bf2316dcf7cc75eb7e4ba374a5b2832)
Diffstat (limited to 'BaseTools/Source/Python/build')
-rw-r--r--BaseTools/Source/Python/build/build.py198
1 files changed, 189 insertions, 9 deletions
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: