Skip to content

Commit 0958f7c

Browse files
committed
[SCons] Extract Python module-building environment setup
1 parent 9875cb4 commit 0958f7c

File tree

3 files changed

+88
-73
lines changed

3 files changed

+88
-73
lines changed

interfaces/cython/SConscript

Lines changed: 7 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
"""Cython-based Python Module"""
22
import re
33
from pathlib import Path
4-
from pkg_resources import parse_version
5-
import json
64
from buildutils import *
75

86
Import('env', 'build', 'install')
@@ -15,70 +13,8 @@ build(dataFiles)
1513
# Install Python samples
1614
install(localenv.RecursiveInstall, "$inst_sampledir/python", "#samples/python")
1715

18-
# Get information needed to build the Python module
19-
script = """\
20-
from sysconfig import *
21-
import numpy
22-
import json
23-
import site
24-
vars = get_config_vars()
25-
vars["plat"] = get_platform()
26-
vars["numpy_include"] = numpy.get_include()
27-
vars["site_packages"] = [d for d in site.getsitepackages() if d.endswith("-packages")]
28-
vars["user_site_packages"] = site.getusersitepackages()
29-
print(json.dumps(vars))
30-
"""
31-
info = json.loads(get_command_output(localenv["python_cmd"], "-c", script))
32-
module_ext = info["EXT_SUFFIX"]
33-
inc = info["INCLUDEPY"]
34-
pylib = info.get("LDLIBRARY")
35-
prefix = info["prefix"]
36-
py_version_short = parse_version(info["py_version_short"])
37-
py_version_full = parse_version(info["py_version"])
38-
py_version_nodot = info["py_version_nodot"]
39-
numpy_include = info["numpy_include"]
40-
site_packages = info["site_packages"]
41-
user_site_packages = info["user_site_packages"]
42-
localenv.Prepend(CPPPATH=[Dir('#include'), inc, numpy_include])
43-
localenv.Prepend(LIBS=localenv['cantera_libs'])
44-
45-
# Fix the module extension for Windows from the sysconfig library.
46-
# See https://github.com/python/cpython/pull/22088 and
47-
# https://bugs.python.org/issue39825
48-
if (
49-
py_version_full < parse_version("3.8.7")
50-
and localenv["OS"] == "Windows"
51-
and module_ext == ".pyd"
52-
):
53-
module_ext = f".cp{py_version_nodot}-{info['plat'].replace('-', '_')}.pyd"
54-
55-
# Don't print deprecation warnings for internal Python changes.
56-
# Only applies to Python 3.8. The field that is deprecated in Python 3.8
57-
# and causes the warnings to appear will be removed in Python 3.9 so no
58-
# further warnings should be issued.
59-
if localenv["HAS_CLANG"] and py_version_short == parse_version("3.8"):
60-
localenv.Append(CXXFLAGS='-Wno-deprecated-declarations')
61-
62-
if "icc" in localenv["CC"]:
63-
localenv.Append(CPPDEFINES={"CYTHON_FALLTHROUGH": " __attribute__((fallthrough))"})
64-
65-
if localenv['OS'] == 'Darwin':
66-
localenv.Append(LINKFLAGS='-undefined dynamic_lookup')
67-
elif localenv['OS'] == 'Windows':
68-
localenv.Append(LIBPATH=prefix + '/libs')
69-
if localenv['toolchain'] == 'mingw':
70-
localenv.Append(LIBS=f"python{py_version_nodot}")
71-
if localenv['OS_BITS'] == 64:
72-
localenv.Append(CPPDEFINES='MS_WIN64')
73-
# Fix for https://bugs.python.org/issue11566. Fixed in 3.7.3 and higher.
74-
# See https://github.com/python/cpython/pull/11283
75-
if py_version_full < parse_version("3.7.3"):
76-
localenv.Append(CPPDEFINES={"_hypot": "hypot"})
77-
78-
if "numpy_1_7_API" in localenv:
79-
localenv.Append(CPPDEFINES="NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION")
80-
81-
localenv["module_ext"] = module_ext
16+
setup_python_env(localenv)
17+
8218
setup_cfg = localenv.SubstFile("setup.cfg", "setup.cfg.in")
8319
readme = localenv.Command("README.rst", "#README.rst", Copy("$TARGET", "$SOURCE"))
8420
license = localenv.Command("LICENSE.txt", "#build/ext/LICENSE.txt",
@@ -104,15 +40,15 @@ for pyxfile in multi_glob(localenv, "cantera", "pyx"):
10440
f"#build/temp-py/{pyxfile.name.split('.')[0]}", cythonized)
10541
cython_obj.append(obj)
10642

