#!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 getLink(self, aTargetArgs):
return "shared" if aTargetArgs.m_TargetType == GDeps.Target.release_dynamic or aTargetArgs.m_TargetType == GDeps.Target.debug_dynamic else "static"
[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