Files
cantera/interfaces/cython/SConscript
Ray Speth 70e10632d4 [SCons] Fix implicit dependencies on 'build' step
The 'install' and 'test' targets had some undeclared dependencies on the 'build'
target, such that running 'scons install' or 'scons test' without having first
run 'scons build' would result in incomplete installation or test failures,
respectively.

Fixes #432.
2017-02-17 11:51:12 -05:00

208 lines
9.2 KiB
Python

""" Cython-based Python Module for Python 3 """
from buildutils import *
import Cython.Build
Import('env', 'build', 'install')
localenv = env.Clone()
def configure_python(env, python_command):
script = '\n'.join(("from distutils.sysconfig import *",
"import numpy",
"print(get_config_var('EXT_SUFFIX') or get_config_var('SO'))",
"print(get_config_var('INCLUDEPY'))",
"print(get_config_var('LDLIBRARY'))",
"print(get_config_var('prefix'))",
"print(get_python_version())",
"print(numpy.get_include())"))
info = getCommandOutput(python_command, '-c', script)
module_ext, inc, pylib, prefix, py_version, numpy_include = info.splitlines()[-6:]
env.Prepend(CPPPATH=[Dir('#include'), inc, numpy_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')
if env['toolchain'] == 'mingw':
env.Append(LIBS='python%s' % py_version.replace('.',''))
if env['OS_BITS'] == 64:
env.Append(CPPDEFINES='MS_WIN64')
# fix for http://bugs.python.org/issue11566
env.Append(CPPDEFINES={'_hypot':'hypot'})
elif env['OS'] == 'Cygwin':
# extract 'pythonX.Y' from 'libpythonX.Y.dll.a'
env.Append(LIBS=pylib[3:-6])
return module_ext, py_version
def add_dependencies(mod, ext):
localenv.Depends(mod, ext)
localenv.Depends(mod, dataFiles + testFiles)
localenv.Depends(ext, localenv['cantera_staticlib'])
for f in (mglob(localenv, 'cantera', 'py') +
mglob(localenv, 'cantera/test', 'py') +
mglob(localenv, 'cantera/examples/tutorial', 'py') +
mglob(localenv, 'cantera/examples/equilibrium', 'py') +
mglob(localenv, 'cantera/examples/kinetics', 'py') +
mglob(localenv, 'cantera/examples/transport', 'py') +
mglob(localenv, 'cantera/examples/reactors', 'py') +
mglob(localenv, 'cantera/examples/onedim', 'py') +
mglob(localenv, 'cantera/examples/surface_chemistry', 'py') +
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)
for line in open('cantera/_cantera.pxd'):
m = re.search(r'from "(cantera.*?)"', line)
if m:
localenv.Depends('cantera/_cantera.cpp', '#include/' + m.group(1))
def install_module(prefix, python_version):
major = python_version[0]
minor = python_version.split('.')[1]
ver = '3' if major == '3' else ''
dummy = 'dummy' + major
if prefix == 'USER':
# Install to the OS-dependent user site-packages directory
extra = '--user'
if localenv['OS'] == 'Darwin':
extra += ' --prefix=""'
elif prefix:
# A specific location for the Cantera python module has been given
if localenv['debian'] and localenv.subst(prefix) == '/usr/local':
# Installation to /usr/local is the default on Debian-based distributions
extra = ''
elif localenv['OS'] == 'Darwin':
extra = localenv.subst(' --prefix=${python%s_prefix}' % ver)
elif localenv['libdirname'] == 'lib64':
# 64-bit RHEL / Fedora
extra = localenv.subst(
' --prefix=${python%s_prefix} --install-lib=${python%s_prefix}/lib64/python%s.%s/site-packages' % (ver, ver, major, minor))
else:
extra = '--user'
localenv.AppendENVPath(
'PYTHONUSERBASE',
normpath(localenv.subst('$python%s_prefix' % ver)))
else:
# Install Python module in the default location
extra = ''
env['python%s_module_loc' % ver] = '<unspecified>'
if localenv['PYTHON_INSTALLER'] == 'direct':
mod_inst = install(localenv.Command, dummy, mod,
build_cmd + ' install %s' % extra +
' --record=../../build/python%s-installed-files.txt' % major +
' --single-version-externally-managed')
global_env = env
def find_module_dir(target, source, env):
check = pjoin('cantera','__init__.py')
for filename in open('build/python%s-installed-files.txt' % major).readlines():
filename = filename.strip()
if filename.endswith(check):
filename = filename.replace(check,'')
global_env['python%s_module_loc' % ver] = normpath(filename)
break
localenv.AlwaysBuild(localenv.AddPostAction(mod_inst, find_module_dir))
if not ver:
env['install_python2_action'] = mod_inst
elif localenv['PYTHON_INSTALLER'] == 'debian':
extra = localenv.subst(' --root=${python%s_prefix}' % ver)
install(localenv.Command, dummy, mod,
build_cmd + ' install --install-layout=deb --no-compile %s' % extra)
elif localenv['PYTHON_INSTALLER'] == 'binary':
install(localenv.Command, dummy, mod,
build_cmd + ' bdist_msi --dist-dir=../..' +
' --target-version=%s' % python_version)
dataFiles = localenv.RecursiveInstall('#interfaces/cython/cantera/data',
'#build/data')
build(dataFiles)
testFiles = localenv.RecursiveInstall('#interfaces/cython/cantera/test/data',
'#test/data')
build(testFiles)
for f in ['inputs/h2o2.inp', 'inputs/gri30.inp', 'transport/gri30_tran.dat']:
inp = build(localenv.Install('#interfaces/cython/cantera/test/data/', '#data/' + f))
testFiles.append(inp)
# Cython module for Python 3.x
if localenv['python3_package'] == 'y':
py3env = localenv.Clone()
module_ext, py3_version = configure_python(py3env, py3env['python3_cmd'])
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,
SHLIBPREFIX='', LIBSUFFIXES=[module_ext])
py3env['py_extension'] = ext[0].name
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
add_dependencies(mod, ext)
install_module(py3env['python3_prefix'], py3_version)
# Cython module for Python 2.x
if localenv['python_package'] == 'full':
py2env = localenv.Clone()
module_ext, py2_version = configure_python(py2env, py2env['python_cmd'])
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,
SHLIBPREFIX='', LIBSUFFIXES=[module_ext])
py2env['py_extension'] = ext[0].name
py2env.SubstFile('setup2.py', 'setup.py.in')
build_cmd = ('cd interfaces/cython &&'
' $python_cmd_esc 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
# Use 3to2 to convert examples from Python 3 syntax
if env['python_convert_examples']:
def convert_example(target, source, env):
shutil.copyfile(source[0].abspath, target[0].abspath)
if env['OS'] == 'Windows':
subprocess.call(env['threetotwo_cmd'] + ['--no-diff', '-n', '-w','-x', 'str',
'-f', 'all', '-f', 'printfunction', '-x', 'print',
'-x', 'open', target[0].abspath])
else:
subprocess.call(['3to2', '--no-diff', '-n', '-w','-x', 'str',
'-f', 'all', '-f', 'printfunction', '-x', 'print',
'-x', 'open', target[0].abspath])
for subdir in subdirs('cantera/examples'):
dirpath = pjoin('cantera', 'examples', subdir)
for filename in os.listdir(dirpath):
if not filename.endswith('.py'):
continue
targetdir = '../../build/python2/cantera/examples'
a = build(py2env.Command(pjoin(targetdir, subdir, filename),
pjoin(dirpath, filename),
convert_example))
py2env.Depends(mod, a)
add_dependencies(mod, ext)
install_module(py2env['python_prefix'], py2_version)