43+
module_ext = localenv["py_module_ext"]
10744
ext = localenv.LoadableModule(f"cantera/_cantera{module_ext}",
10845
cython_obj, LIBPREFIX="", SHLIBSUFFIX=module_ext,
10946
SHLIBPREFIX="", LIBSUFFIXES=[module_ext])
11047

11148
build_cmd = ("$python_cmd_esc -m pip wheel -v --no-build-isolation --no-deps "
11249
"--wheel-dir=build/python/dist build/python")
113-
plat = info['plat'].replace('-', '_').replace('.', '_')
114-
wheel_name = (f"Cantera-{env['cantera_version']}-cp{py_version_nodot}"
115-
f"-cp{py_version_nodot}-{plat}.whl")
50+
wheel_name = ("Cantera-${cantera_version}-cp${py_version_nodot}"
51+
"-cp${py_version_nodot}-${plat}.whl")
11652
mod = build(localenv.Command(f"#build/python/dist/{wheel_name}", "setup.cfg",
11753
build_cmd))
11854
env['python_module'] = mod
@@ -153,9 +89,9 @@ else:
15389
ignore_errors=True)
15490

15591
if user_install:
156-
test_prefix = Path(user_site_packages).parents[2]
92+
test_prefix = Path(localenv["user_site_packages"]).parents[2]
15793
elif python_prefix is None:
158-
test_prefix = Path(site_packages[0]).parents[2]
94+
test_prefix = Path(localenv["site_packages"][0]).parents[2]
15995
else:
16096
test_prefix = Path(python_prefix)
16197

