2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-24 06:02:14 +00:00

Switch SCons to use SConsChecks submodule for Windows support

This commit is contained in:
Christoph Lassner
2014-10-07 16:22:11 +02:00
committed by Jim Bosch
parent c509a3ab01
commit 73b8350e53
7 changed files with 72 additions and 229 deletions

View File

@@ -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")