diff --git a/SConstruct b/SConstruct index 11ed47d564..000c4e149b 100644 --- a/SConstruct +++ b/SConstruct @@ -126,6 +126,8 @@ if "clean" in COMMAND_LINE_TARGETS: remove_directory("test/work") remove_file(".sconsign.dblite") remove_file("include/cantera/base/config.h") + remove_file("src/extensions/PythonExtensionManager.os") + remove_file("src/extensions/delegator.h") remove_file("src/pch/system.h.gch") remove_directory("include/cantera/ext") remove_file("config.log") diff --git a/interfaces/python_sdist/MANIFEST.in b/interfaces/python_sdist/MANIFEST.in index 9b1ae04f48..78bbd163b7 100644 --- a/interfaces/python_sdist/MANIFEST.in +++ b/interfaces/python_sdist/MANIFEST.in @@ -2,10 +2,11 @@ # the wheel file if they are also listed in setup.cfg:options.package_data and not # listed in setup.cfg:options.exclude_package_data. -include cantera/_cantera.cpp +recursive-include cantera *.cpp +recursive-include cantera *.h recursive-include cantera *.pyx +recursive-include cantera *.pxd include sundials_config.h.in -include config.h.in graft include # The C/C++ files in these folders are included automatically because they're in diff --git a/interfaces/python_sdist/SConscript b/interfaces/python_sdist/SConscript index 0aaf71b7e3..d9a8c16766 100644 --- a/interfaces/python_sdist/SConscript +++ b/interfaces/python_sdist/SConscript @@ -9,8 +9,7 @@ from build.env import IsolatedEnvBuilder from buildutils import logger -Import("env", "configh") -configh = configh.copy() +Import("env") localenv = env.Clone() @@ -84,11 +83,13 @@ def replace_git_hash(target, source, env): sdist(localenv.RecursiveInstall( "src", "#src", - exclude=["fortran", "matlab", "clib", r"global\.cpp", "SCons.*"], + exclude=["fortran", "matlab", "clib", r"global\.cpp", "SCons.*", r"canteraStatic\.cpp"], )) sdist(localenv.Command("src/base/global.cpp", "#src/base/global.cpp", replace_git_hash)) +sdist(localenv.Command("include/cantera/cython/utils_utils.h", "#include/cantera/cython/utils_utils.h", + replace_git_hash)) # This is the only bit of the clib that we need for the Python interface clib_defs_target = sdist(localenv.Command( @@ -107,10 +108,11 @@ include_target = sdist(localenv.RecursiveInstall( "clib$", "ext$", r"config\.h\.in", - r"config\.h", + r"utils_utils\.h", ], )) localenv.Depends(clib_defs_target, include_target) +localenv.Depends(include_target, env["config_h_target"]) ext_include_target = sdist(localenv.Command( "include/cantera/ext", @@ -122,45 +124,6 @@ localenv.Depends(ext_include_target, include_target) ext_target = sdist(localenv.Command("ext", "#ext", copy_ext_src)) -# Disable Lapack for the sdist -configh["CT_USE_LAPACK"] = None -configh["CT_SUNDIALS_USE_LAPACK"] = None - - -class DefineDict: - """dict-like class used to fill config.h.in partially. - - We cannot use buildutils.DefineDict because missing keys in self.data are replaced - with /* #undef {key} */, but here we want to leave those as template strings for - setup.py to fill in on the final build machine. - """ - - def __init__(self, data): - self.data = data - - def __getitem__(self, key): - if key not in self.data: - return f"{{{key!s}!s}}" - elif self.data[key] is None: - return f"/* #undef {key!s} */" - else: - return f"#define {key!s} {self.data[key]!s}" - - -def config_builder(target, source, env): - configh = env["configh"] - config_h = Path(str(target[0])) - config_h_in = Path(str(source[0])).read_text() - config_h.write_text(config_h_in.format_map(configh)) - - -localenv["configh"] = DefineDict(configh) -config_h_in_target = sdist(localenv.Command( - "config.h.in", - "#include/cantera/base/config.h.in", - config_builder, -)) - sdist(localenv.UnitsInterfaceBuilder( "cantera/with_units/solution.py", "#interfaces/cython/cantera/with_units/solution.py.in", diff --git a/interfaces/python_sdist/pyproject.toml b/interfaces/python_sdist/pyproject.toml index 1bb9493c62..b16f5851bb 100644 --- a/interfaces/python_sdist/pyproject.toml +++ b/interfaces/python_sdist/pyproject.toml @@ -1,10 +1,10 @@ [build-system] -# These versions are pinned to the latest versions at the time of this commit. -# Feel free to update as required. +# These versions are updated to the latest versions supported in cibuildwheel +# at the time of this commit. Feel free to update as required. requires = [ - "setuptools==67.7.1", + "setuptools>=67.6.1", "wheel", "oldest-supported-numpy", - "Cython==0.29.34", + "Cython>=0.29.34", ] build-backend = "setuptools.build_meta" diff --git a/interfaces/python_sdist/setup.cfg.in b/interfaces/python_sdist/setup.cfg.in index 77aa5557b7..219e53a3f0 100644 --- a/interfaces/python_sdist/setup.cfg.in +++ b/interfaces/python_sdist/setup.cfg.in @@ -45,6 +45,7 @@ install_requires = packaging python_requires @py_requires_ver_str@ packages = + cantera cantera.data cantera.examples cantera.test diff --git a/interfaces/python_sdist/setup.py b/interfaces/python_sdist/setup.py index 127297a178..f6a7e6b2eb 100644 --- a/interfaces/python_sdist/setup.py +++ b/interfaces/python_sdist/setup.py @@ -8,13 +8,14 @@ import numpy import shutil +PY_SRC = Path("cantera") CT_SRC = Path("src") EXT_SRC = Path("ext") CT_INCLUDE = Path("include") BOOST_INCLUDE = None FORCE_CYTHON_COMPILE = False -CYTHON_BUILT_FILES = [Path("cantera") / f"_cantera.{ext}" for ext in ("cpp", "h")] +CYTHON_BUILT_FILES = [pth.with_suffix(".cpp") for pth in PY_SRC.glob("*.pyx")] class CanteraOptionsMixin: @@ -22,6 +23,7 @@ class CanteraOptionsMixin: Modeled after https://stackoverflow.com/a/53833930 """ + user_options = [ ("force-cython-compile", None, "Force compilation of .pyx files via Cython"), ("boost-include", None, "Location of the Boost header files."), @@ -46,13 +48,15 @@ def run(self): class InstallCommand(CanteraOptionsMixin, install): - user_options = (getattr(install, "user_options", []) - + CanteraOptionsMixin.user_options) + user_options = ( + getattr(install, "user_options", []) + CanteraOptionsMixin.user_options + ) class DevelopCommand(CanteraOptionsMixin, develop): - user_options = (getattr(develop, "user_options", []) - + CanteraOptionsMixin.user_options) + user_options = ( + getattr(develop, "user_options", []) + CanteraOptionsMixin.user_options + ) if ( @@ -62,6 +66,7 @@ class DevelopCommand(CanteraOptionsMixin, develop): or os.environ.get("FORCE_CYTHON_COMPILE", False) ): from Cython.Build import cythonize + CYTHON_EXT = ".pyx" for p in CYTHON_BUILT_FILES: if p.exists(): @@ -69,12 +74,13 @@ class DevelopCommand(CanteraOptionsMixin, develop): else: CYTHON_EXT = ".cpp" - def cythonize(extensions): + def cythonize(extensions, **kwargs): """Define a no-op for when we're not using Cython.""" return extensions -source_files = ["cantera/_cantera" + CYTHON_EXT] -source_files += list(map(str, CT_SRC.glob("**/*.cpp"))) + +ct_sources = list(map(str, CT_SRC.glob("**/*.cpp"))) +py_sources = list(map(str, PY_SRC.glob(f"*{CYTHON_EXT}"))) sundials_sources = list(map(str, EXT_SRC.glob("sundials/**/*.c"))) yaml_cpp_sources = list(map(str, EXT_SRC.glob("yaml-cpp/**/*.cpp"))) fmt_sources = list(map(str, EXT_SRC.glob("fmt/*.cc"))) @@ -83,7 +89,8 @@ def cythonize(extensions): str(CT_INCLUDE), str(CT_INCLUDE / "cantera" / "ext"), str(CT_SRC), - numpy.get_include() + "cantera", + numpy.get_include(), ] if "BOOST_INCLUDE" in os.environ: @@ -94,8 +101,12 @@ def cythonize(extensions): def configure_build(): boost_version = "" - boost_locs = (os.environ.get("BOOST_INCLUDE", None), BOOST_INCLUDE, "/usr/include", - "/usr/local/include") + boost_locs = ( + os.environ.get("BOOST_INCLUDE", None), + BOOST_INCLUDE, + "/usr/include", + "/usr/local/include", + ) for boost_dir in boost_locs: if boost_dir is None: continue @@ -111,8 +122,6 @@ def configure_build(): boost_version = boost_lib_version.group(1) break - config_h = {} - if not boost_version: raise ValueError( "Could not find Boost headers. Please set an environment variable called " @@ -125,24 +134,22 @@ def configure_build(): f"Could not convert Boost minor version to integer: '{boost_version}'" ) from None if boost_minor_version < 61: - raise ValueError( - "Cantera requires Boost version 1.61 or newer." - ) + raise ValueError("Cantera requires Boost version 1.61 or newer.") if sys.platform != "win32": extra_compile_flags = ["-std=c++17", "-g0"] sundials_configh = { "SUNDIALS_USE_GENERIC_MATH": "#define SUNDIALS_USE_GENERIC_MATH 1", - "SUNDIALS_BLAS_LAPACK": "/* #undef SUNDIALS_BLAS_LAPACK */" + "SUNDIALS_BLAS_LAPACK": "/* #undef SUNDIALS_BLAS_LAPACK */", } sundials_cflags = ["-w"] sundials_macros = [] else: - extra_compile_flags = [] + extra_compile_flags = ["/EHsc", "/std:c++17"] sundials_macros = [("_CRT_SECURE_NO_WARNINGS", None)] sundials_configh = { "SUNDIALS_USE_GENERIC_MATH": "/* #undef SUNDIALS_USE_GENERIC_MATH */", - "SUNDIALS_BLAS_LAPACK": "/* #undef SUNDIALS_BLAS_LAPACK */" + "SUNDIALS_BLAS_LAPACK": "/* #undef SUNDIALS_BLAS_LAPACK */", } sundials_cflags = [] @@ -152,10 +159,6 @@ def configure_build(): shutil.copy2(sun_config_h, EXT_SRC / "sundials" / "sundials") shutil.copy2(sun_config_h, CT_INCLUDE / "cantera" / "ext" / "sundials") - config_h_in = Path("config.h.in").read_text() - ct_config_h = Path("include") / "cantera" / "base" / "config.h" - ct_config_h.write_text(config_h_in.format_map(config_h)) - return extra_compile_flags, sundials_cflags, sundials_macros @@ -166,31 +169,37 @@ def configure_build(): sundials_cflags = [] sundials_macros = [] -extensions = cythonize([ - Extension( - "cantera._cantera", - source_files, - include_dirs=include_dirs, - extra_compile_args=extra_compile_flags, - language="c++", - ), -]) - def lib_def(sources, cflags, include_dirs, macros): """Convenience factory to create the dictionary for a Setuptools library build.""" - return dict(sources=sources, cflags=cflags, include_dirs=include_dirs, - macros=macros) + return dict( + sources=sources, cflags=cflags, include_dirs=include_dirs, macros=macros + ) sundials_inc_dir = include_dirs + [str(EXT_SRC / "sundials" / "sundials")] libraries = [ - ("sundials", lib_def(sundials_sources, sundials_cflags, sundials_inc_dir, - sundials_macros)), + ( + "sundials", + lib_def(sundials_sources, sundials_cflags, sundials_inc_dir, sundials_macros), + ), ("yaml-cpp", lib_def(yaml_cpp_sources, extra_compile_flags, include_dirs, [])), ("fmtlib", lib_def(fmt_sources, extra_compile_flags, include_dirs, [])), ] +extensions = cythonize( + [ + Extension( + name=f"cantera._cantera", + sources=py_sources + ct_sources, + include_dirs=include_dirs, + extra_compile_args=extra_compile_flags, + language="c++", + ) + ], + compiler_directives={"binding": True, "language_level": 3}, +) + setup( ext_modules=extensions, libraries=libraries, diff --git a/test/python/utilities.py b/test/python/utilities.py index 52d8a2b09e..9682d82448 100644 --- a/test/python/utilities.py +++ b/test/python/utilities.py @@ -16,7 +16,7 @@ slow_test = unittest.skipIf(environ.get("CT_SKIP_SLOW", "0") == "1", "slow test") TEST_DATA_PATH = Path(__file__).parents[1] / "data" -CANTERA_DATA_PATH = Path(__file__).parents[2] / "data" +CANTERA_DATA_PATH = Path(cantera.__file__).parent / "data" cantera.add_directory(TEST_DATA_PATH) cantera.add_directory(CANTERA_DATA_PATH)