interfaces/cython/setup.cfg.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ packages =
5151
# The module extension needs to be here since we don't want setuptools to compile
5252
# the extension, so there are no ``source`` files in the setup.py ``extension`` and
5353
# we have to treat the module as package data.
54-
cantera = *.pxd, *@module_ext@, test/*.txt, examples/*.txt, data/*.*
54+
cantera = *.pxd, *@py_module_ext@, test/*.txt, examples/*.txt, data/*.*
5555

5656
[options.extras_require]
5757
hdf5 = h5py

site_scons/buildutils.py

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
import shutil
1212
import enum
1313
from pathlib import Path
14+
from pkg_resources import parse_version
1415
import logging
1516
from typing import TYPE_CHECKING
1617
from collections.abc import Mapping as MappingABC
1718
from SCons.Variables import PathVariable, EnumVariable, BoolVariable
19+
from SCons.Script import Dir
1820

1921
try:
2022
import numpy as np
@@ -25,7 +27,7 @@
2527
"logger", "remove_directory", "remove_file", "test_results",
2628
"add_RegressionTest", "get_command_output", "listify", "which",
2729
"ConfigBuilder", "multi_glob", "get_spawn", "quoted",
28-
"get_pip_install_location", "compiler_flag_list")
30+
"get_pip_install_location", "compiler_flag_list", "setup_python_env")
2931

3032
if TYPE_CHECKING:
3133
from typing import Iterable, TypeVar, Union, List, Dict, Tuple, Optional, \
@@ -1246,6 +1248,83 @@ def get_command_output(cmd: str, *args: str, ignore_errors=False):
12461248
)
12471249
return data.stdout.strip()
12481250

1251+
_python_info = None
1252+
def setup_python_env(env):
1253+
"""Set up an environment for compiling Python extension modules"""
1254+
1255+
global _python_info
1256+
if _python_info is None:
1257+
# Get information needed to build the Python module
1258+
script = textwrap.dedent("""\
1259+
from sysconfig import *
1260+
import numpy
1261+
import json
1262+
import site
1263+
vars = get_config_vars()
1264+
vars["plat"] = get_platform()
1265+
vars["numpy_include"] = numpy.get_include()
1266+
vars["site_packages"] = [d for d in site.getsitepackages() if d.endswith("-packages")]
1267+
vars["user_site_packages"] = site.getusersitepackages()
1268+
print(json.dumps(vars))
1269+
""")
1270+
_python_info = json.loads(get_command_output(env["python_cmd"], "-c", script))
1271+
1272+
info = _python_info
1273+
module_ext = info["EXT_SUFFIX"]
1274+
inc = info["INCLUDEPY"]
1275+
pylib = info.get("LDLIBRARY")
1276+
prefix = info["prefix"]
1277+
py_version_short = parse_version(info["py_version_short"])
1278+
py_version_full = parse_version(info["py_version"])
1279+
py_version_nodot = info["py_version_nodot"]
1280+
plat = info['plat'].replace('-', '_').replace('.', '_')
1281+
numpy_include = info["numpy_include"]
1282+
env.Prepend(CPPPATH=[Dir('#include'), inc, numpy_include])
1283+
env.Prepend(LIBS=env['cantera_libs'])
1284+
1285+
# Fix the module extension for Windows from the sysconfig library.
1286+
# See https://github.com/python/cpython/pull/22088 and
1287+
# https://bugs.python.org/issue39825
1288+
if (py_version_full < parse_version("3.8.7")
1289+
and env["OS"] == "Windows"
1290+
and module_ext == ".pyd"
1291+
):
1292+
module_ext = f".cp{py_version_nodot}-{info['plat'].replace('-', '_')}.pyd"
1293+
1294+
env["py_module_ext"] = module_ext
1295+
env["py_version_nodot"] = py_version_nodot
1296+
env["py_plat"] = plat
1297+
env["site_packages"] = info["site_packages"]
1298+
env["user_site_packages"] = info["user_site_packages"]
1299+
1300+
# Don't print deprecation warnings for internal Python changes.
1301+
# Only applies to Python 3.8. The field that is deprecated in Python 3.8
1302+
# and causes the warnings to appear will be removed in Python 3.9 so no
1303+
# further warnings should be issued.
1304+
if env["HAS_CLANG"] and py_version_short == parse_version("3.8"):
1305+
env.Append(CXXFLAGS='-Wno-deprecated-declarations')
1306+
1307+
if "icc" in env["CC"]:
1308+
env.Append(CPPDEFINES={"CYTHON_FALLTHROUGH": " __attribute__((fallthrough))"})
1309+
1310+
if env['OS'] == 'Darwin':
1311+
env.Append(LINKFLAGS='-undefined dynamic_lookup')
1312+
elif env['OS'] == 'Windows':
1313+
env.Append(LIBPATH=prefix + '/libs')
1314+
if env['toolchain'] == 'mingw':
1315+
env.Append(LIBS=f"python{py_version_nodot}")
1316+
if env['OS_BITS'] == 64:
1317+
env.Append(CPPDEFINES='MS_WIN64')
1318+
# Fix for https://bugs.python.org/issue11566. Fixed in 3.7.3 and higher.
1319+
# See https://github.com/python/cpython/pull/11283
1320+
if py_version_full < parse_version("3.7.3"):
1321+
env.Append(CPPDEFINES={"_hypot": "hypot"})
1322+
1323+
if "numpy_1_7_API" in env:
1324+
env.Append(CPPDEFINES="NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION")
1325+
1326+
1327+
return env
12491328

12501329
def get_pip_install_location(
12511330
python_cmd: str,

0 commit comments

Comments
 (0)