-
-
Notifications
You must be signed in to change notification settings - Fork 423
Expand file tree
/
Copy pathSConscript
More file actions
202 lines (169 loc) · 8.5 KB
/
Copy pathSConscript
File metadata and controls
202 lines (169 loc) · 8.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
"""Cython-based Python Module"""
import re
from pathlib import Path
from packaging.specifiers import SpecifierSet
from packaging.version import parse as parse_version
from buildutils import (get_command_output, which, multi_glob, logger,
get_pip_install_location, setup_python_env)
Import('env', 'build', 'install')
localenv = env.Clone()
dataFiles = []
for yaml in multi_glob(localenv, "#data", "yaml"):
dataFiles.append(build(
localenv.Command(f"cantera/data/{yaml.name}", yaml.abspath,
Copy("$TARGET", "$SOURCE"))))
if localenv["example_data"]:
for yaml in multi_glob(localenv, "#data/example_data", "yaml"):
dataFiles.append(build(
localenv.Command(f"cantera/data/example_data/{yaml.name}", yaml.abspath,
Copy("$TARGET", "$SOURCE"))))
# Install Python samples
install(localenv.RecursiveInstall, "$inst_sampledir/python", "#samples/python")
setup_python_env(localenv)
logger.info(f"Using setuptools version {localenv['setuptools_version']}")
# Python module shouldn't explicitly link to Python library (added in other cases to
# support Python-based extensions), except when using MinGW
if localenv["toolchain"] != "mingw":
localenv["LIBS"] = [lib for lib in localenv["LIBS"] if not lib.startswith("python")]
setup_cfg = localenv.SubstFile("setup.cfg", "setup.cfg.in")
readme = localenv.Command("README.rst", "#README.rst", Copy("$TARGET", "$SOURCE"))
license = localenv.Command("LICENSE.txt", "#build/ext/LICENSE.txt",
Copy("$TARGET", "$SOURCE"))
localenv.Depends(license, localenv["license_target"])
directives = {"binding": True}
if env["coverage"]:
directives["linetrace"] = True
localenv.Append(CPPDEFINES={
"CYTHON_TRACE": 1,
# TODO: Remove after https://github.com/coveragepy/coveragepy/issues/1790 is resolved.
"CYTHON_USE_SYS_MONITORING": 0}
)
# Build the Python module
cython_obj = []
for pyxfile in multi_glob(localenv, "cantera", "pyx"):
if pyxfile.name == "_utils.pyx":
# Define GIT_COMMIT only in _utils.pyx to avoid unnecessary recompilations
cython_env = localenv.Clone()
cython_env.Append(CPPDEFINES={'GIT_COMMIT': '\\"{0}\\"'.format(env['git_commit'])})
else:
cython_env = localenv
cython_output = f"cantera/{pyxfile.name.replace('.pyx', '.cpp')}"
if pyxfile.name == "delegator.pyx":
cython_output = [cython_output, "cantera/delegator.h"]
cythonized = cython_env.Command(
cython_output, pyxfile,
f'''${{python_cmd}} -c "import setuptools; import Cython.Build; Cython.Build.cythonize(r'${{SOURCE}}', compiler_directives={directives!r})"'''
)
for pxd in multi_glob(cython_env, "cantera", "pxd"):
cython_env.Depends(cythonized, pxd)
obj = cython_env.SharedObject(
f"#build/temp-py/{pyxfile.name.split('.')[0]}", cythonized[0])
cython_obj.append(obj)
copy_header = localenv.Command('#src/extensions/delegator.h', '#build/python/cantera/delegator.h',
Copy('$TARGET', '$SOURCE'))
ext_manager = localenv.SharedObject("#src/extensions/PythonExtensionManager.cpp")
cython_obj.extend(ext_manager)
env.Depends(ext_manager, copy_header)
module_ext = localenv["py_module_ext"]
ext = localenv.LoadableModule(f"cantera/_cantera{module_ext}",
cython_obj, LIBPREFIX="", SHLIBSUFFIX=module_ext,
SHLIBPREFIX="", LIBSUFFIXES=[module_ext])
build_cmd = ("$python_cmd_esc -m pip wheel -v --no-build-isolation --no-deps "
"--wheel-dir=build/python/dist build/python")
# We've already warned that this Python version might be unsupported, so disable
# pip's check for a correct version of Python.
if parse_version(localenv["py_version_short"]) >= env["python_max_version"]:
build_cmd += " --ignore-requires-python"
# Newer setuptools versions always lowercase the package name
spec1 = SpecifierSet(">=75.8.1")
spec2 = SpecifierSet("~=75.3.1") # change backported to this branch
if localenv["setuptools_version"] in spec1 or localenv["setuptools_version"] in spec2:
pkg_name = "cantera"
else:
pkg_name = "Cantera"
wheel_name = (pkg_name + "-${cantera_version}-cp${py_version_nodot}"
"-cp${py_version_nodot}-${py_plat}.whl")
mod = build(localenv.Command(f"#build/python/dist/{wheel_name}", "setup.cfg",
build_cmd))
env['python_module'] = mod
env['python_extension'] = ext
localenv.Depends(mod, [ext, dataFiles, setup_cfg, readme, license,
"setup.py", "pyproject.toml",
"cantera/test/README.txt", "cantera/examples/README.txt"])
if env['OS'] == 'Windows':
# On Windows, the cantera library directory is likely not to be on the path.
# However, Windows does search the directory containing a library (i.e. the
# Python extension module) for DLL dependencies.
dll = [f for f in localenv['cantera_shlib'] if f.name.endswith('.dll')][0]
copy_dll = localenv.Command(f'cantera/{dll.name}', dll, Copy("$TARGET", "$SOURCE"))
localenv.Depends(ext, copy_dll)
# If compiling with MinGW, there are some system libraries that also seem
# to need to be installed alongside the Python extension -- elsewhere on the path
# does not appear to work.
if env['toolchain'] == 'mingw':
mingw_dir = Path(which(env.subst('$CXX'))).parent
prefixes = ['libgcc', 'libstdc++', 'libwinpthread']
for lib in mingw_dir.glob('*.dll'):
if any(lib.name.startswith(prefix) for prefix in prefixes):
copy_lib = localenv.Command(f'cantera/{lib.name}', str(lib),
Copy('$TARGET', '$SOURCE'))
localenv.Depends(mod, copy_lib)
else:
localenv.Depends(ext, localenv['cantera_shlib'])
for f in (multi_glob(localenv, 'cantera', 'py', 'pyi') +
multi_glob(localenv, 'cantera/*', 'py', 'pyi')):
localenv.Depends(mod, f)
localenv.Depends(mod, 'cantera/py.typed')
units = localenv.UnitsInterfaceBuilder(
"cantera/with_units/solution.py",
"cantera/with_units/solution.py.in",
)
localenv.Depends(mod, units)
# Determine installation path and install the Python module
install_cmd = ["$python_cmd_esc", "-m", "pip", "install"]
user_install = False
python_prefix = None
if localenv['python_prefix'] == 'USER':
# Install to the OS-dependent user site-packages directory
install_cmd.append("--user")
user_install = True
elif localenv["python_prefix"]:
# A specific location for the Cantera python module has been given
install_cmd.append(f"--prefix={localenv.subst('$python_prefix')}")
python_prefix = localenv.subst("$python_prefix")
elif not env["default_prefix"]:
install_cmd.append(f"--prefix={env['prefix']}")
python_prefix = env["prefix"]
# Check for existing Python module installation. Allow pip to remove an existing
# installation only if we're installing to the same location. Also disable
# uninstallation if we're installing to a staging directory.
if env["stage_dir"]:
install_cmd.append("--ignore-installed")
else:
info = get_command_output(localenv["python_cmd"], "-m", "pip", "show", "cantera",
ignore_errors=True)
if user_install:
test_prefix = Path(localenv["user_site_packages"]).parents[2]
elif python_prefix is None:
test_prefix = Path(localenv["site_packages"][0]).parents[2]
else:
test_prefix = Path(python_prefix)
match = re.search(r"Location: (.*)\n", info, re.MULTILINE)
existing_prefix = Path(match.group(1)).parents[2] if match else None
if existing_prefix and existing_prefix != test_prefix:
install_cmd.append("--ignore-installed")
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.
stage_dir = Path(env["stage_dir"])
if not stage_dir.is_absolute():
stage_dir = Path(Dir("#").abspath) / stage_dir
install_cmd.append(f"--root={stage_dir.resolve()}")
install_cmd.extend(("--no-build-isolation", "--no-deps", "-v", "--force-reinstall",
"$SOURCE"))
mod_inst = install(localenv.Command, "dummy", mod, " ".join(install_cmd))
env["install_python_action"] = mod_inst
install_locs = get_pip_install_location(localenv["python_cmd"], user_install,
python_prefix)
env["python_module_loc"] = Path(install_locs["platlib"]).as_posix()
env["ct_pyscriptdir"] = Path(install_locs["scripts"]).as_posix()