[SCons] Use SCons to compile the Cython extension
Fixes issues with mismatched compilers between the Cython extension and the cantera library, especially on OS X. Improves build dependency resolution to eliminate unnecessary recompilation of _cantera.cpp.
This commit is contained in:
parent
d516d46f33
commit
eaceaf7b86
3 changed files with 41 additions and 96 deletions
|
|
@ -325,12 +325,6 @@ config_options = [
|
|||
default 'site-packages' directory. To install to the current user's
|
||||
site-packages directory, use 'python3_prefix=USER'.""",
|
||||
defaults.python_prefix, PathVariable.PathAccept),
|
||||
PathVariable(
|
||||
'python_compiler',
|
||||
""" Compiler to use while building the Python extension module. By default,
|
||||
the compiler will be selected by distutils. Applies to both Python 2
|
||||
and Python 3.""",
|
||||
'', PathVariable.PathAccept),
|
||||
EnumVariable(
|
||||
'matlab_toolbox',
|
||||
"""This variable controls whether the Matlab toolbox will be built. If
|
||||
|
|
|
|||
|
|
@ -1,33 +1,34 @@
|
|||
""" Cython-based Python Module for Python 3 """
|
||||
from buildutils import *
|
||||
import Cython.Build
|
||||
|
||||
Import('env', 'build', 'install')
|
||||
|
||||
localenv = env.Clone()
|
||||
|
||||
|
||||
def configure_numpy(env, python_command):
|
||||
def configure_python(env, python_command):
|
||||
script = '\n'.join(("from distutils.sysconfig import *",
|
||||
"import numpy",
|
||||
"print(get_config_var('SO'))",
|
||||
"print(get_config_var('EXT_SUFFIX') or get_config_var('SO'))",
|
||||
"print(get_config_var('INCLUDEPY'))",
|
||||
"print(get_config_var('prefix'))",
|
||||
"print(get_python_version())",
|
||||
"print(numpy.get_include())"))
|
||||
info = getCommandOutput(python_command, '-c', script)
|
||||
module_ext, py_version, numpy_include = info.splitlines()[-3:]
|
||||
|
||||
incDirs = (".", "../../include", numpy_include,
|
||||
localenv['sundials_include'], localenv['boost_inc_dir'])
|
||||
env['py_include_dirs'] = repr([x for x in incDirs if x])
|
||||
|
||||
module_ext, inc, prefix, py_version, numpy_include = info.splitlines()[-5:]
|
||||
env.Append(CPPPATH=[inc, numpy_include, Dir('#include')])
|
||||
env.Prepend(LIBS=env['cantera_libs'])
|
||||
if env['OS'] == 'Darwin':
|
||||
env.Append(LINKFLAGS='-undefined dynamic_lookup')
|
||||
elif env['OS'] == 'Windows':
|
||||
env.Append(LIBPATH=prefix+'/libs')
|
||||
return module_ext, py_version
|
||||
|
||||
|
||||
def add_dependencies(mod, ext):
|
||||
localenv.Depends(mod, ext)
|
||||
localenv.Depends(ext, localenv['cantera_staticlib'])
|
||||
localenv.Depends(mod, dataFiles + testFiles + scripts)
|
||||
for f in mglob(localenv, 'cantera', 'pyx', 'pxd'):
|
||||
localenv.Depends(ext, f)
|
||||
|
||||
for f in (mglob(localenv, 'cantera/test', 'py') +
|
||||
mglob(localenv, 'cantera/mixmaster', 'py') +
|
||||
|
|
@ -42,6 +43,15 @@ def add_dependencies(mod, ext):
|
|||
mglob(localenv, 'cantera/examples/misc', 'py')):
|
||||
localenv.Depends(mod, f)
|
||||
|
||||
|
||||
def cythonize(target, source, env):
|
||||
Cython.Build.cythonize([f.abspath for f in source])
|
||||
|
||||
cythonized = localenv.Command('cantera/_cantera.cpp', ['cantera/_cantera.pyx'],
|
||||
cythonize)
|
||||
for f in mglob(localenv, 'cantera', 'pyx', 'pxd'):
|
||||
localenv.Depends(cythonized, f)
|
||||
|
||||
script_ext = '.py' if os.name == 'nt' else ''
|
||||
localenv['py_ctml_writer'] = repr('scripts/ctml_writer%s' % script_ext)
|
||||
localenv['py_ck2cti'] = repr('scripts/ck2cti%s' % script_ext)
|
||||
|
|
@ -96,41 +106,6 @@ def install_module(prefix, python_version):
|
|||
' --target-version=%s' % python_version)
|
||||
env['python%s_module_loc' % ver] = '<unspecified>'
|
||||
|
||||
|
||||
libDirs = ('../../build/lib', localenv['sundials_libdir'],
|
||||
localenv['blas_lapack_dir'], localenv['boost_lib_dir'])
|
||||
localenv['py_cantera_libs'] = repr(localenv['cantera_libs'])
|
||||
localenv['py_libdirs'] = repr([x for x in libDirs if x])
|
||||
|
||||
# Compile the Python module with the same compiler as the rest of Cantera,
|
||||
# unless otherwise specified
|
||||
localenv['py_extra_compiler_args'] = repr([])
|
||||
localenv['py_extra_link_args'] = repr([])
|
||||
if localenv['OS'] == 'Windows':
|
||||
if env['CC'] == 'cl':
|
||||
flags = ['/EHsc']
|
||||
if env['debug']:
|
||||
flags.extend(['/Zi', '/Fd_cantera.pdb'])
|
||||
localenv['py_extra_link_args'] = repr(['/DEBUG'])
|
||||
compilerOpt = ' --compiler=msvc'
|
||||
localenv['py_extra_compiler_args'] = repr(flags)
|
||||
|
||||
elif env['CC'] == 'gcc':
|
||||
compilerOpt = ' --compiler=mingw32'
|
||||
else:
|
||||
compilerOpt = ''
|
||||
if '-fprofile-arcs' in localenv['CCFLAGS']:
|
||||
localenv['py_extra_compiler_args'] = repr(['-fprofile-arcs', '-ftest-coverage'])
|
||||
localenv['py_extra_link_args'] = repr(['-fprofile-arcs', '-ftest-coverage'])
|
||||
if env['python_compiler']:
|
||||
localenv['ENV']['CC'] = env['python_compiler']
|
||||
localenv['ENV']['CXX'] = env['python_compiler']
|
||||
|
||||
if 'LDFLAGS' not in localenv['ENV']:
|
||||
localenv['ENV']['LDFLAGS'] = ''
|
||||
for framework in localenv['FRAMEWORKS']:
|
||||
localenv['ENV']['LDFLAGS'] += ' -framework ' + framework
|
||||
|
||||
dataFiles = localenv.RecursiveInstall('#interfaces/cython/cantera/data',
|
||||
'#build/data')
|
||||
build(dataFiles)
|
||||
|
|
@ -142,29 +117,22 @@ build(testFiles)
|
|||
# Cython module for Python 3.x
|
||||
if localenv['python3_package'] == 'y':
|
||||
py3env = localenv.Clone()
|
||||
module_ext, py3_version = configure_numpy(py3env, py3env['python3_cmd'])
|
||||
make_setup = py3env.SubstFile('#interfaces/cython/setup3.py',
|
||||
'#interfaces/cython/setup.py.in')
|
||||
build(make_setup)
|
||||
module_ext, py3_version = configure_python(py3env, py3env['python3_cmd'])
|
||||
|
||||
build_base = ('cd interfaces/cython &&'
|
||||
' $python3_cmd setup3.py %s'
|
||||
' --build-lib=../../build/python3'
|
||||
' --build-temp=../../build/temp-py3'
|
||||
+ compilerOpt)
|
||||
obj = py3env.SharedObject('#build/temp-py/_cantera3', 'cantera/_cantera.cpp')
|
||||
ext = py3env.LoadableModule('#build/python3/cantera/_cantera%s' % module_ext,
|
||||
obj, LIBPREFIX='', SHLIBSUFFIX=module_ext,
|
||||
LIBSUFFIXES=[module_ext])
|
||||
py3env['py_extension'] = ext[0].name
|
||||
|
||||
build_cmd = build_base % 'build'
|
||||
ext = build(py3env.Command('#build/python3/cantera/_cantera%s' % module_ext,
|
||||
'setup3.py',
|
||||
build_base % 'build_ext'))
|
||||
mod = build(py3env.Command('#build/python3/cantera/__init__.py',
|
||||
'setup3.py',
|
||||
py3env.SubstFile('setup3.py', 'setup.py.in')
|
||||
build_cmd = ('cd interfaces/cython &&'
|
||||
' $python3_cmd setup3.py build --build-lib=../../build/python3')
|
||||
mod = build(py3env.Command('#build/python3/cantera/__init__.py', 'setup3.py',
|
||||
build_cmd))
|
||||
env['python3_module'] = mod
|
||||
env['python3_extension'] = ext
|
||||
|
||||
py3env.AddPreAction(ext, Delete('interfaces/cython/cantera/_cantera.cpp'))
|
||||
|
||||
add_dependencies(mod, ext)
|
||||
install_module(py3env['python3_prefix'], py3_version)
|
||||
|
||||
|
|
@ -172,29 +140,22 @@ if localenv['python3_package'] == 'y':
|
|||
# Cython module for Python 2.x
|
||||
if localenv['python_package'] == 'full':
|
||||
py2env = localenv.Clone()
|
||||
module_ext, py2_version = configure_numpy(py2env, py2env['python_cmd'])
|
||||
make_setup = py2env.SubstFile('#interfaces/cython/setup2.py',
|
||||
'#interfaces/cython/setup.py.in')
|
||||
build(make_setup)
|
||||
module_ext, py2_version = configure_python(py2env, py2env['python_cmd'])
|
||||
|
||||
build_base = ('cd interfaces/cython &&'
|
||||
' $python_cmd setup2.py %s'
|
||||
' --build-lib=../../build/python2'
|
||||
' --build-temp=../../build/temp-py2'
|
||||
+ compilerOpt)
|
||||
|
||||
build_cmd = build_base % 'build'
|
||||
ext = build(py2env.Command('#build/python2/cantera/_cantera%s' % module_ext,
|
||||
'setup2.py',
|
||||
build_base % 'build_ext'))
|
||||
obj = py2env.SharedObject('#build/temp-py/_cantera2', 'cantera/_cantera.cpp')
|
||||
ext = py2env.LoadableModule('#build/python2/cantera/_cantera%s' % module_ext,
|
||||
obj, LIBPREFIX='', SHLIBSUFFIX=module_ext,
|
||||
LIBSUFFIXES=[module_ext])
|
||||
py2env['py_extension'] = ext[0].name
|
||||
py2env.SubstFile('setup2.py', 'setup.py.in')
|
||||
build_cmd = ('cd interfaces/cython &&'
|
||||
' $python_cmd setup2.py build --build-lib=../../build/python2')
|
||||
mod = build(py2env.Command('#build/python2/cantera/__init__.py',
|
||||
'setup2.py',
|
||||
build_cmd))
|
||||
env['python2_module'] = mod
|
||||
env['python2_extension'] = ext
|
||||
|
||||
py2env.AddPreAction(ext, Delete('interfaces/cython/cantera/_cantera.cpp'))
|
||||
|
||||
# Use 3to2 to convert examples from Python 3 syntax
|
||||
if env['python_convert_examples']:
|
||||
def convert_example(target, source, env):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import os
|
||||
from distutils.core import setup
|
||||
from Cython.Build import cythonize
|
||||
|
||||
# Monkey patch to prevent bdist_msi from incorrectly overwriting the value of
|
||||
# build-lib specified on the command line.
|
||||
|
|
@ -32,14 +31,6 @@ if os.name == 'nt':
|
|||
bdist_msi.run = bdist_run_new
|
||||
|
||||
|
||||
exts = cythonize("cantera/_cantera.pyx")
|
||||
|
||||
exts[0].include_dirs += @py_include_dirs@
|
||||
exts[0].extra_compile_args += @py_extra_compiler_args@
|
||||
exts[0].libraries += @py_cantera_libs@
|
||||
exts[0].library_dirs += @py_libdirs@
|
||||
exts[0].extra_link_args += @py_extra_link_args@
|
||||
|
||||
setup(name="Cantera",
|
||||
version="@cantera_version@",
|
||||
description="The Cantera Python Interface",
|
||||
|
|
@ -58,8 +49,7 @@ setup(name="Cantera",
|
|||
scripts=[@py_ctml_writer@,
|
||||
@py_ck2cti@,
|
||||
@py_mixmaster@],
|
||||
ext_modules = exts,
|
||||
package_data = {'cantera.data': ['*.*'],
|
||||
'cantera.test.data': ['*.*'],
|
||||
'cantera.examples': ['*/*.*'],
|
||||
'cantera': ['*.pxd']})
|
||||
'cantera': ["@py_extension@", '*.pxd']})
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue