mirror of
https://github.com/boostorg/python.git
synced 2026-01-19 16:32:16 +00:00
Switch SCons to use SConsChecks submodule for Windows support
This commit is contained in:
committed by
Jim Bosch
parent
c509a3ab01
commit
73b8350e53
4
.gitmodules
vendored
Normal file
4
.gitmodules
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
[submodule "SConsChecks"]
|
||||
path = SConsChecks
|
||||
url = https://github.com/ChrislS/SConsChecks.git
|
||||
branch = master
|
||||
6
README
6
README
@@ -26,7 +26,11 @@ Linux and CMake on Windows.
|
||||
Building with SCons should be as simple as running "scons" and "scons
|
||||
install", but you may need to use the "--with-boost*" options (see
|
||||
"scons --help") to specify where to find Boost. The Python that is
|
||||
used by SCons will be the one built against.
|
||||
used by SCons will be the one built against. Additionally, the
|
||||
SConsChecks submodule must be initialized by git before building
|
||||
by running
|
||||
|
||||
git submodule update --init
|
||||
|
||||
Please see libs/numpy/doc/cmakeBuild.rst for more information on
|
||||
building with CMake.
|
||||
|
||||
1
SConsChecks
Submodule
1
SConsChecks
Submodule
Submodule SConsChecks added at 9000598871
234
SConscript
234
SConscript
@@ -6,192 +6,21 @@
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Big thanks to Mike Jarvis for help with the configuration prescriptions below.
|
||||
# Integration of SConsChecks for platform independent building
|
||||
# by Christoph Lassner.
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import sysconfig
|
||||
from SCons.SConf import CheckContext
|
||||
from SConsChecks import AddLibOptions, GetLibChecks
|
||||
|
||||
def setupPaths(env, prefix, include, lib):
|
||||
if prefix is not None:
|
||||
if include is None:
|
||||
include = os.path.join(prefix, "include")
|
||||
if lib is None:
|
||||
lib = os.path.join(prefix, "lib")
|
||||
if include:
|
||||
env.PrependUnique(CPPPATH=[include])
|
||||
if lib:
|
||||
env.PrependUnique(LIBPATH=[lib])
|
||||
AddMethod(Environment, setupPaths)
|
||||
|
||||
def checkLibs(context, try_libs, source_file):
|
||||
init_libs = context.env.get('LIBS', [])
|
||||
context.env.PrependUnique(LIBS=[try_libs])
|
||||
result = context.TryLink(source_file, '.cpp')
|
||||
if not result :
|
||||
context.env.Replace(LIBS=init_libs)
|
||||
return result
|
||||
AddMethod(CheckContext, checkLibs)
|
||||
|
||||
def CheckPython(context):
|
||||
python_source_file = """
|
||||
#include "Python.h"
|
||||
int main()
|
||||
{
|
||||
Py_Initialize();
|
||||
Py_Finalize();
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
context.Message('Checking if we can build against Python... ')
|
||||
try:
|
||||
import distutils.sysconfig
|
||||
except ImportError:
|
||||
context.Result(0)
|
||||
print('Failed to import distutils.sysconfig.')
|
||||
return False
|
||||
context.env.AppendUnique(CPPPATH=[distutils.sysconfig.get_python_inc()])
|
||||
libDir = distutils.sysconfig.get_config_var("LIBDIR")
|
||||
context.env.AppendUnique(LIBPATH=[libDir])
|
||||
libfile = distutils.sysconfig.get_config_var("LIBRARY")
|
||||
import re
|
||||
match = re.search("(python.*)\.(a|so|dylib)", libfile)
|
||||
if match:
|
||||
context.env.AppendUnique(LIBS=[match.group(1)])
|
||||
if match.group(2) == 'a':
|
||||
flags = distutils.sysconfig.get_config_var('LINKFORSHARED')
|
||||
if flags is not None:
|
||||
context.env.AppendUnique(LINKFLAGS=flags.split())
|
||||
flags = [f for f in " ".join(distutils.sysconfig.get_config_vars("MODLIBS", "SHLIBS")).split()
|
||||
if f != "-L"]
|
||||
context.env.MergeFlags(" ".join(flags))
|
||||
result, output = context.TryRun(python_source_file,'.cpp')
|
||||
if not result and context.env["PLATFORM"] == 'darwin':
|
||||
# Sometimes we need some extra stuff on Mac OS
|
||||
frameworkDir = libDir # 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, output = context.TryRun(python_source_file,'.cpp')
|
||||
if not result:
|
||||
context.Result(0)
|
||||
print("Cannot run program built with Python.")
|
||||
return False
|
||||
if context.env["PLATFORM"] == "darwin":
|
||||
context.env["LDMODULESUFFIX"] = ".so"
|
||||
context.Result(1)
|
||||
return True
|
||||
|
||||
def CheckNumPy(context):
|
||||
numpy_source_file = """
|
||||
#include "Python.h"
|
||||
#include "numpy/arrayobject.h"
|
||||
#if PY_MAJOR_VERSION == 2
|
||||
static void wrap_import_array() {
|
||||
import_array();
|
||||
}
|
||||
#else
|
||||
static void * wrap_import_array() {
|
||||
import_array();
|
||||
}
|
||||
#endif
|
||||
void doImport() {
|
||||
wrap_import_array();
|
||||
}
|
||||
int main()
|
||||
{
|
||||
int result = 0;
|
||||
Py_Initialize();
|
||||
doImport();
|
||||
if (PyErr_Occurred()) {
|
||||
result = 1;
|
||||
} else {
|
||||
npy_intp dims = 2;
|
||||
PyObject * a = PyArray_SimpleNew(1, &dims, NPY_INT);
|
||||
if (!a) result = 1;
|
||||
Py_DECREF(a);
|
||||
}
|
||||
Py_Finalize();
|
||||
return result;
|
||||
}
|
||||
"""
|
||||
context.Message('Checking if we can build against NumPy... ')
|
||||
try:
|
||||
import numpy
|
||||
except ImportError:
|
||||
context.Result(0)
|
||||
print('Failed to import numpy.')
|
||||
print('Things to try:')
|
||||
print('1) Check that the command line python (with which you probably installed numpy):')
|
||||
print(' ', end=' ')
|
||||
sys.stdout.flush()
|
||||
subprocess.call('which python',shell=True)
|
||||
print(' is the same as the one used by SCons:')
|
||||
print(' ',sys.executable)
|
||||
print(' If not, then you probably need to reinstall numpy with %s.' % sys.executable)
|
||||
print(' Alternatively, you can reinstall SCons with your preferred python.')
|
||||
print('2) Check that if you open a python session from the command line,')
|
||||
print(' import numpy is successful there.')
|
||||
return False
|
||||
context.env.Append(CPPPATH=numpy.get_include())
|
||||
result = context.checkLibs([''],numpy_source_file)
|
||||
if not result:
|
||||
context.Result(0)
|
||||
print("Cannot build against NumPy.")
|
||||
return False
|
||||
result, output = context.TryRun(numpy_source_file,'.cpp')
|
||||
if not result:
|
||||
context.Result(0)
|
||||
print("Cannot run program built with NumPy.")
|
||||
return False
|
||||
context.Result(1)
|
||||
return True
|
||||
|
||||
def CheckBoostPython(context):
|
||||
bp_source_file = """
|
||||
#include "boost/python.hpp"
|
||||
class Foo { public: Foo() {} };
|
||||
int main()
|
||||
{
|
||||
Py_Initialize();
|
||||
boost::python::object obj;
|
||||
boost::python::class_< Foo >("Foo", boost::python::init<>());
|
||||
Py_Finalize();
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
context.Message('Checking if we can build against Boost.Python... ')
|
||||
context.env.setupPaths(
|
||||
prefix = GetOption("boost_prefix"),
|
||||
include = GetOption("boost_include"),
|
||||
lib = GetOption("boost_lib")
|
||||
)
|
||||
boost_python_lib = GetOption ('boost_python_lib')
|
||||
result = (
|
||||
context.checkLibs([''], bp_source_file) or
|
||||
context.checkLibs([boost_python_lib], bp_source_file) or
|
||||
context.checkLibs([boost_python_lib+'_mt'], bp_source_file)
|
||||
)
|
||||
if not result:
|
||||
context.Result(0)
|
||||
print("Cannot build against Boost.Python.")
|
||||
return False
|
||||
result, output = context.TryRun(bp_source_file, '.cpp')
|
||||
if not result:
|
||||
context.Result(0)
|
||||
print ("Cannot run program built against Boost.Python.")
|
||||
return False
|
||||
context.Result(1)
|
||||
return True
|
||||
_libs = ['boost.python',
|
||||
'python',
|
||||
'numpy']
|
||||
_checks = GetLibChecks(_libs)
|
||||
|
||||
# Setup command-line options
|
||||
def setupOptions():
|
||||
@@ -205,7 +34,7 @@ def setupOptions():
|
||||
metavar="DIR", default=os.environ.get("BOOST_DIR"),
|
||||
help="prefix for Boost libraries; should have 'include' and 'lib' subdirectories")
|
||||
AddOption("--with-boost-include", dest="boost_include", type="string", nargs=1, action="store",
|
||||
metavar="DIR", help="location of Boost header files")
|
||||
metavar="DIR", help="location of Boost header files", default=os.environ.get("BOOST_DIR"))
|
||||
AddOption("--with-boost-lib", dest="boost_lib", type="string", nargs=1, action="store",
|
||||
metavar="DIR", help="location of Boost libraries")
|
||||
AddOption("--rpath", dest="custom_rpath", type="string", action="append",
|
||||
@@ -213,7 +42,10 @@ def setupOptions():
|
||||
AddOption("--boost-python-lib", dest="boost_python_lib", type="string", action="store",
|
||||
help="name of boost_python_lib", default='boost_python')
|
||||
variables = Variables()
|
||||
variables.Add("CCFLAGS", default=os.environ.get("CCFLAGS", "-O2 -g"), help="compiler flags")
|
||||
defaultflags = "-O2 -g"
|
||||
if os.name == 'nt':
|
||||
defaultflags = "/O2"
|
||||
variables.Add("CCFLAGS", default=os.environ.get("CCFLAGS", defaultflags), help="compiler flags")
|
||||
return variables
|
||||
|
||||
def makeEnvironment(variables):
|
||||
@@ -227,15 +59,37 @@ def makeEnvironment(variables):
|
||||
custom_rpath = GetOption("custom_rpath")
|
||||
if custom_rpath is not None:
|
||||
env.AppendUnique(RPATH=custom_rpath)
|
||||
boost_lib = GetOption ('boost_lib')
|
||||
if boost_lib is not None:
|
||||
env.PrependUnique(LIBPATH=boost_lib)
|
||||
if env['CC'] == 'cl':
|
||||
# C++ exception handling,
|
||||
# multithread-supporting, dynamically linked system libraries,
|
||||
# generate debug information,
|
||||
# dynamic link library.
|
||||
env.AppendUnique(CPPFLAGS=['/EHsc', '/MD', '/Zi', '/LD'])
|
||||
return env
|
||||
|
||||
def setupTargets(env, root="."):
|
||||
lib = SConscript(os.path.join(root, "libs", "numpy", "src", "SConscript"), exports='env')
|
||||
example = SConscript(os.path.join(root, "libs", "numpy", "example", "SConscript"), exports='env')
|
||||
test = SConscript(os.path.join(root, "libs", "numpy", "test", "SConscript"), exports='env')
|
||||
# Determine file extensions.
|
||||
VERSION = sys.version_info.major
|
||||
if os.name == 'nt':
|
||||
EXT_SUFFIX = '.dll'
|
||||
LIB_SUFFIX = '.lib'
|
||||
PY_SUFFIX = '.pyd'
|
||||
else:
|
||||
EXT_SUFFIX = sysconfig.get_config_var("EXT_SUFFIX")
|
||||
if VERSION == 2 and EXT_SUFFIX == 'None' or EXT_SUFFIX==None:
|
||||
EXT_SUFFIX = '.so'
|
||||
elif VERSION == 3 and EXT_SUFFIX == b'None' or EXT_SUFFIX==None:
|
||||
EXT_SUFFIX = '.so'
|
||||
LIB_SUFFIX = EXT_SUFFIX
|
||||
PY_SUFFIX = EXT_SUFFIX
|
||||
OBJ_SUFFIX = EXT_SUFFIX.replace ('.so', '.os')
|
||||
|
||||
lib = SConscript(os.path.join(root, "libs", "numpy", "src", "SConscript"),
|
||||
exports=['env', 'EXT_SUFFIX', 'LIB_SUFFIX', 'OBJ_SUFFIX'])
|
||||
example = SConscript(os.path.join(root, "libs", "numpy", "example", "SConscript"),
|
||||
exports='env')
|
||||
test = SConscript(os.path.join(root, "libs", "numpy", "test", "SConscript"),
|
||||
exports=['env', 'lib', 'EXT_SUFFIX', 'LIB_SUFFIX', 'OBJ_SUFFIX', 'PY_SUFFIX'])
|
||||
prefix = Dir(GetOption("prefix")).abspath
|
||||
install_headers = GetOption('install_headers')
|
||||
install_lib = GetOption('install_lib')
|
||||
@@ -244,7 +98,7 @@ def setupTargets(env, root="."):
|
||||
if not install_lib:
|
||||
install_lib = os.path.join(prefix, "lib")
|
||||
env.Alias("install", env.Install(install_lib, lib))
|
||||
for header in ("dtype.hpp", "invoke_matching.hpp", "matrix.hpp",
|
||||
for header in ("dtype.hpp", "invoke_matching.hpp", "matrix.hpp",
|
||||
"ndarray.hpp", "numpy_object_mgr_traits.hpp",
|
||||
"scalars.hpp", "ufunc.hpp",):
|
||||
env.Alias("install", env.Install(os.path.join(install_headers, "boost", "numpy"),
|
||||
@@ -252,6 +106,4 @@ def setupTargets(env, root="."):
|
||||
env.Alias("install", env.Install(os.path.join(install_headers, "boost"),
|
||||
os.path.join(root, "boost", "numpy.hpp")))
|
||||
|
||||
checks = {"CheckPython": CheckPython, "CheckNumPy": CheckNumPy, "CheckBoostPython": CheckBoostPython}
|
||||
|
||||
Return("setupOptions", "makeEnvironment", "setupTargets", "checks")
|
||||
Return("setupOptions", "makeEnvironment", "setupTargets", "_checks", "_libs")
|
||||
@@ -5,7 +5,9 @@
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
setupOptions, makeEnvironment, setupTargets, checks = SConscript("SConscript")
|
||||
from SConsChecks import GetLibChecks
|
||||
|
||||
setupOptions, makeEnvironment, setupTargets, checks, libnames = SConscript("SConscript")
|
||||
|
||||
variables = setupOptions()
|
||||
|
||||
@@ -14,8 +16,9 @@ env.AppendUnique(CPPPATH="#.")
|
||||
|
||||
if not GetOption("help") and not GetOption("clean"):
|
||||
config = env.Configure(custom_tests=checks)
|
||||
if not (config.CheckPython() and config.CheckNumPy() and config.CheckBoostPython()):
|
||||
Exit(1)
|
||||
checknames = GetLibChecks(libnames).keys()
|
||||
if False in (config.__dict__[checkname]() for checkname in checknames):
|
||||
Exit(1)
|
||||
env = config.Finish()
|
||||
|
||||
setupTargets(env)
|
||||
|
||||
@@ -7,32 +7,16 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
VERSION = sys.version_info.major
|
||||
import sysconfig
|
||||
if os.name == 'nt':
|
||||
EXT_SUFFIX = '.dll'
|
||||
LIB_SUFFIX = '.lib'
|
||||
else:
|
||||
EXT_SUFFIX = sysconfig.get_config_var("EXT_SUFFIX")
|
||||
LIB_SUFFIX = EXT_SUFFIX
|
||||
|
||||
if VERSION == 2 and EXT_SUFFIX == 'None' or EXT_SUFFIX==None:
|
||||
EXT_SUFFIX = '.so'
|
||||
elif VERSION == 3 and EXT_SUFFIX == b'None' or EXT_SUFFIX==None:
|
||||
EXT_SUFFIX = '.so'
|
||||
print ('EXT:', EXT_SUFFIX)
|
||||
|
||||
OBJ_SUFFIX = EXT_SUFFIX.replace ('.so', '.os')
|
||||
|
||||
Import("env")
|
||||
Import(['env', 'EXT_SUFFIX', 'LIB_SUFFIX', 'OBJ_SUFFIX'])
|
||||
|
||||
LIB_BOOST_NUMPY = ('boost_numpy' + LIB_SUFFIX)
|
||||
mods = [g.name.replace('.cpp', '') for g in Glob("*.cpp")]
|
||||
for m in mods:
|
||||
env.SharedObject (target=m+OBJ_SUFFIX, source=m+'.cpp')
|
||||
sourcefiles = Glob("*.cpp")
|
||||
if os.name == 'nt':
|
||||
lib = env.StaticLibrary(LIB_BOOST_NUMPY, source=[m+OBJ_SUFFIX for m in mods])
|
||||
lib = env.StaticLibrary(LIB_BOOST_NUMPY, source=sourcefiles)
|
||||
else:
|
||||
mods = [g.name.replace('.cpp', '') for g in sourcefiles]
|
||||
for m in mods:
|
||||
env.SharedObject (target=m+OBJ_SUFFIX, source=m+'.cpp')
|
||||
lib = env.SharedLibrary(LIB_BOOST_NUMPY, source=[m+OBJ_SUFFIX for m in mods])
|
||||
|
||||
Return("lib")
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Import("env")
|
||||
Import(['env', 'lib', 'EXT_SUFFIX', 'LIB_SUFFIX', 'OBJ_SUFFIX', 'PY_SUFFIX'])
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -15,17 +15,7 @@ lib_path = os.path.abspath(os.path.join("..", "src"))
|
||||
test_env.Append(LIBPATH=[lib_path])
|
||||
test_env.Append(RPATH=[lib_path])
|
||||
test_env.Append(LINKFLAGS = ["$__RPATH"]) # workaround for SCons bug #1644t
|
||||
import sys;
|
||||
VERSION = sys.version_info.major
|
||||
print (VERSION)
|
||||
|
||||
import sysconfig
|
||||
EXT_SUFFIX = sysconfig.get_config_var("EXT_SUFFIX")
|
||||
|
||||
if VERSION == 2:
|
||||
test_env.Append(LIBS=["boost_numpy"])
|
||||
elif VERSION == 3:
|
||||
test_env.Append(LIBS=["boost_numpy"+EXT_SUFFIX.replace('.so', '')])
|
||||
test_env.AppendUnique(LIBS=lib)
|
||||
test = []
|
||||
|
||||
def RunPythonUnitTest(target, source, env):
|
||||
@@ -39,6 +29,11 @@ def PythonUnitTest(env, script, dependencies):
|
||||
|
||||
for name in ("dtype", "ufunc", "templates", "ndarray", "indexing", "shapes"):
|
||||
mod = test_env.LoadableModule("%s_mod" % name, "%s_mod.cpp" % name, LDMODULEPREFIX="")
|
||||
if os.name == 'nt':
|
||||
# Move the module to have the correct name.
|
||||
mod = env.Command(os.path.join(Dir('.').srcnode().abspath, "%s_mod.pyd" % (name)),
|
||||
mod,
|
||||
Move(os.path.join(Dir('.').srcnode().abspath, "%s_mod.pyd" % (name)), mod[0]))
|
||||
test.extend(PythonUnitTest(test_env, "%s.py" % name, mod))
|
||||
|
||||
Return("test")
|
||||
|
||||
Reference in New Issue
Block a user