mirror of
https://github.com/Cantera/cantera.git
synced 2025-02-25 18:55:29 -06:00
199 lines
6.3 KiB
Python
199 lines
6.3 KiB
Python
import sys
|
|
import os
|
|
import re
|
|
from setuptools import setup, Extension
|
|
from setuptools.command.install import install
|
|
from setuptools.command.develop import develop
|
|
from pathlib import Path
|
|
import numpy
|
|
import shutil
|
|
|
|
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")]
|
|
|
|
|
|
class CanteraOptionsMixin:
|
|
"""Custom options for the install and develop commands.
|
|
|
|
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."),
|
|
]
|
|
|
|
def initialize_options(self):
|
|
super().initialize_options()
|
|
self.force_cython_compile = False
|
|
self.boost_include = None
|
|
|
|
def finalize_options(self):
|
|
if self.boost_include is not None:
|
|
if not Path(self.boost_include).is_dir():
|
|
raise TypeError(f"The path {self.boost_include!r} is not a directory.")
|
|
super().finalize_options()
|
|
|
|
def run(self):
|
|
global BOOST_INCLUDE, FORCE_CYTHON_COMPILE
|
|
BOOST_INCLUDE = self.boost_include
|
|
FORCE_CYTHON_COMPILE = self.force_cython_compile
|
|
super().run()
|
|
|
|
|
|
class InstallCommand(CanteraOptionsMixin, install):
|
|
user_options = (getattr(install, "user_options", [])
|
|
+ CanteraOptionsMixin.user_options)
|
|
|
|
|
|
class DevelopCommand(CanteraOptionsMixin, develop):
|
|
user_options = (getattr(develop, "user_options", [])
|
|
+ CanteraOptionsMixin.user_options)
|
|
|
|
|
|
if (
|
|
not all(p.exists() for p in CYTHON_BUILT_FILES)
|
|
or "sdist" in sys.argv
|
|
or FORCE_CYTHON_COMPILE
|
|
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():
|
|
p.unlink()
|
|
else:
|
|
CYTHON_EXT = ".cpp"
|
|
|
|
def cythonize(extensions):
|
|
"""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")))
|
|
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")))
|
|
|
|
include_dirs = [
|
|
str(CT_INCLUDE),
|
|
str(CT_INCLUDE / "cantera" / "ext"),
|
|
str(CT_SRC),
|
|
numpy.get_include()
|
|
]
|
|
|
|
if "BOOST_INCLUDE" in os.environ:
|
|
include_dirs.append(os.environ["BOOST_INCLUDE"])
|
|
elif BOOST_INCLUDE is not None:
|
|
include_dirs.append(BOOST_INCLUDE)
|
|
|
|
|
|
def configure_build():
|
|
boost_version = ""
|
|
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
|
|
version_hpp = Path(boost_dir) / "boost" / "version.hpp"
|
|
if not version_hpp.exists():
|
|
continue
|
|
boost_lib_version = re.search(
|
|
r'^#define.*BOOST_LIB_VERSION.*"(\d+_\d+[_\d]*?)"$',
|
|
version_hpp.read_text(),
|
|
flags=re.MULTILINE,
|
|
)
|
|
if boost_lib_version is not None:
|
|
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 "
|
|
"BOOST_INCLUDE that contains the path to the Boost headers."
|
|
)
|
|
try:
|
|
boost_minor_version = int(boost_version.split("_")[1])
|
|
except ValueError:
|
|
raise ValueError(
|
|
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."
|
|
)
|
|
|
|
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_cflags = ["-w"]
|
|
sundials_macros = []
|
|
else:
|
|
extra_compile_flags = []
|
|
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_cflags = []
|
|
|
|
sun_config_h_in = Path("sundials_config.h.in").read_text()
|
|
sun_config_h = Path("sundials_config.h")
|
|
sun_config_h.write_text(sun_config_h_in.format_map(sundials_configh))
|
|
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
|
|
|
|
|
|
if "bdist_wheel" in sys.argv:
|
|
extra_compile_flags, sundials_cflags, sundials_macros = configure_build()
|
|
else:
|
|
extra_compile_flags = []
|
|
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)
|
|
|
|
|
|
sundials_inc_dir = include_dirs + [str(EXT_SRC / "sundials" / "sundials")]
|
|
libraries = [
|
|
("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, [])),
|
|
]
|
|
|
|
setup(
|
|
ext_modules=extensions,
|
|
libraries=libraries,
|
|
cmdclass={"install": InstallCommand, "develop": DevelopCommand},
|
|
)
|