mirror of
https://github.com/Cantera/cantera.git
synced 2025-02-25 18:55:29 -06:00
218 lines
7.5 KiB
Python
218 lines
7.5 KiB
Python
"""SDist of the Python Module"""
|
|
from pathlib import Path
|
|
import re
|
|
import shutil
|
|
from textwrap import dedent
|
|
|
|
from build import ProjectBuilder
|
|
from build.env import IsolatedEnvBuilder
|
|
|
|
from buildutils import logger
|
|
|
|
Import("env", "configh")
|
|
configh = configh.copy()
|
|
|
|
localenv = env.Clone()
|
|
|
|
sdist_targets = []
|
|
|
|
|
|
def sdist(targets):
|
|
sdist_targets.extend(targets)
|
|
return targets
|
|
|
|
|
|
def copy_ext_src(target, source, env):
|
|
target_ext = Path(target[0].abspath)
|
|
source_ext = Path(source[0].abspath)
|
|
if target_ext.is_dir():
|
|
shutil.rmtree(target_ext)
|
|
|
|
error_message = ("Please run 'git submodule update --init --recursive' to clone "
|
|
"these files.")
|
|
|
|
# fmt library
|
|
FMT_ROOT = target_ext / "fmt"
|
|
FMT_ROOT.mkdir(parents=True) # Needed to be able to use copy2
|
|
FMT_SOURCE = source_ext / "fmt"
|
|
if not FMT_SOURCE.is_dir():
|
|
raise ValueError("Missing fmt submodule. " + error_message)
|
|
for cc_file in (FMT_SOURCE / "src").glob("*.cc"):
|
|
shutil.copy2(cc_file, FMT_ROOT)
|
|
shutil.copytree(FMT_SOURCE / "include" / "fmt", FMT_ROOT / "fmt")
|
|
|
|
# yaml-cpp library
|
|
YAML_ROOT = target_ext / "yaml-cpp"
|
|
YAML_SOURCE = source_ext / "yaml-cpp"
|
|
if not YAML_SOURCE.is_dir():
|
|
raise ValueError("Missing yaml-cpp submodule. " + error_message)
|
|
shutil.copytree(YAML_SOURCE / "src", YAML_ROOT)
|
|
shutil.copytree(YAML_SOURCE / "include" / "yaml-cpp", YAML_ROOT / "yaml-cpp")
|
|
|
|
# SUNDIALS library
|
|
SUNDIALS_ROOT = target_ext / "sundials"
|
|
SUNDIALS_SOURCE = source_ext / "sundials"
|
|
if not SUNDIALS_SOURCE.is_dir():
|
|
raise ValueError("Missing sundials submodule. " + error_message)
|
|
subdirs = ["sundials", "nvector/serial", "cvodes", "ida", "sunmatrix/band",
|
|
"sunmatrix/dense", "sunmatrix/sparse", "sunlinsol/dense",
|
|
"sunlinsol/band", "sunlinsol/spgmr", "sunnonlinsol/newton"]
|
|
ignores = shutil.ignore_patterns("fsun*", "CMake*", "fmod", "fcmix")
|
|
for subdir in subdirs:
|
|
shutil.copytree(
|
|
SUNDIALS_SOURCE / "src" / subdir,
|
|
SUNDIALS_ROOT / subdir,
|
|
ignore=ignores,
|
|
)
|
|
|
|
|
|
def replace_git_hash(target, source, env):
|
|
# Avoid having to set a C preprocessor define at compile time, since
|
|
# the git commit is unknown from the sdist
|
|
target = Path(target[0].abspath)
|
|
source = Path(source[0].abspath)
|
|
git_commit_replaced = re.sub("#ifdef GIT_COMMIT.*?#endif",
|
|
f""" return "{env['git_commit']}";""",
|
|
source.read_text(),
|
|
flags=re.DOTALL)
|
|
target.write_text(git_commit_replaced)
|
|
|
|
|
|
# Use RecursiveInstall to be able to exclude files and folders.
|
|
sdist(localenv.RecursiveInstall(
|
|
"src",
|
|
"#src",
|
|
exclude=["fortran", "matlab", "clib", r"global\.cpp", "SCons.*"],
|
|
))
|
|
|
|
sdist(localenv.Command("src/base/global.cpp", "#src/base/global.cpp",
|
|
replace_git_hash))
|
|
|
|
# This is the only bit of the clib that we need for the Python interface
|
|
clib_defs_target = sdist(localenv.Command(
|
|
"include/cantera/clib/clib_defs.h",
|
|
"#include/cantera/clib/clib_defs.h",
|
|
Copy("$TARGET", "$SOURCE")
|
|
))
|
|
|
|
# The clib is handled by clib_defs_target. The include/cantera/ext folder is handled by
|
|
# ext_include_target. config.h needs to be filled on the user's machine by setup.py and
|
|
# the template file is handled by config_h_in_target.
|
|
include_target = sdist(localenv.RecursiveInstall(
|
|
"include",
|
|
"#include",
|
|
exclude=[
|
|
"clib$",
|
|
"ext$",
|
|
r"config\.h\.in",
|
|
r"config\.h",
|
|
],
|
|
))
|
|
localenv.Depends(clib_defs_target, include_target)
|
|
|
|
ext_include_target = sdist(localenv.Command(
|
|
"include/cantera/ext",
|
|
"#include/cantera/ext",
|
|
Copy("$TARGET", "$SOURCE"),
|
|
))
|
|
localenv.Depends(ext_include_target, env["ext_include_copies_target"])
|
|
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",
|
|
))
|
|
# Use RecursiveInstall to make sure that files are not overwritten during the copy.
|
|
# A normal Copy Action would fail because of the existing directories.
|
|
sdist(localenv.RecursiveInstall("cantera",
|
|
"#interfaces/cython/cantera",
|
|
exclude=["__pycache__"]))
|
|
sdist(localenv.RecursiveInstall("cantera/data",
|
|
"#build/data"))
|
|
|
|
# Copy the minimal Sundials configuration template into the sdist so that
|
|
# it can be filled in at compile time on the user's machine
|
|
sdist(localenv.Command("sundials_config.h.in", "#ext/sundials_config.h.in",
|
|
Copy("$TARGET", "$SOURCE")))
|
|
|
|
license = sdist(localenv.Command("LICENSE.txt", "#build/ext/LICENSE.txt",
|
|
Copy("$TARGET", "$SOURCE")))
|
|
localenv.Depends(license, localenv["license_target"])
|
|
|
|
sdist(localenv.SubstFile("setup.cfg", "setup.cfg.in"))
|
|
sdist(localenv.Command("README.rst", "#README.rst", Copy("$TARGET", "$SOURCE")))
|
|
|
|
|
|
def build_sdist(target, source, env):
|
|
build_dir = Path(source[0].abspath).parent
|
|
builder = ProjectBuilder(str(build_dir))
|
|
with IsolatedEnvBuilder() as build_env:
|
|
builder.python_executable = build_env.executable
|
|
builder.scripts_dir = build_env.scripts_dir
|
|
# first install the build dependencies
|
|
build_env.install(builder.build_system_requires)
|
|
# then get the extra required dependencies from the backend
|
|
build_env.install(builder.get_requires_for_build("sdist"))
|
|
builder.build("sdist", str(build_dir / "dist"), {})
|
|
|
|
|
|
def finish_sdist_message(target, source, env):
|
|
sdist = Path(source[0].path).name
|
|
message = dedent(f"""
|
|
*******************************************************
|
|
Python sdist '{sdist}' created successfully.
|
|
The sdist file is in the 'build/python_sdist/dist'
|
|
directory.
|
|
*******************************************************
|
|
""")
|
|
logger.info(message, print_level=False)
|
|
|
|
|
|
sdist_target = f"dist/Cantera-{env['cantera_version']}.tar.gz"
|
|
sdist_sources = ("setup.py", "pyproject.toml", "MANIFEST.in")
|
|
built_sdist = localenv.Command(sdist_target, sdist_sources, build_sdist)
|
|
finish_sdist = localenv.Command("finish_sdist", sdist_target, finish_sdist_message)
|
|
localenv.Depends(built_sdist, sdist_targets)
|
|
env.Alias("sdist", finish_sdist)
|