Source code for gdeps.boost

#!python3

# Copyright 2007-2017 Gemr. All Rights Reserved.
# Licensed to MIT see LICENSE.txt

import os
import warnings
from pathlib import PureWindowsPath

import gdeps as GDeps

__author__ = 'Suryavarman (http://sourceforge.net/u/suryavarman/profile/)'


ms_boostDefault_Path = '*.DEFAULT.*'


[docs]class boostrapReport(GDeps.Reporting): def __init__(self): GDeps.Reporting.__init__(self) self.m_ErrorRegexp = r"(.*failed.*|.*Failed:.*)" # |.*could not find.*) """ **See:** http://www.boost.org/build/doc/html/jam/miscellaneous.html """ self.m_WarningRegexp = r"(.*warning.*|.*UserWarning:.*)"
[docs]class boostTarget(GDeps.Reporting): def __init__(self): GDeps.Reporting.__init__(self) self.m_ErrorRegexp = r"(.*failed.*|.*error:.*)|.*ERROR:.*" # |.*could not find.*) """ **See:** http://www.boost.org/build/doc/html/jam/miscellaneous.html """ self.m_WarningRegexp = r"(.*warning.*|.*UserWarning:.*)" @staticmethod
[docs] def getReportId(inVariant="release", inLink="shared", inAdressModel="64", inToolSet="gcc", inThreading="multi"): return inToolSet + "-" + inAdressModel + "-" + inVariant + "-" + inAdressModel + "-" + inThreading
[docs]class boost(GDeps.Make): """ To build the boost library is not necessary to use an external boost.build. But if you want you can use your boost.build to build boost. To install boost.build : .. todo:: Watch for boostJam Repository : clone git@github.com:boostorg/build.git // If you haven't a Github account or you don't want add an ssh key use the subversion link on https://github.com/boostorg/build or download the zip file : https://github.com/boostorg/build/archive/develop.zip .. bug:: Sometime as.exe stay running on background and block bootstrap.log .. bug:: has_icu.exe for lack of http://boost.2283326.n4.nabble.com/config-Boost-Build-Configuration-tests-incorrectly-showing-up-on-the-console-td3087500.html """ def __init__(self, inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, inCompilers, inIdes, inExeName="b2.exe", inExePath=ms_boostDefault_Path, inTypeName="boost2"): """ Constructor :param inConfigFile: the config file object :type inConfigFile: GDeps.ConfigFile :param inSectionName: the cmake config section :type inSectionName: str :param inFolderDir: :type inFolderDir: str :param inSolutionName: :type inSolutionName: str :param inArgs: :type inArgs: dic :param inExeName: depend of the boost version. :type inExeName: str :param inExePath: by default boost build is include in tho sources :type inExePath: str :param inTypeName: :type inTypeName: str """ GDeps.Make.__init__(self, inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, inCompilers, inIdes, inExePath if inExePath != ms_boostDefault_Path else inFolderDir, inTypeName) self.m_ExeName = inExeName """ The maker executable name is function of the boost version. """ self.m_UserConfigPath = os.path.normpath(inArgs[GDeps.Keys.ms_boostUserConfigPath]) if GDeps.Keys.ms_boostUserConfigPath in inArgs else "" self.Load()
[docs] def getBuildPath(self): """ **Example:** .\\tools\\build\\v2\engine\\src """ pass
[docs] def read(self, inSection): r""" If you haven't «boost.build» to build boost : You haven't to define a config section with the value >>> exepath=r".\\" if you have boost.build : define the boostrap.bat path **Example** >>> [boost2_build_dir] >>> exepath=r"X:\\boost-build\\" """ GDeps.Make.read(self, inSection)
[docs] def getb2Flags(self, inCompiler): aResult = "" if inCompiler.m_TypeName == GDeps.Clang_64.getTypeName(): aResult = ' cxxflags="-std=c++11 -stdlib=libc++" linkflags="-stdlib=libc++"' # if inToolSet == "msvc-9.0": # aResult = ' --with-system' return aResult
[docs] def getConfigFlags(self, inCompiler): aResult = "" if inCompiler.m_TypeName == GDeps.VC140_64.getTypeName(): """ **See:** http://boost.2283326.n4.nabble.com/Building-with-VC-using-address-model-64-td4647453.html """ aPath = PureWindowsPath(os.path.normpath(inCompiler.getVarsBatDir())) aResult = r' : : <setup-amd64>"' + str(aPath.as_posix()) + r'" <setup-options-amd64>""' if inCompiler.m_TypeName == GDeps.Mingw_64.getTypeName(): aResult = r' : : <compileflags>-m64 <linkflags>-m64' # if( inCompiler.m_TypeName == GDeps.Clang_32.getTypeName() or inCompiler.m_TypeName == GDeps.Clang_64.getTypeName()) : # aResult = r' : : <compatibility>' return aResult
[docs] def writeUserConfigJam(self, inCompiler, inTargetArgs): """ For one compiler we rewrite the user-config.jam close to the project jamroot.jam. **See:** http://www.boost.org/build/doc/html/bbv2/overview/configuration.html """ aAdressModel, aBootStrapId, aBoostId = self.getboostCompilerIds(inCompiler) # with open( self.m_FolderDir + '\\user-config.jam', 'w') as aFile: def localWrite(inFilePath): with open(inFilePath, 'w') as aFile: aConfig = self.getConfigFlags(inCompiler) aConfig = (' : ' + aConfig if aConfig else "") aFile.write('using ' + aBootStrapId + aConfig + " ;") aFileName = 'user-config.jam' aDefault = self.m_ExePath + r'\\src\\kernel\\' + aFileName aUserConfigPath = self.m_UserConfigPath if not aUserConfigPath: aUserConfigPath = os.path.normpath(inTargetArgs.m_Args[GDeps.Keys.ms_boostUserConfigPath]) if GDeps.Keys.ms_boostUserConfigPath in inTargetArgs.m_Args else "" aCustomUserConfigPath = os.path.normpath(aUserConfigPath + r'\\' + aFileName) if aUserConfigPath and os.path.exists(aCustomUserConfigPath): localWrite(aCustomUserConfigPath) else: if os.path.exists(aDefault): localWrite(aDefault) else: aFilePath = self.m_ExePath + r'\\tools\\build\\v2\\' + aFileName if os.path.exists(aFilePath): localWrite(aFilePath) else: assert False, "user-config.jam cannot be find."
[docs] def getboostCompilerIds(self, inCompiler): """ :return: the adress model, compiler id for bootstrap, compiler id for b2/bjam """ aAdresseModel = "32" if inCompiler.getAdressModel() == GDeps.AdressModel.x86 else "64" aBootStrapArgVC = "msvc" aBootStrapId = "" aBoostId = "" def getExpress(): aResult = "" if inCompiler.m_IsExpress: aResult = "express" return aResult if inCompiler.m_TypeName == GDeps.Mingw_32.getTypeName() or inCompiler.m_TypeName == GDeps.Mingw_64.getTypeName(): aBootStrapId = "gcc" # "mingw" aBoostId = "gcc" elif inCompiler.m_TypeName == GDeps.Clang_32.getTypeName() or inCompiler.m_TypeName == GDeps.Clang_64.getTypeName(): aBootStrapId = "clang" aBoostId = "clang" """ .. note: use http://svn.boost.org/svn/boost/branches/release/boost/config/compiler/clang.hpp to build boost with clang """ elif inCompiler.m_TypeName == GDeps.VC140_32.getTypeName() or inCompiler.m_TypeName == GDeps.VC140_64.getTypeName(): aBootStrapId = aBootStrapArgVC aBoostId = "msvc-14.0" elif inCompiler.m_TypeName == GDeps.VC120_32.getTypeName() or inCompiler.m_TypeName == GDeps.VC120_64.getTypeName(): aBootStrapId = aBootStrapArgVC aBoostId = "msvc-12.0" elif inCompiler.m_TypeName == GDeps.VC110_32.getTypeName() or inCompiler.m_TypeName == GDeps.VC110_64.getTypeName(): aBootStrapId = aBootStrapArgVC aBoostId = "msvc-11.0" elif inCompiler.m_TypeName == GDeps.VC100_32.getTypeName() or inCompiler.m_TypeName == GDeps.VC100_64.getTypeName(): aBootStrapId = aBootStrapArgVC aBoostId = "msvc-10.0" elif inCompiler.m_TypeName == GDeps.VC90_32.getTypeName(): aBootStrapId = aBootStrapArgVC aBoostId = "msvc-9.0" + getExpress() elif inCompiler.m_TypeName == GDeps.Dm_32.getTypeName(): aBootStrapId = "dmc" aBoostId = "dmc" else: warnings.warn(self.m_TypeName + " doesn't implement the compiler " + inCompiler.m_TypeName) return aAdresseModel, aBootStrapId, aBoostId
[docs] def callexe(self, inCompiler, inTargetArgs, inLogFilePath, inVariant="release", inLink="shared", inAdressModel="64", inToolSet="gcc", inEnv=os.environ.copy(), inThreading="multi"): aCommand = " toolset=" + inToolSet + " variant=" + inVariant + " threading=" + inThreading + " link=" + inLink + " address-model=" + inAdressModel aCommand += " warnings=on target-os=windows" aCommand += self.getb2Flags(inCompiler) aCommand += " --debug-configuration" aCommand += " -a" # rebuild aArgs = GDeps.getAllParamsString(self.m_Args, inTargetArgs, inCompiler, inSeparator=' ', inEqualSign='=', inRemoveLastSeparator=False) aCommand += " " if aArgs else "" # GDeps.call( self.m_ExeName + " --clean" + aCommand, False, inEnv ) # http://www.boost.org/doc/libs/1_52_0/doc/html/bbv2/overview.html # inCheckCall False because boost cannot build perfectly aExeFilePath = self.m_ExePath + r"\\" + self.m_ExeName aExeFilePath = os.path.normpath(aExeFilePath) GDeps.call(aExeFilePath + aCommand + " -d1 > " + inLogFilePath, False, inEnv)
[docs] def getVariant(self, aTargetArgs): return "release" if aTargetArgs.m_TargetType == GDeps.Target.release_static or aTargetArgs.m_TargetType == GDeps.Target.release_dynamic else "debug"
[docs] def callexes(self, inCompiler, inAdressModel="64", inToolSet="gcc", inEnv=os.environ.copy()): """ :return: A dictionary { reportId : log file path } to make the compiler reporting """ aLogFilePaths = {} if not self.m_TargetsArgs: warnings.warn(self.m_TypeName + "There are no targets") aReportFolder = self.m_FolderDir + r"\\bin\\" if not os.path.exists(aReportFolder): os.mkdir(aReportFolder) for aTargetArgs in self.m_TargetsArgs: self.writeUserConfigJam(inCompiler, aTargetArgs) aVariant = self.getVariant(aTargetArgs) aLink = self.getLink(aTargetArgs) aReportId = boostTarget.getReportId(aVariant, aLink, inAdressModel, inToolSet) aLogFilePath = aReportFolder + aReportId + ".log" self.callexe(inCompiler, aTargetArgs, aLogFilePath, aVariant, aLink, inAdressModel, inToolSet, inEnv) self.m_MacroReporting.append(boostTarget(), aReportId, aLogFilePath, False) aLogFilePaths[aReportId] = aLogFilePath return aLogFilePaths
[docs] def maketargets(self, inCompiler, inAdressModel="64", inBootStrapArg="mingw", inToolSet="gcc"): aCurrentDir = os.getcwd() os.chdir(self.m_ExePath) r""" Bootstrapping the build engine The system cannot find the path specified. '.\build.bat' is not recognized as an internal or external command, operable program or batch file. Failed to bootstrap the build engine Please consult bootstrap.log for further diagnostics. "You should cd into the boost build directory before executing bootstrap.bat." **See:** https://stackoverflow.com/questions/31918133/building-boost-build-bat-is-not-recognized-as-a-program http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html http://www.boost.org/boost-build2/doc/html/bbv2/reference/tools.html#bbv2.reference.tools.compilers https://stackoverflow.com/questions/13956727/building-boost-1-52-with-non-standard-location-of-mingw http://www.boost.org/doc/libs/1_46_1/doc/html/bbv2/installation.html http://wiki.tiker.net/BoostInstallationHowto to build with multi thread use -j4 4 it's the number of processor https://stackoverflow.com/questions/2231227/python-subprocess-popen-with-a-modified-environment https://stackoverflow.com/questions/20669558/how-to-make-subprocess-called-with-call-popen-inherit-environment-variables http://lists.boost.org/boost-users/2013/01/77141.php """ inCompiler.setvars() aEnvironementVariables = os.environ.copy() # the root dir should be in first, the compiler found in the PATH will be used by jam aEnvironementVariables['PATH'] = inCompiler.m_Dir + ";" + aEnvironementVariables['PATH'] aEnvironementVariables['BOOST_ROOT'] = self.m_ExePath """ Unable to load Boost.Build: could not find "boost-build.jam" --------------------------------------------------------------- BOOST_ROOT must be set, either in the environment, or on the command-line with -sBOOST_ROOT=..., to the root of the boost installation. """ aEnvironementVariables['BOOST_JAM_TOOLSET_ROOT'] = inCompiler.m_Dir + r'\\' aEnvironementVariables['BOOST_JAM_TOOLSET'] = inToolSet aBatchFilePath = self.m_ExePath + r"\\bootstrap.bat" aBatchFilePath = os.path.normpath(aBatchFilePath) GDeps.call(aBatchFilePath + " " + inBootStrapArg, False, aEnvironementVariables) aBootStrapLogId = inCompiler.m_TypeName + "-" + inBootStrapArg + "-" + inAdressModel + "-" + inToolSet aBootStrapLogPath = self.m_ExePath + r"\\bootstrap.log" if not os.path.exists(aBootStrapLogPath): aBootStrapLogPath = self.m_ExePath + r"\\bjam.log" if not os.path.exists(aBootStrapLogPath): aBootStrapLogPath = self.m_ExePath + r'\\tools\\build\\bjam.log' assert os.path.exists(aBootStrapLogPath), "The conventional log file path doesn't exist : " + aBootStrapLogPath + " ." aBootStrapLogPath = os.path.normpath(aBootStrapLogPath) self.m_MacroReporting.append(boostrapReport(), aBootStrapLogId, aBootStrapLogPath, False) aBoostBuildPath = self.m_FolderDir + self.getBuildPath() # if os.path.exists( aBoostBuildPath ): # os.chdir( aBoostBuildPath ) # # # http://www.boost.org/doc/libs/1_35_0/doc/html/jam/building.html # GDeps.call( "build.bat " + inBootStrapArg, False, aEnvironementVariables ) # os.chdir( aCurrentDir ) # os.chdir( self.m_ExePath ) os.chdir(self.m_FolderDir) aLogFilePaths = self.callexes(inCompiler, inAdressModel, inToolSet, aEnvironementVariables) for aReportId, aLogFilePath in aLogFilePaths.items(): self.m_MacroReporting.append(inCompiler, inCompiler.m_TypeName + "-" + aReportId, aLogFilePath, False) os.chdir(aCurrentDir)
[docs] def make(self): """ **See:** http://www.boost.org/doc/libs/1_59_0/more/getting_started/unix-variants.html#identify-your-toolset http://www.boost.org/build/doc/html/bbv2/jam.html http://www.boost.org/build/doc/html/bbv2/reference/tools.html **Clang:** http://blog.llvm.org/2010/05/clang-builds-boost.html https://stackoverflow.com/questions/8486077/how-to-compile-link-boost-with-clang-libc **Digital Mars** http://www.boost.org/doc/libs/1_33_1/tools/build/v1/dmc-stlport-tools.jam """ self.m_MacroReporting = GDeps.Make.make(self) for aCompiler in self.m_Compilers: aAdressModel, aBootStrapId, aBoostId = self.getboostCompilerIds(aCompiler) self.maketargets(aCompiler, aAdressModel, aBootStrapId, aBoostId) return self.m_MacroReporting
[docs]class boostJam(boost): """ **See:** http://www.boost.org/doc/libs/1_46_1/more/getting_started/windows.html """ def __init__(self, inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, inCompilers, inIdes=[], inExePath=ms_boostDefault_Path): """ :param inExePath: by default boost build is include in tho sources """ boost.__init__(self, inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, inCompilers, inIdes, boostJam.getExeName(), inExePath, boostJam.getTypeName()) @staticmethod
[docs] def getTypeName(): return "boostJam"
@staticmethod
[docs] def getExeName(): return "bjam.exe"
[docs] def getBuildPath(self): return r".\\tools\\build\\v2\\engine\\src"
[docs]class boost2(boost): """ **See:** http://www.boost.org/doc/libs/master/doc/html/bbv2.html """ def __init__(self, inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, inCompilers, inIdes=[], inExePath=ms_boostDefault_Path): """ :param inExePath: by default boost build is include in tho sources **See:** http://www.boost.org/build/doc/html/bbv2/overview/invocation.html usage: b2.exe [ options ] targets... -a Build all targets, even if they are current. -dx Set the debug level to x (0-9). -fx Read x instead of Jambase. -jx Run up to x shell commands concurrently. -lx Limit actions to x number of seconds after which they are stopped. -mx Maximum target output saved (kb), default is to save all output. -n Don't actually execute the updating actions. -ox Mirror all output to file x. -px x=0, pipes action stdout and stderr merged into action output. -q Quit quickly as soon as a target fails. -sx=y Set variable x=y, overriding environment. -tx Rebuild x, even if it is up-to-date. -v Print the version of jam and exit. --x Option is ignored. """ boost.__init__(self, inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, inCompilers, inIdes, boost2.getExeName(), inExePath, boost2.getTypeName()) @staticmethod
[docs] def getTypeName(): return "boost2"
@staticmethod
[docs] def getExeName(): return "b2.exe"
[docs] def getBuildPath( self ): return r".\\tools\\build\\v2\\engine"
[docs]class boostSelector: def __init__(self, inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, inCompilers, inIdes=[], inExePath=ms_boostDefault_Path): self.m_boosts = [] aJamCompilers = [] aB2Compilers = [] for aCompiler in inCompilers: if self.isACompilerForJam(aCompiler): aJamCompilers.append(aCompiler) if self.isACompilerForB2(aCompiler): aB2Compilers.append(aCompiler) self.m_boosts.append(boostJam(inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, aJamCompilers, inIdes, inExePath)) self.m_boosts.append(boost2(inConfigFile, inSectionName, inFolderDir, inSolutionName, inArgs, inTargetsArgs, aB2Compilers, inIdes, inExePath))
[docs] def isACompilerForJam(self, inCompiler): aResult = False if inCompiler.m_TypeName == GDeps.VC90_32.getTypeName(): aResult = True return aResult
[docs] def isACompilerForB2(self, inCompiler): aResult = False if inCompiler.m_TypeName == GDeps.Mingw_32.getTypeName(): aResult = True elif inCompiler.m_TypeName == GDeps.Mingw_64.getTypeName(): aResult = True elif inCompiler.m_TypeName == GDeps.Clang_32.getTypeName(): aResult = True elif inCompiler.m_TypeName == GDeps.Clang_64.getTypeName(): aResult = True elif inCompiler.m_TypeName == GDeps.VC140_32.getTypeName(): aResult = True elif inCompiler.m_TypeName == GDeps.VC140_64.getTypeName(): aResult = True elif inCompiler.m_TypeName == GDeps.VC120_32.getTypeName(): aResult = True elif inCompiler.m_TypeName == GDeps.VC120_64.getTypeName(): aResult = True elif inCompiler.m_TypeName == GDeps.VC110_32.getTypeName(): aResult = True elif inCompiler.m_TypeName == GDeps.VC110_64.getTypeName(): aResult = True elif inCompiler.m_TypeName == GDeps.VC100_32.getTypeName(): aResult = True elif inCompiler.m_TypeName == GDeps.VC100_64.getTypeName(): aResult = True return aResult
[docs] def make(self): aMacroReporting = GDeps.MacroReporting() for aboost in self.m_boosts: aReport = aboost.make() for aErrorKey, aErrorValue in aReport.m_Errors.items(): aMacroReporting.m_Errors[aErrorKey] = aErrorValue for aWarningKey, aWarningValue in aReport.m_Warnings.items(): aMacroReporting.m_Warnings[aWarningKey] = aWarningValue return aMacroReporting