Files
cantera/interfaces/cython/SConscript
Ray Speth 29587eeba5 [SCons] Improve staged installations of Python module
Fixes setup_cantera and the post-install message to reference the path
of the Python module on the target system rather than the staging
directory.

Also, generated .pyc files no long specify the path in the staging
directory. This has no effect on the use of the .pyc files, but helps
avoid warnings/errors from packaging system linters (notably, on
FreeBSD).

Fixes #1094
2021-09-20 12:33:47 -04:00

159 lines
6.9 KiB
Python

"""Cython-based Python Module"""
import re
from os.path import join as pjoin
from os.path import normpath
from pathlib import Path
from pkg_resources import parse_version
from buildutils import *
Import('env', 'build', 'install')
localenv = env.Clone()
cythonized = localenv.Command(
'cantera/_cantera.cpp',
'cantera/_cantera.pyx',
'''${python_cmd} -c "import Cython.Build; Cython.Build.cythonize('${SOURCE}')"''')
for f in multi_glob(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))
dataFiles = localenv.RecursiveInstall('#interfaces/cython/cantera/data',
'#build/data')
build(dataFiles)
testFiles = localenv.RecursiveInstall('#interfaces/cython/cantera/test/data',
'#test/data')
build(testFiles)
# Get information needed to build the Python module
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 = get_command_output(localenv["python_cmd"], "-c", script)
module_ext, inc, pylib, prefix, py_version, numpy_include = info.splitlines()[-6:]
localenv.Prepend(CPPPATH=[Dir('#include'), inc, numpy_include])
localenv.Prepend(LIBS=localenv['cantera_libs'])
# Don't print deprecation warnings for internal Python changes.
# Only applies to Python 3.8. The field that is deprecated in Python 3.8
# and causes the warnings to appear will be removed in Python 3.9 so no
# further warnings should be issued.
if localenv['HAS_CLANG'] and parse_version(py_version) == parse_version('3.8'):
localenv.Append(CXXFLAGS='-Wno-deprecated-declarations')
if localenv['OS'] == 'Darwin':
localenv.Append(LINKFLAGS='-undefined dynamic_lookup')
elif localenv['OS'] == 'Windows':
localenv.Append(LIBPATH=prefix+'/libs')
if localenv['toolchain'] == 'mingw':
localenv.Append(LIBS='python{}'.format(py_version.replace('.','')))
if localenv['OS_BITS'] == 64:
localenv.Append(CPPDEFINES='MS_WIN64')
# fix for http://bugs.python.org/issue11566
localenv.Append(CPPDEFINES={'_hypot':'hypot'})
elif localenv['OS'] == 'Cygwin':
# extract 'pythonX.Y' from 'libpythonX.Y.dll.a'
localenv.Append(LIBS=pylib[3:-6])
# Build the Python module
obj = localenv.SharedObject('#build/temp-py/_cantera', 'cantera/_cantera.cpp')
ext = localenv.LoadableModule('#build/python/cantera/_cantera{}'.format(module_ext),
obj, LIBPREFIX='', SHLIBSUFFIX=module_ext,
SHLIBPREFIX='', LIBSUFFIXES=[module_ext])
localenv['py_extension'] = ext[0].name
localenv.SubstFile('setup.py', 'setup.py.in')
build_cmd = ('cd interfaces/cython &&'
' $python_cmd_esc setup.py build --build-lib=../../build/python')
mod = build(localenv.Command('#build/python/cantera/__init__.py', 'setup.py',
build_cmd))
env['python_module'] = mod
env['python_extension'] = ext
localenv.Depends(mod, ext)
localenv.Depends(mod, dataFiles + testFiles)
localenv.Depends(ext, localenv['cantera_staticlib'])
for f in (multi_glob(localenv, 'cantera', 'py') +
multi_glob(localenv, 'cantera/test', 'py') +
multi_glob(localenv, 'cantera/examples/kinetics', 'py') +
multi_glob(localenv, 'cantera/examples/multiphase', 'py') +
multi_glob(localenv, 'cantera/examples/onedim', 'py') +
multi_glob(localenv, 'cantera/examples/reactors', 'py') +
multi_glob(localenv, 'cantera/examples/surface_chemistry', 'py') +
multi_glob(localenv, 'cantera/examples/thermo', 'py') +
multi_glob(localenv, 'cantera/examples/transport', 'py')):
localenv.Depends(mod, f)
# Determine installation path and install the Python module
if localenv['python_prefix'] == 'USER':
# Install to the OS-dependent user site-packages directory
extra = '--user'
if localenv['OS'] == 'Darwin':
extra += ' --prefix=""'
elif localenv['python_prefix']:
# A specific location for the Cantera python module has been given
if localenv['debian'] and localenv.subst('${python_prefix}') == '/usr/local':
# Installation to /usr/local is the default on Debian-based distributions
extra = ''
elif localenv['OS'] == 'Darwin':
extra = localenv.subst(' --prefix=${python_prefix}')
elif localenv['libdirname'] != 'lib':
# 64-bit RHEL / Fedora etc. or e.g. x32 Gentoo profile
extra = localenv.subst(
' --prefix=${{python_prefix}}'
' --install-lib=${{python_prefix}}/${{libdirname}}/python{}/site-packages'.format(py_version))
else:
extra = '--user'
localenv.AppendENVPath(
'PYTHONUSERBASE',
normpath(localenv.subst('$python_prefix')))
else:
# Install Python module in the default location
extra = ''
if env["stage_dir"]:
# Get the absolute path to the stage directory. If the stage directory is a relative
# path, consider it to be relative to the root of the Cantera source directory,
# which is two directories up from the current working directory of this SConscript
# file.
stage_absolute = Path.cwd().parents[1].joinpath(env['stage_dir']).resolve()
extra += f" --root={stage_absolute}"
env['python_module_loc'] = '<unspecified>'
if localenv['PYTHON_INSTALLER'] == 'direct':
mod_inst = install(localenv.Command, 'dummy', mod,
build_cmd + ' install ' + extra +
' --record=../../build/python-installed-files.txt' +
' --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-installed-files.txt').readlines():
filename = filename.strip()
if filename.endswith(check):
global_env["python_module_loc"] = normpath(filename.replace(check, ""))
break
localenv.AlwaysBuild(localenv.AddPostAction(mod_inst, find_module_dir))
env['install_python_action'] = mod_inst
elif localenv['PYTHON_INSTALLER'] == 'debian':
extra = localenv.subst(' --root=${python_prefix}')
install(localenv.Command, 'dummy', mod,
build_cmd + ' install --install-layout=deb --no-compile ' + extra)
elif localenv['PYTHON_INSTALLER'] == 'binary':
install(localenv.Command, 'dummy', mod,
build_cmd + ' bdist_msi --dist-dir=../..' +
' --target-version=' + py_version)