mirror of
https://github.com/boostorg/python.git
synced 2026-01-19 16:32:16 +00:00
Add SCons-based build system.
This commit is contained in:
34
SConscript
Normal file
34
SConscript
Normal file
@@ -0,0 +1,34 @@
|
||||
# -*- python -*-
|
||||
|
||||
Import("env")
|
||||
|
||||
env.Append(CPPPATH = "#/include",CPPDEFINES = ["BOOST_ALL_NO_LIB=1"])
|
||||
|
||||
env.AppendUnique(CPPDEFINES = ["${LINK_DYNAMIC and 'BOOST_PYTHON_DYN_LINK=1' or []}"])
|
||||
for variant in env["variant"]:
|
||||
env["current_variant"] = variant
|
||||
env.SetProperty(profile = False)
|
||||
if variant == "release":
|
||||
env.SetProperty(optimize = "speed", debug = False)
|
||||
elif variant == "debug":
|
||||
env.SetProperty(optimize = "no", debug = True)
|
||||
elif variant == "profile":
|
||||
env.SetProperty(optimize = "speed", profile = True, debug = True)
|
||||
for linking in env["link"]:
|
||||
env["linking"] = linking
|
||||
if linking == "dynamic":
|
||||
env["LINK_DYNAMIC"] = True
|
||||
else:
|
||||
env["LINK_DYNAMIC"] = False
|
||||
for threading in env["threading"]:
|
||||
env["current_threading"] = threading
|
||||
env.SetProperty(threading = threading)
|
||||
variant_dir=env.subst("$BOOST_CURRENT_VARIANT_DIR")
|
||||
|
||||
env.SConscript("src/SConscript", variant_dir=variant_dir + '/src',
|
||||
exports = { "env" : env.Clone(BOOST_LIB = 'python') })
|
||||
if GetOption("test"):
|
||||
test_env = env.Clone(BOOST_LIB = 'python', BOOST_TEST = True)
|
||||
test_env.BoostUseLib('python')
|
||||
env.SConscript("test/SConscript", variant_dir=variant_dir + '/test',
|
||||
exports = { "env" : test_env })
|
||||
82
SConstruct
Normal file
82
SConstruct
Normal file
@@ -0,0 +1,82 @@
|
||||
# -*- python -*-
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import SCons.Script.Main
|
||||
import config
|
||||
import config.ui
|
||||
import platform
|
||||
import os
|
||||
|
||||
|
||||
#
|
||||
# We try to mimic the typical autotools-workflow.
|
||||
#
|
||||
# * In a 'configure' step all the essential build parameters are established
|
||||
# (either by explicit command-line arguments or from configure checks)
|
||||
# * A subsequent build step can then simply read the cached variables, so
|
||||
# users don't have to memorize and re-issue the arguments on each subsequent
|
||||
# invocation, and neither do the config checks need to be re-run.
|
||||
#
|
||||
# The essential part here is to define a 'config' target, which removes any
|
||||
# caches that may still be lingering around, then runs the checks.
|
||||
|
||||
if 'config' in COMMAND_LINE_TARGETS:
|
||||
# Clear the cache
|
||||
try: os.remove('bin.SCons/config.py')
|
||||
except: pass
|
||||
if not os.path.exists('bin.SCons/'):
|
||||
os.mkdir('bin.SCons/')
|
||||
vars = Variables('bin.SCons/config.py', ARGUMENTS)
|
||||
config.add_options(vars)
|
||||
arch = ARGUMENTS.get('arch', platform.machine())
|
||||
env = Environment(toolpath=['config/tools'],
|
||||
tools=['default', 'libs', 'tests'],
|
||||
variables=vars,
|
||||
TARGET_ARCH=arch)
|
||||
|
||||
Help(config.ui.help(vars, env) + """
|
||||
Variables are saved in bin.SCons/config.py and persist between scons invocations.
|
||||
""")
|
||||
|
||||
if GetOption('help'):
|
||||
Return()
|
||||
|
||||
build_dir = config.prepare_build_dir(env)
|
||||
config_log = '{}/config.log'.format(build_dir)
|
||||
|
||||
# configure
|
||||
SConsignFile('{}/.sconsign'.format(build_dir))
|
||||
#env.Decider('MD5-timestamp')
|
||||
env.Decider('timestamp-newer')
|
||||
checks = config.get_checks()
|
||||
if 'config' in COMMAND_LINE_TARGETS:
|
||||
conf=env.Configure(custom_tests=checks, log_file=config_log, conf_dir=build_dir)
|
||||
if False in (getattr(conf, c)() for c in checks):
|
||||
Exit(1)
|
||||
env = conf.Finish()
|
||||
vars.Save('bin.SCons/config.py', env)
|
||||
|
||||
if not os.path.exists(config_log):
|
||||
print('Please run `scons config` first. (See `scons -h` for available options.)')
|
||||
Exit(1)
|
||||
|
||||
if not GetOption('verbose'):
|
||||
config.ui.pretty_output(env)
|
||||
|
||||
# build
|
||||
env['BPL_VERSION'] = '1.61'
|
||||
for e in config.variants(env):
|
||||
variant_dir=e.subst("$BOOST_CURRENT_VARIANT_DIR")
|
||||
e.SConscript('src/SConscript', variant_dir=variant_dir + '/src',
|
||||
exports = { 'env' : e.Clone(BOOST_LIB = 'python') })
|
||||
if 'test' in COMMAND_LINE_TARGETS:
|
||||
test_env = e.Clone(BOOST_LIB = 'python', BOOST_TEST = True)
|
||||
test_env.BoostUseLib('python')
|
||||
e.SConscript('test/SConscript', variant_dir=variant_dir + '/test',
|
||||
exports = { 'env' : test_env })
|
||||
116
config/__init__.py
Normal file
116
config/__init__.py
Normal file
@@ -0,0 +1,116 @@
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from SCons.Variables import *
|
||||
from SCons.Script import AddOption
|
||||
from collections import OrderedDict
|
||||
import platform
|
||||
from . import ui
|
||||
from . import python
|
||||
from . import boost
|
||||
|
||||
def add_options(vars):
|
||||
ui.add_option('-V', '--verbose', dest='verbose', action='store_true', help='verbose mode: print full commands.')
|
||||
python.add_options(vars)
|
||||
boost.add_options(vars)
|
||||
|
||||
vars.Add('CPPPATH', converter=lambda v:v.split())
|
||||
vars.Add('CCFLAGS', converter=lambda v:v.split())
|
||||
vars.Add('LIBPATH', converter=lambda v:v.split())
|
||||
vars.Add('LIBS', converter=lambda v:v.split())
|
||||
vars.Add('PYTHON')
|
||||
vars.Add('PYTHONLIBS')
|
||||
|
||||
ui.add_variable(vars, ("arch", "target architeture", platform.machine()))
|
||||
ui.add_variable(vars, ("toolchain", "toolchain to use", 'gcc'))
|
||||
ui.add_variable(vars, ListVariable("variant", "Build configuration", "release", ["release", "debug", "profile"]))
|
||||
ui.add_variable(vars, ListVariable("link", "Library linking", "dynamic", ["static", "dynamic"]))
|
||||
ui.add_variable(vars, ListVariable("threading", "Multi-threading support", "multi", ["single", "multi"]))
|
||||
ui.add_variable(vars, EnumVariable("layout", "Layout of library names and header locations", "versioned", ["versioned", "system"]))
|
||||
ui.add_variable(vars, PathVariable("stagedir", "If --stage is passed install only compiled library files in this location", "stage", PathVariable.PathAccept))
|
||||
ui.add_variable(vars, PathVariable("prefix", "Install prefix", "/usr/local", PathVariable.PathAccept))
|
||||
|
||||
|
||||
def get_checks():
|
||||
checks = OrderedDict()
|
||||
checks['python'] = python.check
|
||||
checks['boost'] = boost.check
|
||||
return checks
|
||||
|
||||
|
||||
def set_property(env, **kw):
|
||||
|
||||
from toolchains.gcc import features as gcc_features
|
||||
from toolchains.msvc import features as msvc_features
|
||||
|
||||
if 'gcc' in env['TOOLS']: features = gcc_features
|
||||
elif 'msvc' in env['TOOLS']: features = msvc_features
|
||||
else: raise Error('unknown toolchain')
|
||||
features.init_once(env)
|
||||
for (prop,value) in kw.items():
|
||||
getattr(features, prop, lambda x, y : None)(env, value)
|
||||
env[prop.upper()] = value
|
||||
|
||||
|
||||
def boost_suffix(env):
|
||||
suffix = str()
|
||||
|
||||
if env["layout"] == "versioned":
|
||||
if "gcc" in env["TOOLS"]:
|
||||
suffix += "-gcc" + "".join(env["CCVERSION"].split(".")[0:2])
|
||||
if env["THREADING"] == "multi":
|
||||
suffix += "-mt"
|
||||
if env["DEBUG"]:
|
||||
suffix += "-d"
|
||||
if env["layout"] == "versioned":
|
||||
suffix += "-" + "_".join(env["BPL_VERSION"].split("."))
|
||||
|
||||
return suffix
|
||||
|
||||
|
||||
def prepare_build_dir(env):
|
||||
|
||||
vars = {}
|
||||
env["boost_suffix"] = boost_suffix
|
||||
build_dir="bin.SCons"
|
||||
if "gcc" in env["TOOLS"]:
|
||||
build_dir+="/gcc-%s"%env["CCVERSION"]
|
||||
vars['CXXFLAGS'] = ['-ftemplate-depth-128', '-Wall']
|
||||
|
||||
elif "msvc" in env["TOOLS"]:
|
||||
build_dir+="/msvc-%s"%env["MSVS_VERSION"]
|
||||
vars['BOOST_BUILD_DIR'] = build_dir
|
||||
vars['BOOST_SUFFIX'] = "${boost_suffix(__env__)}"
|
||||
env.Replace(**vars)
|
||||
return build_dir
|
||||
|
||||
|
||||
def variants(env):
|
||||
|
||||
env.Append(CPPPATH = "#/include", CPPDEFINES = ["BOOST_ALL_NO_LIB=1"])
|
||||
set_property(env, architecture = env['TARGET_ARCH'])
|
||||
for variant in env["variant"]:
|
||||
e = env.Clone()
|
||||
e["current_variant"] = variant
|
||||
set_property(env, profile = False)
|
||||
if variant == "release":
|
||||
set_property(e, optimize = "speed", debug = False)
|
||||
elif variant == "debug":
|
||||
set_property(e, optimize = "no", debug = True)
|
||||
elif variant == "profile":
|
||||
set_property(e, optimize = "speed", profile = True, debug = True)
|
||||
for linking in env["link"]:
|
||||
e["linking"] = linking
|
||||
if linking == "dynamic":
|
||||
e["LINK_DYNAMIC"] = True
|
||||
else:
|
||||
e["LINK_DYNAMIC"] = False
|
||||
for threading in e["threading"]:
|
||||
e["current_threading"] = threading
|
||||
set_property(e, threading = threading)
|
||||
yield e
|
||||
40
config/boost.py
Normal file
40
config/boost.py
Normal file
@@ -0,0 +1,40 @@
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from . import ui
|
||||
import os
|
||||
|
||||
def add_options(vars):
|
||||
|
||||
ui.add_option("--boost-prefix", dest="boost_prefix", type="string", nargs=1, action="store",
|
||||
metavar="DIR", default=os.environ.get("BOOST_DIR"),
|
||||
help="prefix for Boost libraries; should have 'include' and 'lib' subdirectories, 'boost' and 'stage\\lib' subdirectories on Windows")
|
||||
ui.add_option("--boost-include", dest="boost_include", type="string", nargs=1, action="store",
|
||||
metavar="DIR", help="location of Boost header files")
|
||||
|
||||
|
||||
def check(context):
|
||||
|
||||
boost_source_file = r"#include <boost/config.hpp>"
|
||||
|
||||
context.Message('Checking for Boost...')
|
||||
|
||||
boost_prefix = context.env.GetOption('boost_prefix')
|
||||
boost_include = context.env.GetOption('boost_include')
|
||||
incpath=None
|
||||
if boost_include:
|
||||
incpath=boost_include
|
||||
elif boost_prefix:
|
||||
incpath=boost_prefix
|
||||
if incpath:
|
||||
context.env.AppendUnique(CPPPATH=[incpath])
|
||||
if not context.TryCompile(boost_source_file, '.cpp'):
|
||||
context.Result(0)
|
||||
return False
|
||||
context.Result(1)
|
||||
return True
|
||||
98
config/python.py
Normal file
98
config/python.py
Normal file
@@ -0,0 +1,98 @@
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from . import ui
|
||||
|
||||
def add_options(vars):
|
||||
|
||||
ui.add_option('--python', help='the python executable')
|
||||
|
||||
|
||||
def check(context):
|
||||
|
||||
python_source_file = r"""
|
||||
// If defined, enforces linking againg PythonXXd.lib, which
|
||||
// is usually not included in Python environments.
|
||||
#undef _DEBUG
|
||||
#include "Python.h"
|
||||
int main()
|
||||
{
|
||||
Py_Initialize();
|
||||
Py_Finalize();
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
|
||||
import platform
|
||||
import subprocess
|
||||
import re, os
|
||||
|
||||
def check_python(cmd):
|
||||
return subprocess.check_output([python, '-c', cmd]).strip()
|
||||
|
||||
def check_sysconfig(cmd):
|
||||
r = check_python('import distutils.sysconfig as c; print(c.%s)'%cmd)
|
||||
return r if r != 'None' else ''
|
||||
|
||||
context.Message('Checking for Python...')
|
||||
python = context.env.GetOption('python') or 'python'
|
||||
context.env['PYTHON'] = python
|
||||
incpath = check_sysconfig('get_python_inc()')
|
||||
context.env.AppendUnique(CPPPATH=[incpath])
|
||||
if platform.system() == 'Windows':
|
||||
version = check_python('import sys; print("%d%d"%sys.version_info[0:2])')
|
||||
prefix = check_python('import sys; print(sys.prefix)')
|
||||
libfile = os.path.join(prefix, 'libs', 'python%s.lib'%version)
|
||||
libpath = os.path.join(prefix, 'libs')
|
||||
lib = 'python%s'%version
|
||||
context.env.AppendUnique(LIBS=[lib])
|
||||
else:
|
||||
libpath = check_sysconfig('get_config_var("LIBDIR")')
|
||||
libfile = check_sysconfig('get_config_var("LIBRARY")')
|
||||
match = re.search('(python.*)\.(a|so|dylib)', libfile)
|
||||
lib = None
|
||||
if match:
|
||||
lib = match.group(1)
|
||||
context.env.AppendUnique(PYTHONLIBS=[lib])
|
||||
if match.group(2) == 'a':
|
||||
flags = check_sysconfig('get_config_var("LINKFORSHARED")')
|
||||
if flags is not None:
|
||||
context.env.AppendUnique(LINKFLAGS=flags.split())
|
||||
context.env.AppendUnique(LIBPATH=[libpath])
|
||||
oldlibs = context.AppendLIBS([lib])
|
||||
flags = check_sysconfig('get_config_var("MODLIBS")')
|
||||
flags += ' ' + check_sysconfig('get_config_var("SHLIBS")')
|
||||
flags = [f[2:] for f in flags.strip().split() if f.startswith('-l')]
|
||||
if flags:
|
||||
context.AppendLIBS([flags])
|
||||
result = context.TryLink(python_source_file,'.cpp')
|
||||
if not result and context.env['PLATFORM'] == 'darwin':
|
||||
# Sometimes we need some extra stuff on Mac OS
|
||||
frameworkDir = libpath # search up the libDir tree for the proper home for frameworks
|
||||
while frameworkDir and frameworkDir != "/":
|
||||
frameworkDir, d2 = os.path.split(frameworkDir)
|
||||
if d2 == "Python.framework":
|
||||
if not "Python" in os.listdir(os.path.join(frameworkDir, d2)):
|
||||
context.Result(0)
|
||||
print((
|
||||
"Expected to find Python in framework directory %s, but it isn't there"
|
||||
% frameworkDir))
|
||||
return False
|
||||
break
|
||||
context.env.AppendUnique(LINKFLAGS="-F%s" % frameworkDir)
|
||||
result = context.TryLink(python_source_file,'.cpp')
|
||||
if not result:
|
||||
context.Result(0)
|
||||
print("Cannot link program with Python.")
|
||||
return False
|
||||
if context.env['PLATFORM'] == 'darwin':
|
||||
context.env['LDMODULESUFFIX'] = '.so'
|
||||
context.Result(1)
|
||||
context.SetLIBS(oldlibs)
|
||||
context.env.AppendUnique(PYTHONLIBS=[lib] + flags)
|
||||
return True
|
||||
18
config/toolchains/__init__.py
Normal file
18
config/toolchains/__init__.py
Normal file
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import traceback
|
||||
|
||||
def append_feature_flag(env, **kw):
|
||||
stack = traceback.extract_stack(limit = 3)
|
||||
feature = stack[0][2].upper()
|
||||
for (key, val) in kw.items():
|
||||
feature_var = feature + "_" + key
|
||||
env.AppendUnique(**{ key : "$" + feature_var })
|
||||
env[feature_var] = val
|
||||
|
||||
55
config/toolchains/gcc.py
Normal file
55
config/toolchains/gcc.py
Normal file
@@ -0,0 +1,55 @@
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from . import append_feature_flag
|
||||
|
||||
class features:
|
||||
|
||||
@classmethod
|
||||
def init_once(cls, env):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def architecture(env, arch):
|
||||
if arch:
|
||||
flag = {'x86' : '-m32',
|
||||
'x86_64' : '-m64',}.get(arch)
|
||||
if flag:
|
||||
append_feature_flag(env, CCFLAGS = flag)
|
||||
|
||||
@staticmethod
|
||||
def optimize(env, optimize):
|
||||
if not optimize or optimize == "no":
|
||||
append_feature_flag(env, CCFLAGS = "-O0 -fno-inline")
|
||||
elif optimize == "speed":
|
||||
append_feature_flag(env, CCFLAGS = "-O3 -finline-functions -Wno-inline")
|
||||
elif optimize == "space":
|
||||
append_feature_flag(env, CCFLAGS = "-Os")
|
||||
else:
|
||||
append_feature_flag(env, CCFLAGS = "")
|
||||
|
||||
@staticmethod
|
||||
def profile(env, profile):
|
||||
if profile:
|
||||
append_feature_flag(env, CCFLAGS = "-pg", LINKFLAGS = "-pg")
|
||||
else:
|
||||
append_feature_flag(env, CCFLAGS = "", LINKFLAGS = "")
|
||||
|
||||
@staticmethod
|
||||
def threading(env, threading):
|
||||
if threading == "multi":
|
||||
append_feature_flag(env, CCFLAGS = "-pthread", LINKFLAGS = "-pthread")
|
||||
else:
|
||||
append_feature_flag(env, CCFLAGS = "", LINKFLAGS = "")
|
||||
|
||||
@staticmethod
|
||||
def debug(env, debug):
|
||||
if debug:
|
||||
append_feature_flag(env, CCFLAGS = "-g", CPPDEFINES = [])
|
||||
else:
|
||||
append_feature_flag(env, CCFLAGS = "", CPPDEFINES = "NDEBUG")
|
||||
57
config/toolchains/msvc.py
Normal file
57
config/toolchains/msvc.py
Normal file
@@ -0,0 +1,57 @@
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from . import append_feature_flag
|
||||
|
||||
class features:
|
||||
|
||||
@classmethod
|
||||
def init_once(cls, env):
|
||||
env.AppendUnique(CCFLAGS = ['-TP', '/Z7', '/W3' ,'/GR', '/MDd', '/Zc:forScope', '/Zc:wchar_t', '/wd4675', '/EHs'])
|
||||
env.AppendUnique(LINKFLAGS = ['/subsystem:console'])
|
||||
|
||||
@staticmethod
|
||||
def architecture(env, arch):
|
||||
if arch:
|
||||
flag = {'x86' : '/MACHINE:X32',
|
||||
'x86_64' : '/MACHINE:X64',}.get(arch)
|
||||
if flag:
|
||||
append_feature_flag(env, LINKFLAGS = flag)
|
||||
|
||||
@staticmethod
|
||||
def optimize(env, optimize):
|
||||
#if not optimize or optimize == "no":
|
||||
# append_feature_flag(env, CCFLAGS = "-O0 -fno-inline")
|
||||
#elif optimize == "speed":
|
||||
# append_feature_flag(env, CCFLAGS = "-O3 -finline-functions -Wno-inline")
|
||||
#elif optimize == "space":
|
||||
# append_feature_flag(env, CCFLAGS = "-Os")
|
||||
#else:
|
||||
append_feature_flag(env, CCFLAGS = "")
|
||||
|
||||
@staticmethod
|
||||
def profile(env, profile):
|
||||
#if profile:
|
||||
# append_feature_flag(env, CCFLAGS = "-pg", LINKFLAGS = "-pg")
|
||||
#else:
|
||||
append_feature_flag(env, CCFLAGS = "", LINKFLAGS = "")
|
||||
|
||||
@staticmethod
|
||||
def threading(env, threading):
|
||||
#if threading == "multi":
|
||||
# append_feature_flag(env, CCFLAGS = "/MT")
|
||||
#else:
|
||||
# append_feature_flag(env, CCFLAGS = "", LINKFLAGS = "")
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def debug(env, debug):
|
||||
#if debug:
|
||||
# append_feature_flag(env, CCFLAGS = "-g", CPPDEFINES = [])
|
||||
#else:
|
||||
append_feature_flag(env, CCFLAGS = "", CPPDEFINES = "NDEBUG")
|
||||
44
config/tools/clang.py
Normal file
44
config/tools/clang.py
Normal file
@@ -0,0 +1,44 @@
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Based on SCons/Tool/gcc.py
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import SCons.Util
|
||||
import SCons.Tool.cc
|
||||
|
||||
compilers = ['clang']
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for clang to an Environment."""
|
||||
SCons.Tool.cc.generate(env)
|
||||
|
||||
env['CC'] = env.Detect(compilers) or 'clang'
|
||||
if env['PLATFORM'] in ['cygwin', 'win32']:
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
|
||||
else:
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC')
|
||||
# determine compiler version
|
||||
if env['CC']:
|
||||
#pipe = SCons.Action._subproc(env, [env['CC'], '-dumpversion'],
|
||||
pipe = SCons.Action._subproc(env, [env['CC'], '--version'],
|
||||
stdin = 'devnull',
|
||||
stderr = 'devnull',
|
||||
stdout = subprocess.PIPE)
|
||||
if pipe.wait() != 0: return
|
||||
# clang -dumpversion is of no use
|
||||
line = pipe.stdout.readline()
|
||||
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
|
||||
if match:
|
||||
env['CCVERSION'] = match.group(1)
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(compilers)
|
||||
84
config/tools/libs.py
Normal file
84
config/tools/libs.py
Normal file
@@ -0,0 +1,84 @@
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import distutils.sysconfig
|
||||
from SCons.Script import AddOption, COMMAND_LINE_TARGETS, BUILD_TARGETS
|
||||
|
||||
|
||||
def BoostLibrary(env, lib, sources, make_aliases = True, **kw):
|
||||
if env["LINK_DYNAMIC"]:
|
||||
lib_node = env.SharedLibrary("boost_" + lib + env["BOOST_SUFFIX"], sources, **kw)
|
||||
else:
|
||||
lib_node = env.StaticLibrary("boost_" + lib + env["BOOST_SUFFIX"], sources, **kw)
|
||||
|
||||
if make_aliases:
|
||||
if env.GetOption("stage"):
|
||||
env.Alias(lib, env.Install(env.Dir("$stagedir", "#"), lib_node))
|
||||
env.Default(env.Alias(lib, lib_node))
|
||||
|
||||
if env.GetOption("install"):
|
||||
env.Alias(lib, env.Install("$prefix/lib", lib_node))
|
||||
return lib_node
|
||||
|
||||
|
||||
def BoostUseLib(env, lib):
|
||||
env.AppendUnique(
|
||||
LIBPATH = [env.Dir("$BOOST_CURRENT_VARIANT_DIR/src")],
|
||||
LIBS = ["boost_" + lib + env["BOOST_SUFFIX"]]
|
||||
)
|
||||
if env.get("BOOST_TEST"):
|
||||
env.AppendUnique(RPATH = [env.Dir("$BOOST_CURRENT_VARIANT_DIR/src")])
|
||||
|
||||
|
||||
def PythonExtension(env, lib, sources, **kw):
|
||||
if env["LINK_DYNAMIC"]:
|
||||
#env.AppendUnique(CPPDEFINES = ['BOOST_PYTHON_DYN_LINK=1'])
|
||||
ext = env.SharedLibrary(lib, sources, SHLIBPREFIX='', SHLIBSUFFIX=distutils.sysconfig.get_config_var("SO"), **kw)
|
||||
#env.Alias(lib, ext)
|
||||
return ext
|
||||
|
||||
|
||||
def boost_copy_func(dest, source, env):
|
||||
import os, stat, shutil
|
||||
|
||||
if os.path.isdir(source):
|
||||
if os.path.exists(dest):
|
||||
if not os.path.isdir(dest):
|
||||
raise SCons.Errors.UserError, "cannot overwrite non-directory `%s' with a directory `%s'" % (str(dest), str(source))
|
||||
else:
|
||||
os.makedirs(dest)
|
||||
for file in os.listdir(source):
|
||||
if file == ".svn": continue
|
||||
boost_copy_func(os.path.join(dest, file), os.path.join(source, file), env)
|
||||
else:
|
||||
shutil.copy2(source, dest)
|
||||
st = os.stat(source)
|
||||
os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def exists(env):
|
||||
return True
|
||||
|
||||
|
||||
def generate(env):
|
||||
env.AddMethod(BoostLibrary)
|
||||
env.AddMethod(BoostUseLib)
|
||||
env.AddMethod(PythonExtension)
|
||||
|
||||
env.Replace(
|
||||
INSTALL = boost_copy_func,
|
||||
BOOST_CURRENT_VARIANT_DIR = "$BOOST_BUILD_DIR/$current_variant/$linking/threading-$current_threading"
|
||||
)
|
||||
|
||||
AddOption('--stage', dest='stage', action="store_true")
|
||||
AddOption('--install', dest='install', action="store_true")
|
||||
|
||||
#if env.GetOption("install"):
|
||||
# BUILD_TARGETS.extend(env.Alias("install-headers"))
|
||||
105
config/tools/tests.py
Normal file
105
config/tools/tests.py
Normal file
@@ -0,0 +1,105 @@
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from SCons.Script import AddOption, Flatten
|
||||
from SCons.Script import Builder
|
||||
from SCons.Action import Action
|
||||
from subprocess import check_output, STDOUT, CalledProcessError
|
||||
import sys
|
||||
|
||||
|
||||
def BoostCompileTest(env, test, source = None, **kw):
|
||||
obj = env.Object(test, source if source is not None else test + '.cpp')
|
||||
return obj
|
||||
|
||||
def BoostRun(env, prog, target, command = '$SOURCE'):
|
||||
|
||||
def call(target, source, env=env):
|
||||
cmd = env.subst(command, target=target, source=source)
|
||||
result_file = env.subst('$TARGET', target=target)
|
||||
output=''
|
||||
try:
|
||||
output=check_output(cmd, stderr=STDOUT, shell=True)
|
||||
success=True
|
||||
except CalledProcessError as e:
|
||||
output=e.output
|
||||
success=False
|
||||
with open(result_file, 'w+') as result:
|
||||
result.write('Result: {}\n'.format(success and 'pass' or 'fail'))
|
||||
result.write('Output: {}\n'.format(output))
|
||||
if sys.stdout.isatty():
|
||||
env['RESULT']=success and '\033[92mPASS\033[0m' or '\033[91mFAIL\033[0m'
|
||||
else:
|
||||
env['RESULT']=success and 'PASS' or 'FAIL'
|
||||
|
||||
testcomstr = env.get('TESTCOMSTR')
|
||||
if testcomstr:
|
||||
run = env.Command(target, prog, Action(call, cmdstr=testcomstr))
|
||||
else:
|
||||
run = env.Command(target, prog, Action(call, cmdstr=command))
|
||||
env.AddPostAction(target, Action('@echo $RESULT'))
|
||||
return run
|
||||
|
||||
|
||||
def BoostRunPythonScript(env, script):
|
||||
return env.BoostRun(env.File(script), script.replace('.py', '.result'), '"${PYTHON}" $SOURCE')
|
||||
|
||||
|
||||
def BoostRunTest(env, test, source = None, command = '$SOURCE', command_sources = [], **kw):
|
||||
test_prog = env.Program(test, (source is None) and (test + ".cpp") or source, **kw)
|
||||
command += '> $TARGET'
|
||||
run = env.BoostRun([test_prog, command_sources], test + '.result', command)
|
||||
return run
|
||||
|
||||
|
||||
def BoostRunTests(env, tests, **kw):
|
||||
run = []
|
||||
for test in Flatten(tests):
|
||||
run += env.BoostRunTest(test, **kw)
|
||||
return run
|
||||
|
||||
def BoostCompileTests(env, tests, **kw):
|
||||
comp = []
|
||||
for test in Flatten(tests):
|
||||
comp += env.BoostCompileTest(test, **kw)
|
||||
return comp
|
||||
|
||||
|
||||
def BoostTestSummary(env, tests, **kw):
|
||||
|
||||
def print_summary(target, source, **kw):
|
||||
results = tests
|
||||
failures = [r for r in results
|
||||
if r.get_path().endswith('.result') and not 'Result: pass' in r.get_contents()]
|
||||
print('%s tests; %s pass; %s fails'%(len(results), len(results)-len(failures), len(failures)))
|
||||
for f in failures:
|
||||
print('%s\n%s'%(f.get_path(), f.get_contents()))
|
||||
testsumcomstr = env.get('TESTSUMCOMSTR')
|
||||
if testsumcomstr:
|
||||
run = env.Command('summary', tests, Action(print_summary, cmdstr=testsumcomstr))
|
||||
else:
|
||||
run = env.Command('summary', tests, print_summary, cmdstr='')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def exists(env):
|
||||
return True
|
||||
|
||||
|
||||
def generate(env):
|
||||
AddOption('--test', dest='test', action="store_true")
|
||||
|
||||
env.AddMethod(BoostCompileTest)
|
||||
env.AddMethod(BoostRun)
|
||||
env.AddMethod(BoostRunPythonScript)
|
||||
env.AddMethod(BoostRunTest)
|
||||
env.AddMethod(BoostRunTests)
|
||||
env.AddMethod(BoostCompileTests)
|
||||
env.AddMethod(BoostTestSummary)
|
||||
96
config/ui.py
Normal file
96
config/ui.py
Normal file
@@ -0,0 +1,96 @@
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from SCons.Script import AddOption
|
||||
import sys
|
||||
|
||||
variables=[] # remember 'public' variables
|
||||
options=[]
|
||||
|
||||
def add_option(*args, **kwds):
|
||||
"""Capture the help messages so we can produce a helpful usage text."""
|
||||
options.append('{:25} {}'.format(', '.join(args), kwds.get('help', '')))
|
||||
AddOption(*args, **kwds)
|
||||
|
||||
def add_variable(vars, var):
|
||||
variables.append(var[0])
|
||||
vars.Add(var)
|
||||
|
||||
|
||||
def options_help(env):
|
||||
|
||||
return '\n '.join(options)
|
||||
|
||||
|
||||
def variables_help(vars, env):
|
||||
"""This is cloned from SCons' Variables.GenerateHelpText, to only report 'public' variables."""
|
||||
|
||||
opts = [o for o in vars.options if o.key in variables]
|
||||
|
||||
def format(opt):
|
||||
if opt.key in env:
|
||||
actual = env.subst('${%s}' % opt.key)
|
||||
else:
|
||||
actual = None
|
||||
return vars.FormatVariableHelpText(env, opt.key, opt.help, opt.default, actual, opt.aliases)
|
||||
text = ''.join([f for f in map(format, opts) if f])
|
||||
lines = [' %s'%l for l in text.split('\n')] # Add some indentation
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
|
||||
def help(vars, env):
|
||||
|
||||
return """Usage: scons [--option...] [variable=value...] [target...]
|
||||
|
||||
available options:
|
||||
|
||||
{}
|
||||
|
||||
available variables:
|
||||
{}
|
||||
""".format(options_help(env), variables_help(vars, env))
|
||||
|
||||
def pretty_output(env):
|
||||
|
||||
colors = {}
|
||||
colors['red'] = '\033[31m'
|
||||
colors['green'] = '\033[32m'
|
||||
colors['blue'] = '\033[34m'
|
||||
colors['yellow'] = '\033[93m'
|
||||
colors['Red'] = '\033[91m'
|
||||
colors['Green'] = '\033[92m'
|
||||
colors['Blue'] = '\033[94m'
|
||||
colors['Purple'] = '\033[95m'
|
||||
colors['Cyan'] = '\033[96m'
|
||||
colors['end'] = '\033[0m'
|
||||
|
||||
#If the output is not a terminal, remove the colors
|
||||
if not sys.stdout.isatty():
|
||||
for key, value in colors.iteritems():
|
||||
colors[key] = ''
|
||||
|
||||
compile_source_message = '{green}Compiling $TARGET{end}'.format(**colors)
|
||||
compile_shared_source_message = '{green}Compiling $TARGET{end}'.format(**colors)
|
||||
link_program_message = '{blue}Linking $TARGET{end}'.format(**colors)
|
||||
link_library_message = '{blue}Linking $TARGET{end}'.format(**colors)
|
||||
ranlib_library_message = '{blue}Ranlib $TARGET{end}'.format(**colors)
|
||||
link_shared_library_message = '{blue}Linking $TARGET{end}'.format(**colors)
|
||||
test_message = '{blue}Testing $SOURCE{end}'.format(**colors)
|
||||
testsum_message = '{Blue}Test Summary{end}'.format(**colors)
|
||||
|
||||
env.Replace(CXXCOMSTR = compile_source_message,
|
||||
CCCOMSTR = compile_source_message,
|
||||
SHCCCOMSTR = compile_shared_source_message,
|
||||
SHCXXCOMSTR = compile_shared_source_message,
|
||||
ARCOMSTR = link_library_message,
|
||||
RANLIBCOMSTR = ranlib_library_message,
|
||||
SHLINKCOMSTR = link_shared_library_message,
|
||||
LINKCOMSTR = link_program_message,
|
||||
TESTCOMSTR = test_message,
|
||||
TESTSUMCOMSTR = testsum_message)
|
||||
44
src/SConscript
Normal file
44
src/SConscript
Normal file
@@ -0,0 +1,44 @@
|
||||
# -*- python -*-
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Import('env')
|
||||
|
||||
env.AppendUnique(CPPDEFINES = ["${LINK_DYNAMIC and 'BOOST_PYTHON_DYN_LINK=1' or ''}"])
|
||||
env.AppendUnique(CPPDEFINES = ['BOOST_PYTHON_SOURCE'])
|
||||
|
||||
env.BoostLibrary(
|
||||
'python',
|
||||
['numeric.cpp',
|
||||
'list.cpp',
|
||||
'long.cpp',
|
||||
'dict.cpp',
|
||||
'tuple.cpp',
|
||||
'str.cpp',
|
||||
'slice.cpp',
|
||||
'converter/from_python.cpp',
|
||||
'converter/registry.cpp',
|
||||
'converter/type_id.cpp',
|
||||
'object/enum.cpp',
|
||||
'object/class.cpp',
|
||||
'object/function.cpp',
|
||||
'object/inheritance.cpp',
|
||||
'object/life_support.cpp',
|
||||
'object/pickle_support.cpp',
|
||||
'errors.cpp',
|
||||
'module.cpp',
|
||||
'converter/builtin_converters.cpp',
|
||||
'converter/arg_to_python_base.cpp',
|
||||
'object/iterator.cpp',
|
||||
'object/stl_iterator.cpp',
|
||||
'object_protocol.cpp',
|
||||
'object_operators.cpp',
|
||||
'wrapper.cpp',
|
||||
'import.cpp',
|
||||
'exec.cpp',
|
||||
'object/function_doc_signature.cpp'])
|
||||
132
test/SConscript
Normal file
132
test/SConscript
Normal file
@@ -0,0 +1,132 @@
|
||||
# -*- python -*-
|
||||
#
|
||||
# Copyright (c) 2016 Stefan Seefeld
|
||||
# All rights reserved.
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Import('env')
|
||||
|
||||
# libs needed for embedding
|
||||
ELIBS=env['LIBS'] + env['PYTHONLIBS']
|
||||
|
||||
def BPLTest(env, name, sources = None, script = None):
|
||||
run = env.BoostRunPythonScript(name + '.py')
|
||||
if sources:
|
||||
for source in sources:
|
||||
Depends(run,
|
||||
env.PythonExtension(source != name and source or (source + '_ext'), source + '.cpp')
|
||||
)
|
||||
else:
|
||||
Depends(run, env.PythonExtension(name + '_ext', name + '.cpp'))
|
||||
return run
|
||||
|
||||
env.AddMethod(BPLTest)
|
||||
|
||||
env.AppendENVPath('PYTHONPATH', Dir('.').path)
|
||||
|
||||
tests=[]
|
||||
tests+=env.BPLTest('crossmod_exception', ['crossmod_exception_a', 'crossmod_exception_b'])
|
||||
|
||||
for test in ['injected',
|
||||
'properties',
|
||||
'return_arg',
|
||||
'staticmethod',
|
||||
'shared_ptr',
|
||||
'enable_shared_from_this',
|
||||
'andreas_beyer',
|
||||
'polymorphism',
|
||||
'polymorphism2',
|
||||
'wrapper_held_type',
|
||||
'polymorphism2_auto_ptr',
|
||||
'auto_ptr',
|
||||
'minimal',
|
||||
'args',
|
||||
'raw_ctor',
|
||||
#'numpy',
|
||||
'enum',
|
||||
'exception_translator']:
|
||||
tests+=env.BPLTest(test)
|
||||
|
||||
tests+=env.BPLTest('test_cltree', ['cltree'])
|
||||
tests+=env.BPLTest('newtest', ['m1', 'm2'])
|
||||
tests+=env.BPLTest('const_argument')
|
||||
tests+=env.BPLTest('keywords_test', ['keywords'])
|
||||
Depends(
|
||||
env.BoostRunPythonScript('test_builtin_converters.py'),
|
||||
env.PythonExtension('builtin_converters_ext', 'test_builtin_converters.cpp')
|
||||
)
|
||||
|
||||
for test in ['test_pointer_adoption',
|
||||
'operators',
|
||||
'operators_wrapper',
|
||||
'callbacks',
|
||||
'defaults',
|
||||
'object',
|
||||
'list',
|
||||
'long',
|
||||
'dict',
|
||||
'tuple',
|
||||
'str',
|
||||
'slice',
|
||||
'virtual_functions',
|
||||
'back_reference',
|
||||
'implicit',
|
||||
'data_members',
|
||||
'ben_scott1',
|
||||
'bienstman1',
|
||||
'bienstman2',
|
||||
'bienstman3',
|
||||
'multi_arg_constructor']:
|
||||
tests+=env.BPLTest(test)
|
||||
|
||||
tests+=env.BPLTest('iterator', ['iterator', 'input_iterator'])
|
||||
tests+=env.BPLTest('stl_iterator')
|
||||
tests+=env.BPLTest('extract')
|
||||
tests+=env.BPLTest('crossmod_opaque', ['crossmod_opaque_a', 'crossmod_opaque_b'])
|
||||
|
||||
for test in ['opaque',
|
||||
'voidptr',
|
||||
'pickle1',
|
||||
'pickle2',
|
||||
'pickle3',
|
||||
'pickle4',
|
||||
'nested',
|
||||
'docstring',
|
||||
'pytype_function',
|
||||
'vector_indexing_suite',
|
||||
'pointer_vector']:
|
||||
tests+=env.BPLTest(test)
|
||||
|
||||
Depends(
|
||||
env.BoostRunPythonScript('map_indexing_suite.py'),
|
||||
env.PythonExtension('map_indexing_suite_ext', [
|
||||
'map_indexing_suite.cpp',
|
||||
'int_map_indexing_suite.cpp',
|
||||
'a_map_indexing_suite.cpp'])
|
||||
)
|
||||
|
||||
tests+=env.BoostRunTest('import_', 'import_.cpp', '${SOURCES[0]} ${SOURCES[1]}', 'import_.py', LIBS=ELIBS)
|
||||
|
||||
tests+=env.BoostCompileTest('indirect_traits_test')
|
||||
tests+=env.BoostRunTests(['destroy_test',
|
||||
'pointer_type_id_test',
|
||||
'bases',
|
||||
'if_else',
|
||||
'pointee',
|
||||
'result'], LIBS=ELIBS)
|
||||
|
||||
tests+=env.BoostCompileTests(['string_literal',
|
||||
'borrowed',
|
||||
'object_manager',
|
||||
'copy_ctor_mutates_rhs'])
|
||||
|
||||
tests+=env.BoostRunTest('upcast', LIBS=ELIBS)
|
||||
tests+=env.BoostCompileTest('select_holder')
|
||||
tests+=env.BoostRunTest('select_from_python_test', LIBS=ELIBS)
|
||||
tests+=env.BoostCompileTest('select_arg_to_python_test')
|
||||
|
||||
env.BoostTestSummary(tests)
|
||||
AlwaysBuild(tests)
|
||||
Reference in New Issue
Block a user