From a64f2154777e14be9e9d7d2672a260762825a183 Mon Sep 17 00:00:00 2001 From: Bryan Weber Date: Tue, 29 Mar 2022 14:27:31 -0400 Subject: [PATCH 1/8] [CI] Fix name of versioned Boost folder We are now downloading 1.78 from jfrog. This has been working up to now because the cache was available. --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7f91bfd268..23cc3c4b68 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -507,8 +507,8 @@ jobs: BOOST_ROOT=$(echo $BOOST_ROOT | sed 's/\\/\//g') mkdir -p $BOOST_ROOT curl --progress-bar --location --output $BOOST_ROOT/download.7z $BOOST_URL - 7z -o$BOOST_ROOT x $BOOST_ROOT/download.7z -y -bd boost_1_75_0/boost - mv $BOOST_ROOT/boost_1_75_0/boost $BOOST_ROOT/boost + 7z -o$BOOST_ROOT x $BOOST_ROOT/download.7z -y -bd boost_1_78_0/boost + mv $BOOST_ROOT/boost_1_78_0/boost $BOOST_ROOT/boost rm $BOOST_ROOT/download.7z shell: bash - name: Build Cantera @@ -647,8 +647,8 @@ jobs: BOOST_ROOT=$(echo $BOOST_ROOT | sed 's/\\/\//g') mkdir -p $BOOST_ROOT curl --progress-bar --location --output $BOOST_ROOT/download.7z $BOOST_URL - 7z -o$BOOST_ROOT x $BOOST_ROOT/download.7z -y -bd boost_1_75_0/boost - mv $BOOST_ROOT/boost_1_75_0/boost $BOOST_ROOT/boost + 7z -o$BOOST_ROOT x $BOOST_ROOT/download.7z -y -bd boost_1_78_0/boost + mv $BOOST_ROOT/boost_1_78_0/boost $BOOST_ROOT/boost rm $BOOST_ROOT/download.7z shell: bash - name: Build Cantera From dd716fedc6219aae3ec31ce61c8a7b03e0dcbcf5 Mon Sep 17 00:00:00 2001 From: Bryan Weber Date: Tue, 29 Mar 2022 14:29:23 -0400 Subject: [PATCH 2/8] [Cython] Allow instances of Path in write_yaml YamlWriter.to_file() calls the C++ function after stringify-ing the filename. This implicitly assumes that filename is a string. With this change, filename can be either a string or an instance of pathlib.Path. --- interfaces/cython/cantera/base.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interfaces/cython/cantera/base.pyx b/interfaces/cython/cantera/base.pyx index 0c0f03afbb..5208a5ffaa 100644 --- a/interfaces/cython/cantera/base.pyx +++ b/interfaces/cython/cantera/base.pyx @@ -417,7 +417,7 @@ cdef class _SolutionBase: Y.skip_user_defined = skip_user_defined if filename is None: return Y.to_string() - Y.to_file(filename) + Y.to_file(str(filename)) def __getitem__(self, selection): copy = self.__class__(origin=self) From 82db426417f5cd7fe558829474661978e45e483a Mon Sep 17 00:00:00 2001 From: Bryan Weber Date: Tue, 29 Mar 2022 14:30:54 -0400 Subject: [PATCH 3/8] [Cython/Test] Fix tests writing to local directory Tests that write data should do so in the test_work_path to avoid polluting the user's current working directory and to avoid permission errors if the current working directory is write-protected. --- .../cython/cantera/test/test_composite.py | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/interfaces/cython/cantera/test/test_composite.py b/interfaces/cython/cantera/test/test_composite.py index be67ae5525..fc0822bb23 100644 --- a/interfaces/cython/cantera/test/test_composite.py +++ b/interfaces/cython/cantera/test/test_composite.py @@ -122,10 +122,10 @@ class TestPickle(utilities.CanteraTest): def test_pickle_gas(self): gas = ct.Solution("h2o2.yaml", transport_model=None) gas.TPX = 500, 500000, "H2:.75,O2:.25" - with open("gas.pkl", "wb") as pkl: + with open(self.test_work_path / "gas.pkl", "wb") as pkl: pickle.dump(gas, pkl) - with open("gas.pkl", "rb") as pkl: + with open(self.test_work_path / "gas.pkl", "rb") as pkl: gas2 = pickle.load(pkl) self.assertNear(gas.T, gas2.T) self.assertNear(gas.P, gas2.P) @@ -137,10 +137,10 @@ def test_pickle_gas_with_transport(self): gas = ct.Solution("h2o2.yaml") gas.TPX = 500, 500000, "H2:.75,O2:.25" gas.transport_model = "Multi" - with open("gas.pkl", "wb") as pkl: + with open(self.test_work_path / "gas.pkl", "wb") as pkl: pickle.dump(gas, pkl) - with open("gas.pkl", "rb") as pkl: + with open(self.test_work_path / "gas.pkl", "rb") as pkl: gas2 = pickle.load(pkl) self.assertNear(gas.T, gas2.T) self.assertNear(gas.P, gas2.P) @@ -154,7 +154,7 @@ def test_pickle_interface(self): interface = ct.Interface("diamond.yaml", "diamond_100", (gas, solid)) with self.assertRaises(NotImplementedError): - with open("interface.pkl", "wb") as pkl: + with open(self.test_work_path / "interface.pkl", "wb") as pkl: pickle.dump(interface, pkl) @@ -660,8 +660,8 @@ def test_yaml_simple(self): gas.TPX = 500, ct.one_atm, 'H2: 1.0, O2: 1.0' gas.equilibrate('HP') gas.TP = 1500, ct.one_atm - gas.write_yaml('h2o2-generated.yaml') - generated = utilities.load_yaml("h2o2-generated.yaml") + gas.write_yaml(self.test_work_path / "h2o2-generated.yaml") + generated = utilities.load_yaml(self.test_work_path / "h2o2-generated.yaml") for key in ('generator', 'date', 'phases', 'species', 'reactions'): self.assertIn(key, generated) self.assertEqual(generated['phases'][0]['transport'], 'mixture-averaged') @@ -670,7 +670,7 @@ def test_yaml_simple(self): for blessed, generated in zip(gas.reactions(), generated["reactions"]): assert blessed.equation == generated["equation"] - gas2 = ct.Solution("h2o2-generated.yaml") + gas2 = ct.Solution(self.test_work_path / "h2o2-generated.yaml") self.assertArrayNear(gas.concentrations, gas2.concentrations) self.assertArrayNear(gas.partial_molar_enthalpies, gas2.partial_molar_enthalpies) @@ -684,8 +684,8 @@ def test_yaml_outunits1(self): gas.equilibrate('HP') gas.TP = 1500, ct.one_atm units = {'length': 'cm', 'quantity': 'mol', 'energy': 'cal'} - gas.write_yaml('h2o2-generated.yaml', units=units) - generated = utilities.load_yaml("h2o2-generated.yaml") + gas.write_yaml(self.test_work_path / "h2o2-generated.yaml", units=units) + generated = utilities.load_yaml(self.test_work_path / "h2o2-generated.yaml") original = utilities.load_yaml(self.cantera_data_path / "h2o2.yaml") self.assertEqual(generated['units'], units) @@ -694,7 +694,7 @@ def test_yaml_outunits1(self): self.assertNear(r1['rate-constant']['A'], r2['rate-constant']['A']) self.assertNear(r1['rate-constant']['Ea'], r2['rate-constant']['Ea']) - gas2 = ct.Solution("h2o2-generated.yaml") + gas2 = ct.Solution(self.test_work_path / "h2o2-generated.yaml") self.assertArrayNear(gas.concentrations, gas2.concentrations) self.assertArrayNear(gas.partial_molar_enthalpies, gas2.partial_molar_enthalpies) @@ -709,8 +709,8 @@ def test_yaml_outunits2(self): gas.TP = 1500, ct.one_atm units = {'length': 'cm', 'quantity': 'mol', 'energy': 'cal'} system = ct.UnitSystem(units) - gas.write_yaml('h2o2-generated.yaml', units=system) - generated = utilities.load_yaml("h2o2-generated.yaml") + gas.write_yaml(self.test_work_path / "h2o2-generated.yaml", units=system) + generated = utilities.load_yaml(self.test_work_path / "h2o2-generated.yaml") original = utilities.load_yaml(self.cantera_data_path / "h2o2.yaml") for r1, r2 in zip(original['reactions'], generated['reactions']): @@ -718,7 +718,7 @@ def test_yaml_outunits2(self): self.assertNear(r1['rate-constant']['A'], r2['rate-constant']['A']) self.assertNear(r1['rate-constant']['Ea'], r2['rate-constant']['Ea']) - gas2 = ct.Solution("h2o2-generated.yaml") + gas2 = ct.Solution(self.test_work_path / "h2o2-generated.yaml") self.assertArrayNear(gas.concentrations, gas2.concentrations) self.assertArrayNear(gas.partial_molar_enthalpies, gas2.partial_molar_enthalpies) @@ -727,14 +727,14 @@ def test_yaml_outunits2(self): self.assertArrayNear(gas.mix_diff_coeffs, gas2.mix_diff_coeffs) def check_ptcombust(self, gas, surf): - generated = utilities.load_yaml("ptcombust-generated.yaml") + generated = utilities.load_yaml(self.test_work_path / "ptcombust-generated.yaml") for key in ("phases", "species", "gas-reactions", "Pt_surf-reactions"): self.assertIn(key, generated) self.assertEqual(len(generated["gas-reactions"]), gas.n_reactions) self.assertEqual(len(generated["Pt_surf-reactions"]), surf.n_reactions) self.assertEqual(len(generated["species"]), surf.n_total_species) - surf2 = ct.Solution("ptcombust-generated.yaml", "Pt_surf") + surf2 = ct.Solution(self.test_work_path / "ptcombust-generated.yaml", "Pt_surf") self.assertArrayNear(surf.concentrations, surf2.concentrations) self.assertArrayNear(surf.partial_molar_enthalpies, surf2.partial_molar_enthalpies) @@ -746,7 +746,7 @@ def test_yaml_surface_explicit(self): surf = ct.Interface("ptcombust.yaml", "Pt_surf", [gas]) gas.TPY = 900, ct.one_atm, np.ones(gas.n_species) surf.coverages = np.ones(surf.n_species) - surf.write_yaml("ptcombust-generated.yaml") + surf.write_yaml(self.test_work_path / "ptcombust-generated.yaml") self.check_ptcombust(gas, surf) def test_yaml_surface_adjacent(self): @@ -754,15 +754,15 @@ def test_yaml_surface_adjacent(self): gas = surf.adjacent["gas"] gas.TPY = 900, ct.one_atm, np.ones(gas.n_species) surf.coverages = np.ones(surf.n_species) - surf.write_yaml("ptcombust-generated.yaml") + surf.write_yaml(self.test_work_path / "ptcombust-generated.yaml") self.check_ptcombust(gas, surf) def test_yaml_eos(self): ice = ct.Solution('water.yaml', 'ice') ice.TP = 270, 2 * ct.one_atm - ice.write_yaml('ice-generated.yaml', units={'length': 'mm', 'mass': 'g'}) + ice.write_yaml(self.test_work_path / "ice-generated.yaml", units={'length': 'mm', 'mass': 'g'}) - ice2 = ct.Solution('ice-generated.yaml') + ice2 = ct.Solution(self.test_work_path / "ice-generated.yaml") self.assertNear(ice.density, ice2.density) self.assertNear(ice.entropy_mole, ice2.entropy_mole) @@ -779,7 +779,7 @@ def test_yaml_inconsistent_species(self): h2.thermo.reference_pressure, nasa_coeffs) gas2.modify_species(gas2.species_index('H2'), h2) with self.assertRaisesRegex(ct.CanteraError, "different definitions"): - gas.write_yaml('h2o2-error.yaml', phases=gas2) + gas.write_yaml(self.test_work_path / "h2o2-error.yaml", phases=gas2) def test_yaml_user_data(self): gas = ct.Solution("h2o2.yaml") @@ -791,8 +791,8 @@ def test_yaml_user_data(self): S.thermo.update_user_data({"something": (False, True)}) gas.reaction(5).update_user_data({"baked-beans": True}) - gas.write_yaml("h2o2-generated-user-data.yaml") - gas2 = ct.Solution("h2o2-generated-user-data.yaml") + gas.write_yaml(self.test_work_path / "h2o2-generated-user-data.yaml") + gas2 = ct.Solution(self.test_work_path / "h2o2-generated-user-data.yaml") data2 = gas2.species(2).input_data self.assertEqual(gas2.input_data["spam"], extra["spam"]) From 7d751bed414ecd1df63dd3de31561c0110a81c3f Mon Sep 17 00:00:00 2001 From: Bryan Weber Date: Tue, 29 Mar 2022 14:34:31 -0400 Subject: [PATCH 4/8] [SCons] Fix config options for sdist Some configuration options conflict with creating the sdist, or else are just unnecessary. These options are checked and set to an appropriate value if they aren't specified. The build now errors if incompatible options are explicitly specified. --- SConstruct | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/SConstruct b/SConstruct index a2e5490ab3..5cd33c282e 100644 --- a/SConstruct +++ b/SConstruct @@ -851,6 +851,22 @@ if 'sphinx' in COMMAND_LINE_TARGETS: if "sdist" in COMMAND_LINE_TARGETS: env["python_sdist"] = True + if env["python_package"] == "default": + logger.info("'sdist' target was specified. Setting 'python_package' to none.") + env["python_package"] = "none" + elif env["python_package"] in ("full", "y"): + logger.error("'sdist' target was specified. Cannot also build Python package.") + sys.exit(1) + for ext_dependency in ("sundials", "fmt", "yamlcpp", "eigen"): + if env[f"system_{ext_dependency}"] == "y": + logger.error(f"'sdist' target was specified. Cannot use 'system_{ext_dependency}'.") + sys.exit(1) + else: + env[f"system_{ext_dependency}"] = "n" + + logger.info("'sdist' target was specified. Setting 'use_pch' to False.") + env["use_pch"] = False + for arg in ARGUMENTS: if arg not in config: logger.error(f"Encountered unexpected command line option: '{arg}'") From 69ca6afa28225d640a5e59c128ee8bc5e9e790b3 Mon Sep 17 00:00:00 2001 From: Bryan Weber Date: Tue, 29 Mar 2022 16:11:18 -0400 Subject: [PATCH 5/8] [sdist] Fix platform-dependent sdist The config.h file for Cantera needs to have certain values set on the platform that will build/install Cantera, not the platform building the sdist. These values are now added to the config.h.in template by setup.py. Values that are not platform dependent are still handled by SConscript when the sdist is generated. --- SConstruct | 2 +- interfaces/python_sdist/MANIFEST.in | 1 + interfaces/python_sdist/SConscript | 76 ++++++++++++++++++-- interfaces/python_sdist/setup.py | 108 ++++++++++++++++++++++------ 4 files changed, 159 insertions(+), 28 deletions(-) diff --git a/SConstruct b/SConstruct index 5cd33c282e..b53488e826 100644 --- a/SConstruct +++ b/SConstruct @@ -1995,7 +1995,7 @@ else: env["cantera_shared_libs"] = ["cantera"] + env["external_libs"] # Add targets from the SConscript files in the various subdirectories -Export('env', 'build', 'libraryTargets', 'install', 'buildSample') +Export('env', 'build', 'libraryTargets', 'install', 'buildSample', "configh") # ext needs to come before src so that libraryTargets is fully populated VariantDir('build/ext', 'ext', duplicate=0) diff --git a/interfaces/python_sdist/MANIFEST.in b/interfaces/python_sdist/MANIFEST.in index 060d90ecf3..11dc4b8e44 100644 --- a/interfaces/python_sdist/MANIFEST.in +++ b/interfaces/python_sdist/MANIFEST.in @@ -2,6 +2,7 @@ include cantera/_cantera.cpp include cantera/_cantera.h recursive-include cantera *.pyx include sundials_config.h.in +include config.h.in graft include recursive-include ext *.h recursive-include src *.h diff --git a/interfaces/python_sdist/SConscript b/interfaces/python_sdist/SConscript index 136e4f81fa..4e5b972555 100644 --- a/interfaces/python_sdist/SConscript +++ b/interfaces/python_sdist/SConscript @@ -9,7 +9,8 @@ from build.env import IsolatedEnvBuilder from buildutils import logger -Import("env") +Import("env", "configh") +configh = configh.copy() localenv = env.Clone() @@ -89,18 +90,79 @@ def replace_git_hash(target, source, env): sdist(localenv.RecursiveInstall( "src", "#src", - exclude=["fortran", "matlab", r"global\.cpp", "SCons.*"], + exclude=["fortran", "matlab", "clib", r"global\.cpp", "SCons.*"], )) sdist(localenv.Command("src/base/global.cpp", "#src/base/global.cpp", replace_git_hash)) -include_target = sdist(localenv.Command("include", "#include", - Copy("$TARGET", "$SOURCE"))) -localenv.Depends(include_target, env["config_h_target"]) -localenv.Depends(include_target, env["ext_include_copies_target"]) +# 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 + +# These keys are determined by the build machine +for key in ("SOLARIS", "DARWIN", "CT_USE_DEMANGLE"): + del configh[key] -sdist(localenv.Command("ext", "#ext", copy_ext_src)) + +class DefineDict: + 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, +)) # Use RecursiveInstall to make sure that files are not overwritten during the copy. # A normal Copy Action would fail because of the existing directories. diff --git a/interfaces/python_sdist/setup.py b/interfaces/python_sdist/setup.py index 4bd16ab71e..c41c18783b 100644 --- a/interfaces/python_sdist/setup.py +++ b/interfaces/python_sdist/setup.py @@ -1,5 +1,6 @@ import sys import os +import re from setuptools import setup, Extension from setuptools.command.install import install from setuptools.command.develop import develop @@ -92,28 +93,95 @@ def cythonize(extensions): elif BOOST_INCLUDE is not None: include_dirs.append(BOOST_INCLUDE) -if sys.platform != "win32": - extra_compile_flags = ["-std=c++11"] - sundials_configh = { - "SUNDIALS_USE_GENERIC_MATH": "#define SUNDIALS_USE_GENERIC_MATH 1", - "SUNDIALS_BLAS_LAPACK": "/* #undef SUNDIALS_BLAS_LAPACK */" - } - sundials_cflags = ["-w"] - sundials_macros = [] + +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 = {} + + def create_config(key, value): + config_h[key] = f"#define {key} {value}" + + 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 < 56: + create_config("CT_USE_DEMANGLE", 0) + else: + create_config("CT_USE_DEMANGLE", 1) + + if sys.platform == "darwin": + create_config("DARWIN", 1) + else: + create_config("DARWIN", 0) + + # I have no idea if this is the value for Solaris, and I don't have a Solaris + # machine handy to test. YOLO! + if sys.platform.startswith("sunos"): + create_config("SOLARIS", 1) + else: + create_config("SOLARIS", 0) + + if sys.platform != "win32": + extra_compile_flags = ["-std=c++11"] + 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 = (HERE / "sundials_config.h.in").read_text() + sun_config_h = HERE / "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 = (HERE / "config.h.in").read_text() + ct_config_h = HERE / "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_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 = [] - -config_h_in = (HERE / "sundials_config.h.in").read_text() -config_h = HERE / "sundials_config.h" -config_h.write_text(config_h_in.format_map(sundials_configh)) -shutil.copy2(config_h, EXT_SRC / "sundials" / "sundials") -shutil.copy2(config_h, CT_INCLUDE / "cantera" / "ext" / "sundials") + sundials_macros = [] extensions = cythonize([ Extension( @@ -138,7 +206,7 @@ def lib_def(sources, cflags, include_dirs, macros): sundials_macros)), ("yaml-cpp", lib_def(yaml_cpp_sources, extra_compile_flags, include_dirs, [])), ("fmtlib", lib_def(fmt_sources, extra_compile_flags, include_dirs, [])), - ("libexecstream", {"sources": libexecstream_sources, "include_dirs": include_dirs}) + ("libexecstream", {"sources": libexecstream_sources, "include_dirs": include_dirs}), ] setup( From b11e2cf0b3be1c4e099207dcd7f7d7676377d248 Mon Sep 17 00:00:00 2001 From: Bryan Weber Date: Tue, 29 Mar 2022 16:15:47 -0400 Subject: [PATCH 6/8] [sdist] Reduce wheel size on Linux Setuptools includes CFLAGS from when Python was built, which may include the flag to add debug symbols. This dramatically inflates the size of our wheels, so this change disables those symbols. We also exclude source files from the built wheel. _cantera.cpp ends up being ~10 MB uncompressed, so this is a signifcant savings as well. Overall, the wheel goes from ~100 MB to ~5 MB. --- interfaces/python_sdist/MANIFEST.in | 11 +++++++++-- interfaces/python_sdist/setup.cfg.in | 7 +++++++ interfaces/python_sdist/setup.py | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/interfaces/python_sdist/MANIFEST.in b/interfaces/python_sdist/MANIFEST.in index 11dc4b8e44..0c7d288f3c 100644 --- a/interfaces/python_sdist/MANIFEST.in +++ b/interfaces/python_sdist/MANIFEST.in @@ -1,11 +1,18 @@ +# The files listed here will be included in the sdist. They will also be included in +# 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 include cantera/_cantera.h recursive-include cantera *.pyx 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 +# the source of the extension. recursive-include ext *.h recursive-include src *.h -recursive-include ext/libexecstream/posix *.cpp -recursive-include ext/libexecstream/win *.cpp + +recursive-include ext/libexecstream *.cpp exclude include/cantera/ext/sundials/sundials_config.h diff --git a/interfaces/python_sdist/setup.cfg.in b/interfaces/python_sdist/setup.cfg.in index ccf42785c0..b1660ea900 100644 --- a/interfaces/python_sdist/setup.cfg.in +++ b/interfaces/python_sdist/setup.cfg.in @@ -50,12 +50,19 @@ packages = cantera.test.data cantera.examples +# These options include data in the sdist and wheel if the files are also listed in +# MANIFEST.in. Note that only files that are inside the "cantera" packages will be +# included in the wheel. [options.package_data] cantera.data = *.*, */*.* cantera.test.data = *.*, */*.* cantera.examples = */*.* cantera = *.pxd +# These options exclude data from the wheel file but not from the sdist +[options.exclude_package_data] +cantera = *.cpp, *.h, *.pyx + [options.extras_require] hdf5 = h5py pandas = pandas diff --git a/interfaces/python_sdist/setup.py b/interfaces/python_sdist/setup.py index c41c18783b..035c515f52 100644 --- a/interfaces/python_sdist/setup.py +++ b/interfaces/python_sdist/setup.py @@ -147,7 +147,7 @@ def create_config(key, value): create_config("SOLARIS", 0) if sys.platform != "win32": - extra_compile_flags = ["-std=c++11"] + extra_compile_flags = ["-std=c++11", "-g0"] sundials_configh = { "SUNDIALS_USE_GENERIC_MATH": "#define SUNDIALS_USE_GENERIC_MATH 1", "SUNDIALS_BLAS_LAPACK": "/* #undef SUNDIALS_BLAS_LAPACK */" From a56486820f09eff30378a830251ad4428a026b25 Mon Sep 17 00:00:00 2001 From: Bryan Weber Date: Wed, 30 Mar 2022 12:11:05 -0400 Subject: [PATCH 7/8] Add a docstring to DefineDict in the sdist builder --- interfaces/python_sdist/SConscript | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/interfaces/python_sdist/SConscript b/interfaces/python_sdist/SConscript index 4e5b972555..033096939a 100644 --- a/interfaces/python_sdist/SConscript +++ b/interfaces/python_sdist/SConscript @@ -138,6 +138,13 @@ for key in ("SOLARIS", "DARWIN", "CT_USE_DEMANGLE"): 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 From cfbbf0c4d7f3234c168e354e1287d5936c0a6175 Mon Sep 17 00:00:00 2001 From: Bryan Weber Date: Wed, 30 Mar 2022 12:12:46 -0400 Subject: [PATCH 8/8] [SCons] Only resolve prefix if stage_dir isn't set Eager resolution of the prefix path to an absolute directory caused the entire path to the prefix to be used under the stage_dir. As this breaks the utility of stage_dir, the resolution is conditional on stage_dir not being among the selected options. Resolves build failures of the Conda package for Matlab. --- SConstruct | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index b53488e826..0381fd96b1 100644 --- a/SConstruct +++ b/SConstruct @@ -1721,7 +1721,8 @@ if env["layout"] == "conda" and os.name == "nt": env["ct_incdir"] = pjoin(env["prefix"], "Library", "include", "cantera") env["ct_incroot"] = pjoin(env["prefix"], "Library", "include") else: - env["prefix"] = str(Path(env["prefix"]).resolve()) + if "stage_dir" not in selected_options: + env["prefix"] = str(Path(env["prefix"]).resolve()) env["ct_libdir"] = pjoin(env["prefix"], env["libdirname"]) env["ct_bindir"] = pjoin(env["prefix"], "bin") env["ct_python_bindir"] = pjoin(env["prefix"], "bin")