Compare commits
4 Commits
3b9a6eba5a
...
0759ff6d9c
| Author | SHA1 | Date | |
|---|---|---|---|
| 0759ff6d9c | |||
| 2fca1674f8 | |||
| 5502b0ac80 | |||
| 61cd7359d4 |
2
Doxyfile
2
Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = GridFire
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = v0.7.6rc4.2
|
||||
PROJECT_NUMBER = v1.0.0
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewers a
|
||||
|
||||
@@ -61,7 +61,6 @@ version_sufficient = required_min == '' ? true : compiler_version.version_compar
|
||||
|
||||
# --- failure analysis and reporting ----------------------------------------
|
||||
if toolchain_functional and not version_sufficient
|
||||
# Works in practice; don't break a functioning setup over a number.
|
||||
warning(toolchain_desc + ' is below the minimum GridFire tests against ('
|
||||
+ required_min + '), but all C++23 capability probes passed. '
|
||||
+ 'Proceeding; if you hit compiler errors deep in the build, '
|
||||
@@ -69,7 +68,6 @@ if toolchain_functional and not version_sufficient
|
||||
endif
|
||||
|
||||
if not toolchain_functional
|
||||
# 1) Name the failure precisely.
|
||||
failure_detail = ''
|
||||
if not have_print_hdr
|
||||
failure_detail += '\n * C++ standard library header <print> not found.'
|
||||
@@ -83,14 +81,11 @@ if not toolchain_functional
|
||||
if not version_sufficient
|
||||
failure_detail += '\n * ' + toolchain_desc + ' is below the required minimum (' + required_min + ').'
|
||||
elif compiler_id == 'clang' and not is_apple_clang
|
||||
# New-enough clang but probes failed: almost always the C++ stdlib
|
||||
# underneath it, not clang itself.
|
||||
failure_detail += ('\n * clang itself is new enough; on Linux clang uses the system '
|
||||
+ 'libstdc++, so the GNU C++ runtime is likely too old. Install GCC >= '
|
||||
+ gridfire_gcc_min + ' (clang will pick up its libstdc++), or use -Dcpp_args=-stdlib=libc++ with libc++ >= 17 installed.')
|
||||
endif
|
||||
|
||||
# 2) Search for a suitable already-installed alternate.
|
||||
candidate_names = []
|
||||
if compiler_id == 'gcc'
|
||||
candidate_names += ['g++-16', 'g++-15', 'g++-14', 'clang++-21', 'clang++-20', 'clang++-19', 'clang++-18', 'clang++-17']
|
||||
@@ -110,7 +105,6 @@ if not toolchain_functional
|
||||
p = find_program(cand, required: false)
|
||||
if p.found()
|
||||
cand_ver = p.version()
|
||||
# Decide the applicable minimum from the candidate's family.
|
||||
cand_min = cand.contains('clang') ? gridfire_clang_min : gridfire_gcc_min
|
||||
if cand_ver != 'unknown' and cand_ver.version_compare('>=' + cand_min)
|
||||
candidates_report += '\n [OK] ' + p.full_path() + ' (version ' + cand_ver + ')'
|
||||
@@ -123,7 +117,6 @@ if not toolchain_functional
|
||||
endif
|
||||
endforeach
|
||||
|
||||
# 3) OS-specific install guidance.
|
||||
os_help = ''
|
||||
if host_machine.system() == 'darwin'
|
||||
os_help = '''
|
||||
@@ -160,7 +153,6 @@ How to get a suitable compiler on Linux:''' + distro_hint + '''
|
||||
os_help = '\nInstall GCC >= ' + gridfire_gcc_min + ' or LLVM clang >= ' + gridfire_clang_min + ' for your platform.'
|
||||
endif
|
||||
|
||||
# 4) Assemble the verdict.
|
||||
if suitable_cxx != ''
|
||||
action = ('\nA suitable compiler IS already installed. Meson cannot switch compilers '
|
||||
+ 'after configuration starts, so re-run setup pointing at it:\n\n'
|
||||
@@ -181,18 +173,9 @@ How to get a suitable compiler on Linux:''' + distro_hint + '''
|
||||
+ action)
|
||||
endif
|
||||
|
||||
# --- everything below unchanged from the original check ---------------------
|
||||
|
||||
# For Eigen
|
||||
add_project_arguments('-Wno-deprecated-declarations', language: 'cpp')
|
||||
|
||||
if get_option('build_python')
|
||||
message('enabling hidden visibility for C++ symbols when building Python extension. This reduces the size of the resulting shared library.')
|
||||
add_project_arguments('-fvisibility=hidden', language: 'cpp')
|
||||
else
|
||||
message('enabling default visibility for C++ symbols')
|
||||
add_project_arguments('-fvisibility=default', language: 'cpp')
|
||||
endif
|
||||
add_project_arguments('-fvisibility=default', language: 'cpp')
|
||||
|
||||
if get_option('openmp_support')
|
||||
gridfire_args += ['-DGF_USE_OPENMP']
|
||||
|
||||
@@ -1,82 +1,74 @@
|
||||
fourdst_build_lib_all = true
|
||||
if not get_option('plugin_support')
|
||||
fourdst_build_lib_all=false
|
||||
message('Disabling fourdst plugin support as per user request.')
|
||||
endif
|
||||
|
||||
fourdst_default_options = [
|
||||
'build_tests=' + get_option('build_tests').to_string(),
|
||||
'build_python=' + get_option('build_python').to_string(),
|
||||
'build_lib_all=' + fourdst_build_lib_all.to_string(),
|
||||
'build_lib_comp=true',
|
||||
'build_lib_config=true',
|
||||
'build_lib_log=true',
|
||||
'build_lib_const=true',
|
||||
'pkg_config=' + get_option('pkg_config').to_string(),
|
||||
]
|
||||
|
||||
if get_option('build_python')
|
||||
fourdst_default_options += ['default_library=static']
|
||||
endif
|
||||
fourdst_inc_probe = run_command(py_installation, '-c',
|
||||
'import fourdst; print("\\n".join(fourdst.get_include_dirs()))',
|
||||
check: false)
|
||||
if fourdst_inc_probe.returncode() != 0
|
||||
error('Could not interrogate the fourdst wheel:\n' + fourdst_inc_probe.stderr()
|
||||
+ '\nIs fourdst installed in the build environment?')
|
||||
endif
|
||||
fourdst_inc_dirs = fourdst_inc_probe.stdout().strip().split('\n')
|
||||
|
||||
fourdst_sp = subproject('fourdst', default_options: fourdst_default_options)
|
||||
fourdst_lib_probe = run_command(py_installation, '-c',
|
||||
'import fourdst; print("\\n".join(fourdst.get_lib_dirs()))',
|
||||
check: false)
|
||||
if fourdst_lib_probe.returncode() != 0
|
||||
error('Could not interrogate the fourdst wheel:\n' + fourdst_lib_probe.stderr())
|
||||
endif
|
||||
fourdst_lib_dirs = fourdst_lib_probe.stdout().strip().split('\n')
|
||||
fourdst_inc_args = []
|
||||
foreach d : fourdst_inc_dirs
|
||||
fourdst_inc_args += ['-I' + d]
|
||||
endforeach
|
||||
|
||||
composition_dep = fourdst_sp.get_variable('composition_dep')
|
||||
log_dep = fourdst_sp.get_variable('log_dep')
|
||||
const_dep = fourdst_sp.get_variable('const_dep')
|
||||
config_dep = fourdst_sp.get_variable('config_dep')
|
||||
if get_option('plugin_support')
|
||||
warning('Including plugin library from fourdst. Note this will bring in minizip-ng and openssl, which can cause build issues with cross compilation due to their complexity.')
|
||||
plugin_dep = fourdst_sp.get_variable('plugin_dep')
|
||||
endif
|
||||
cpp = meson.get_compiler('cpp')
|
||||
comp_lib = cpp.find_library('composition', dirs: fourdst_lib_dirs)
|
||||
log_lib = cpp.find_library('logging', dirs: fourdst_lib_dirs)
|
||||
const_lib = cpp.find_library('const', dirs: fourdst_lib_dirs)
|
||||
refl_lib = cpp.find_library('reflect_cpp', dirs: fourdst_lib_dirs)
|
||||
|
||||
libcomposition = fourdst_sp.get_variable('libcomposition')
|
||||
libconst = fourdst_sp.get_variable('libconst')
|
||||
liblogging = fourdst_sp.get_variable('liblogging')
|
||||
composition_dep = declare_dependency(compile_args: fourdst_inc_args, dependencies: [comp_lib, refl_lib])
|
||||
log_dep = declare_dependency(compile_args: fourdst_inc_args, dependencies: log_lib)
|
||||
const_dep = declare_dependency(compile_args: fourdst_inc_args, dependencies: const_lib)
|
||||
config_dep = declare_dependency(compile_args: fourdst_inc_args) # header-only libconfig
|
||||
else
|
||||
fourdst_build_lib_all = true
|
||||
if not get_option('plugin_support')
|
||||
fourdst_build_lib_all=false
|
||||
message('Disabling fourdst plugin support as per user request.')
|
||||
endif
|
||||
|
||||
if get_option('plugin_support')
|
||||
warning('Including plugin library from fourdst. Note this will bring in minizip-ng and openssl, which can cause build issues with cross compilation due to their complexity.')
|
||||
libplugin = fourdst_sp.get_variable('libplugin')
|
||||
endif
|
||||
|
||||
if get_option('build_python')
|
||||
sp_root = meson.project_source_root() / 'subprojects'
|
||||
|
||||
fourdst_header_trees = [
|
||||
|
||||
['config',
|
||||
sp_root / 'libconfig' / 'src' / 'config' / 'include' / 'fourdst' / 'config',
|
||||
gridfire_includedir / 'fourdst'],
|
||||
['composition',
|
||||
sp_root / 'libcomposition' / 'src' / 'composition' / 'include' / 'fourdst' / 'composition',
|
||||
gridfire_includedir / 'fourdst'],
|
||||
['atomic',
|
||||
sp_root / 'libcomposition' / 'src' / 'composition' / 'include' / 'fourdst' / 'atomic',
|
||||
gridfire_includedir / 'fourdst'],
|
||||
['constants',
|
||||
sp_root / 'libconstants' / 'src' / 'constants' / 'include' / 'fourdst' / 'constants',
|
||||
gridfire_includedir / 'fourdst'],
|
||||
['logging',
|
||||
sp_root / 'liblogging' / 'src' / 'logging' / 'include' / 'fourdst' / 'logging',
|
||||
gridfire_includedir / 'fourdst'],
|
||||
['toml++',
|
||||
sp_root / 'libconfig' / 'build-config' / 'tomlpp' / 'vendor' / 'include' / 'toml++',
|
||||
gridfire_fourdst_vendor_includedir],
|
||||
['quill',
|
||||
sp_root / 'quill' / 'include' / 'quill',
|
||||
gridfire_fourdst_vendor_includedir],
|
||||
['CLI',
|
||||
sp_root / 'CLI11-2.6.1' / 'include' / 'CLI',
|
||||
gridfire_fourdst_vendor_includedir],
|
||||
fourdst_default_options = [
|
||||
'build_tests=' + get_option('build_tests').to_string(),
|
||||
'build_python=' + get_option('build_python').to_string(),
|
||||
'build_lib_all=' + fourdst_build_lib_all.to_string(),
|
||||
'build_lib_comp=true',
|
||||
'build_lib_config=true',
|
||||
'build_lib_log=true',
|
||||
'build_lib_const=true',
|
||||
'pkg_config=' + get_option('pkg_config').to_string(),
|
||||
]
|
||||
|
||||
foreach t : fourdst_header_trees
|
||||
custom_target(
|
||||
'wheel_headers_' + t[0].underscorify(),
|
||||
command: copytree_cmd + [t[1], '@OUTPUT@'],
|
||||
output: t[0],
|
||||
install: true,
|
||||
install_dir: t[2],
|
||||
)
|
||||
endforeach
|
||||
if get_option('build_python')
|
||||
fourdst_default_options += ['default_library=static']
|
||||
endif
|
||||
|
||||
fourdst_sp = subproject('fourdst', default_options: fourdst_default_options)
|
||||
|
||||
composition_dep = fourdst_sp.get_variable('composition_dep')
|
||||
log_dep = fourdst_sp.get_variable('log_dep')
|
||||
const_dep = fourdst_sp.get_variable('const_dep')
|
||||
config_dep = fourdst_sp.get_variable('config_dep')
|
||||
if get_option('plugin_support')
|
||||
warning('Including plugin library from fourdst. Note this will bring in minizip-ng and openssl, which can cause build issues with cross compilation due to their complexity.')
|
||||
plugin_dep = fourdst_sp.get_variable('plugin_dep')
|
||||
endif
|
||||
|
||||
libcomposition = fourdst_sp.get_variable('libcomposition')
|
||||
libconst = fourdst_sp.get_variable('libconst')
|
||||
liblogging = fourdst_sp.get_variable('liblogging')
|
||||
|
||||
if get_option('plugin_support')
|
||||
warning('Including plugin library from fourdst. Note this will bring in minizip-ng and openssl, which can cause build issues with cross compilation due to their complexity.')
|
||||
libplugin = fourdst_sp.get_variable('libplugin')
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -36,28 +36,16 @@ if get_option('build_python')
|
||||
]
|
||||
|
||||
|
||||
if meson.is_cross_build() and host_machine.system() == 'darwin'
|
||||
py_mod = shared_module(
|
||||
'_gridfire',
|
||||
sources: py_sources,
|
||||
dependencies: gridfire_py_deps,
|
||||
name_prefix: '',
|
||||
name_suffix: 'so',
|
||||
install: true,
|
||||
install_rpath: gridfire_ext_rpath,
|
||||
install_dir: py_installation.get_install_dir() + '/gridfire'
|
||||
)
|
||||
else
|
||||
py_mod = py_installation.extension_module(
|
||||
'_gridfire',
|
||||
sources: py_sources,
|
||||
dependencies : gridfire_py_deps,
|
||||
install : true,
|
||||
install_rpath: gridfire_ext_rpath,
|
||||
subdir: 'gridfire',
|
||||
)
|
||||
endif
|
||||
|
||||
py_mod = py_installation.extension_module(
|
||||
'_gridfire',
|
||||
sources: py_sources,
|
||||
dependencies: gridfire_py_deps,
|
||||
install: true,
|
||||
link_args: gridfire_ext_rpath_args,
|
||||
build_rpath: gridfire_ext_rpath,
|
||||
install_rpath: gridfire_ext_rpath,
|
||||
subdir: 'gridfire',
|
||||
)
|
||||
|
||||
py_installation.install_sources(
|
||||
files(
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# *********************************************************************** #
|
||||
project('GridFire', ['c', 'cpp'], version: 'v0.7.6rc4.2', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0')
|
||||
project('GridFire', ['c', 'cpp'], version: 'v1.0.0', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0')
|
||||
|
||||
gridfire_args = []
|
||||
|
||||
|
||||
@@ -13,3 +13,4 @@ option('openmp_support', type: 'boolean', value: false, description: 'Enable Ope
|
||||
option('use_mimalloc', type: 'boolean', value: true, description: 'Use mimalloc as the memory allocator for GridFire. Generally this is ~10% faster than the system allocator.')
|
||||
option('build_benchmarks', type: 'boolean', value: false, description: 'build the benchmark suite')
|
||||
option('asan', type: 'boolean', value: false, description: 'Enable AddressSanitizer (ASan) support for detecting memory errors')
|
||||
option('libomp_prefix', type: 'string', value: '', description: 'Explicit prefix of an LLVM OpenMP runtime to use instead of auto-detection (macOS wheel builds). Empty = dependency(\'openmp\') auto-detection.')
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
#!/bin/bash
|
||||
# pip_install_mac_patch.sh - Workaround for meson-python duplicate RPATH bug on macOS
|
||||
|
||||
set -e
|
||||
|
||||
# Color codes for output
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Returns 0 if the Mach-O binary at $1 has duplicate LC_RPATH entries.
|
||||
has_duplicate_rpaths() {
|
||||
local binary="$1"
|
||||
local rpaths dup
|
||||
rpaths=$(otool -l "$binary" | awk '/cmd LC_RPATH/{getline; getline; print $2}')
|
||||
dup=$(printf '%s\n' "$rpaths" | sort | uniq -d)
|
||||
[ -n "$dup" ]
|
||||
}
|
||||
|
||||
echo -e "${YELLOW}"
|
||||
echo "========================================================================="
|
||||
echo " INSTALLATION + DUPLICATE-RPATH SAFETY NET (macOS)"
|
||||
echo "========================================================================="
|
||||
echo -e "${NC}"
|
||||
echo ""
|
||||
echo "This script installs gridfire with pip and then checks the installed"
|
||||
echo "extension modules for duplicate LC_RPATH entries (a meson-python bug"
|
||||
echo "exposed by macOS 26.1, see:"
|
||||
echo " https://github.com/mesonbuild/meson-python/issues/813 )."
|
||||
echo ""
|
||||
echo "With the current self-contained wheel layout the bug should not"
|
||||
echo "trigger; binaries are only patched if duplicates are actually found."
|
||||
echo ""
|
||||
echo -e "${YELLOW}Continue? [y/N]${NC} "
|
||||
read -r response
|
||||
|
||||
if [[ ! "$response" =~ ^[Yy]$ ]]; then
|
||||
echo -e "${RED}Installation cancelled.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}Step 1: Finding current Python environment...${NC}"
|
||||
|
||||
PYTHON_BIN=$(which python3)
|
||||
if [ -z "$PYTHON_BIN" ]; then
|
||||
echo -e "${RED}Error: python3 not found in PATH${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Using Python: $PYTHON_BIN"
|
||||
PYTHON_VERSION=$($PYTHON_BIN --version)
|
||||
echo "Python version: $PYTHON_VERSION"
|
||||
|
||||
SITE_PACKAGES=$($PYTHON_BIN -c "import site; print(site.getsitepackages()[0])")
|
||||
echo "Site packages: $SITE_PACKAGES"
|
||||
echo ""
|
||||
|
||||
echo -e "${GREEN}Step 2: Installing gridfire with pip...${NC}"
|
||||
$PYTHON_BIN -m pip install . -v --no-build-isolation
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}Error: pip install failed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
FIX_SCRIPT="build-python/fix_rpaths.py"
|
||||
|
||||
check_and_fix() {
|
||||
local label="$1" so_file="$2"
|
||||
|
||||
if [ -z "$so_file" ]; then
|
||||
echo -e "${YELLOW}Skipping ${label}: extension module not found (package may not be installed).${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Found ${label} extension module: $so_file"
|
||||
if has_duplicate_rpaths "$so_file"; then
|
||||
echo -e "${YELLOW}Duplicate LC_RPATH entries detected in ${label}; applying fix...${NC}"
|
||||
if [ ! -f "$FIX_SCRIPT" ]; then
|
||||
echo -e "${RED}Error: $FIX_SCRIPT not found${NC}"
|
||||
echo "Please run this script from the project root directory."
|
||||
exit 1
|
||||
fi
|
||||
$PYTHON_BIN "$FIX_SCRIPT" "$so_file"
|
||||
else
|
||||
echo -e "${GREEN}No duplicate LC_RPATH entries in ${label}; no patch needed.${NC}"
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
echo -e "${GREEN}Step 3: Checking installed extension modules...${NC}"
|
||||
|
||||
GRIDFIRE_SO=$(find "$SITE_PACKAGES/gridfire" -name "_gridfire.cpython-*-darwin.so" 2>/dev/null | head -n 1)
|
||||
check_and_fix "gridfire" "$GRIDFIRE_SO"
|
||||
|
||||
FOURDST_SO=$(find "$SITE_PACKAGES/fourdst" -name "_phys.cpython-*-darwin.so" 2>/dev/null | head -n 1)
|
||||
check_and_fix "fourdst" "$FOURDST_SO"
|
||||
|
||||
echo -e "${GREEN}=========================================================================${NC}"
|
||||
echo -e "${GREEN} Installation Complete!${NC}"
|
||||
echo -e "${GREEN}=========================================================================${NC}"
|
||||
echo ""
|
||||
echo "Test the installation with:"
|
||||
echo " $PYTHON_BIN -c 'import gridfire; print(gridfire.__version__)'"
|
||||
echo ""
|
||||
@@ -1,14 +1,10 @@
|
||||
[build-system]
|
||||
requires = [
|
||||
"meson-python>=0.19.0",
|
||||
"meson>=1.9.1",
|
||||
"pybind11>=2.10"
|
||||
]
|
||||
requires = ["meson-python>=0.19.0", "meson>=1.9.1", "pybind11==3.0.0", "fourdst==0.10.5"]
|
||||
build-backend = "mesonpy"
|
||||
|
||||
[project]
|
||||
name = "gridfire"
|
||||
version = "v0.7.6rc4.2"
|
||||
dynamic = ["version"]
|
||||
description = "Python interface to the GridFire nuclear network code"
|
||||
readme = "README.md"
|
||||
license = { file = "LICENSE.txt" }
|
||||
@@ -21,6 +17,8 @@ maintainers = [
|
||||
{name = "Emily M. Boudreaux", email = "emily@boudreauxmail.com"}
|
||||
]
|
||||
|
||||
dependencies = ["fourdst==0.10.6"]
|
||||
|
||||
[tool.meson-python.args]
|
||||
setup = [
|
||||
'-Ddefault_library=static',
|
||||
|
||||
@@ -130,7 +130,7 @@ struct MultiscalePartitioningEngineViewScratchPad final : AbstractScratchPad {
|
||||
* @brief Check whether the scratchpad has been initialized.
|
||||
* @return true if initialized with a valid SUNContext, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool is_initialized() const override { return has_initialized; }
|
||||
[[nodiscard]] bool is_initialized() const override;
|
||||
|
||||
/**
|
||||
* @brief Initialize the scratchpad by creating a SUNDIALS context.
|
||||
@@ -150,16 +150,7 @@ struct MultiscalePartitioningEngineViewScratchPad final : AbstractScratchPad {
|
||||
* SUNContext ctx = scratch.sun_ctx;
|
||||
* @endcode
|
||||
*/
|
||||
void initialize() {
|
||||
if (has_initialized) return;
|
||||
|
||||
const int flag = SUNContext_Create(SUN_COMM_NULL, &sun_ctx);
|
||||
if (flag != 0) {
|
||||
throw std::runtime_error("Failed to create SUNContext in MultiscalePartitioningEngineViewScratchPad.");
|
||||
}
|
||||
|
||||
has_initialized = true;
|
||||
}
|
||||
void initialize();
|
||||
|
||||
/**
|
||||
* @brief Destructor that properly releases SUNDIALS resources.
|
||||
@@ -167,13 +158,7 @@ struct MultiscalePartitioningEngineViewScratchPad final : AbstractScratchPad {
|
||||
* Clears all QSE solvers before freeing the SUNContext to ensure
|
||||
* proper cleanup order and avoid dangling references.
|
||||
*/
|
||||
~MultiscalePartitioningEngineViewScratchPad() override {
|
||||
qse_solvers.clear();
|
||||
if (sun_ctx != nullptr) {
|
||||
SUNContext_Free(&sun_ctx);
|
||||
sun_ctx = nullptr;
|
||||
}
|
||||
}
|
||||
~MultiscalePartitioningEngineViewScratchPad() override;
|
||||
|
||||
/**
|
||||
* @brief Create a partial copy of this scratchpad.
|
||||
@@ -196,20 +181,7 @@ struct MultiscalePartitioningEngineViewScratchPad final : AbstractScratchPad {
|
||||
*
|
||||
* @endcode
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<AbstractScratchPad> clone() const override {
|
||||
auto clone_pad = std::make_unique<MultiscalePartitioningEngineViewScratchPad>();
|
||||
clone_pad->qse_groups = this->qse_groups;
|
||||
clone_pad->dynamic_species = this->dynamic_species;
|
||||
clone_pad->algebraic_species = this->algebraic_species;
|
||||
clone_pad->composition_cache = this->composition_cache;
|
||||
|
||||
clone_pad->initialize();
|
||||
clone_pad->qse_solvers.reserve(this->qse_solvers.size());
|
||||
for (const auto& solver : qse_solvers) {
|
||||
clone_pad->qse_solvers.push_back(solver->clone(clone_pad->sun_ctx)); // Must rebind context to new SUNContext
|
||||
}
|
||||
return clone_pad;
|
||||
}
|
||||
[[nodiscard]] std::unique_ptr<AbstractScratchPad> clone() const override;
|
||||
};
|
||||
|
||||
} // namespace gridfire::engine::scratch
|
||||
|
||||
52
src/lib/engine/scratchpads/engine_multiscale_scratchpad.cpp
Normal file
52
src/lib/engine/scratchpads/engine_multiscale_scratchpad.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "gridfire/engine/views/engine_multiscale.h"
|
||||
#include "gridfire/engine/scratchpads/scratchpad_abstract.h"
|
||||
#include "gridfire/engine/scratchpads/types.h"
|
||||
#include "gridfire/engine/scratchpads/engine_multiscale_scratchpad.h"
|
||||
|
||||
#include "fourdst/atomic/atomicSpecies.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "sundials/sundials_context.h"
|
||||
|
||||
|
||||
namespace gridfire::engine::scratch {
|
||||
bool MultiscalePartitioningEngineViewScratchPad::is_initialized() const{ return has_initialized; }
|
||||
|
||||
void MultiscalePartitioningEngineViewScratchPad::initialize() {
|
||||
if (has_initialized) return;
|
||||
|
||||
const int flag = SUNContext_Create(SUN_COMM_NULL, &sun_ctx);
|
||||
if (flag != 0) {
|
||||
throw std::runtime_error("Failed to create SUNContext in MultiscalePartitioningEngineViewScratchPad.");
|
||||
}
|
||||
|
||||
has_initialized = true;
|
||||
}
|
||||
|
||||
MultiscalePartitioningEngineViewScratchPad::~MultiscalePartitioningEngineViewScratchPad() {
|
||||
qse_solvers.clear();
|
||||
if (sun_ctx != nullptr) {
|
||||
SUNContext_Free(&sun_ctx);
|
||||
sun_ctx = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractScratchPad> MultiscalePartitioningEngineViewScratchPad::clone() const {
|
||||
auto clone_pad = std::make_unique<MultiscalePartitioningEngineViewScratchPad>();
|
||||
clone_pad->qse_groups = this->qse_groups;
|
||||
clone_pad->dynamic_species = this->dynamic_species;
|
||||
clone_pad->algebraic_species = this->algebraic_species;
|
||||
clone_pad->composition_cache = this->composition_cache;
|
||||
|
||||
clone_pad->initialize();
|
||||
clone_pad->qse_solvers.reserve(this->qse_solvers.size());
|
||||
for (const auto& solver : qse_solvers) {
|
||||
clone_pad->qse_solvers.push_back(solver->clone(clone_pad->sun_ctx)); // Must rebind context to new SUNContext
|
||||
}
|
||||
return clone_pad;
|
||||
}
|
||||
|
||||
}
|
||||
119
src/meson.build
119
src/meson.build
@@ -12,6 +12,7 @@ gridfire_sources = files(
|
||||
'lib/engine/procedures/construction.cpp',
|
||||
'lib/engine/diagnostics/dynamic_engine_diagnostics.cpp',
|
||||
'lib/engine/types/jacobian.cpp',
|
||||
'lib/engine/scratchpads/engine_multiscale_scratchpad.cpp',
|
||||
'lib/reaction/reaction.cpp',
|
||||
'lib/reaction/reaclib.cpp',
|
||||
'lib/reaction/weak/weak.cpp',
|
||||
@@ -56,7 +57,16 @@ if get_option('plugin_support')
|
||||
endif
|
||||
|
||||
if get_option('openmp_support')
|
||||
openmp_dep = dependency('openmp', required: true)
|
||||
libomp_prefix = get_option('libomp_prefix')
|
||||
if libomp_prefix != ''
|
||||
omp_lib = cpp.find_library('omp', dirs: [libomp_prefix + '/lib'])
|
||||
openmp_dep = declare_dependency(
|
||||
compile_args: ['-Xpreprocessor', '-fopenmp', '-I' + libomp_prefix + '/include'],
|
||||
dependencies: omp_lib,
|
||||
)
|
||||
else
|
||||
openmp_dep = dependency('openmp', required: true)
|
||||
endif
|
||||
gridfire_build_dependencies += [openmp_dep]
|
||||
endif
|
||||
|
||||
@@ -67,39 +77,97 @@ gridfire_link_args = cpp.get_supported_link_arguments(
|
||||
)
|
||||
|
||||
if get_option('build_python')
|
||||
gridfire_link_whole += [libcomposition, libconst, liblogging]
|
||||
if get_option('plugin_support')
|
||||
gridfire_link_whole += [libplugin]
|
||||
error('plugin_support is not available when build_python=true: '
|
||||
+ 'the fourdst wheel does not ship libplugin, and bundling it '
|
||||
+ 'would break cross-package type compatibility.')
|
||||
endif
|
||||
|
||||
# ---- rpaths ---------------------------------------------------------
|
||||
# Wheel layout (both packages share one site-packages):
|
||||
# <site-packages>/gridfire/_gridfire.<tag>.so
|
||||
# <site-packages>/gridfire/lib/libgridfire.{so,dylib}
|
||||
# <site-packages>/fourdst/lib/lib{composition,logging,const}.*
|
||||
# <site-packages>/fourdst/lib/vendor/libreflect_cpp.*
|
||||
#
|
||||
# libgridfire (in gridfire/lib/) needs: itself-dir, ../../fourdst/lib{,/vendor}
|
||||
# _gridfire (in gridfire/) needs: ./lib, ../fourdst/lib{,/vendor}
|
||||
#
|
||||
# Platform split:
|
||||
# * macOS / Mach-O: LC_RPATH cannot hold colon-separated lists,
|
||||
# meson carries a user-supplied build_rpath as a single string, and
|
||||
# install_rpath is only applied by `meson install` (which
|
||||
# meson-python never runs). So on darwin we emit one raw
|
||||
# `-Wl,-rpath,<path>` link arg per path, and deliberately do NOT
|
||||
# set build_rpath/install_rpath (a real `meson install` would then
|
||||
# add install_rpath on top of the link args, producing duplicate
|
||||
# LC_RPATH entries, which macOS 26+ dyld treats as a hard load
|
||||
# error).
|
||||
# * Linux / ELF: colon-joined DT_RUNPATH is the native format, and
|
||||
# install_rpath is baked into the binary at link time, so the
|
||||
# kwargs work for both meson-python wheels and `meson install`.
|
||||
#
|
||||
# NOTE: compose paths with '+', never the '/' join operator —
|
||||
# 'x' / '/y' silently discards 'x' in Meson.
|
||||
#
|
||||
# gridfire_ext_rpath_args / gridfire_ext_rpath are consumed later by
|
||||
# build-python/meson.build for the _gridfire extension module (this
|
||||
# subdir is processed before build-python in the root meson.build).
|
||||
if host_machine.system() == 'darwin'
|
||||
gridfire_lib_rpath_args = [
|
||||
'-Wl,-rpath,@loader_path',
|
||||
'-Wl,-rpath,@loader_path/../../fourdst/lib',
|
||||
'-Wl,-rpath,@loader_path/../../fourdst/lib/vendor',
|
||||
]
|
||||
gridfire_lib_rpath = ''
|
||||
|
||||
gridfire_ext_rpath_args = [
|
||||
'-Wl,-rpath,@loader_path/lib',
|
||||
'-Wl,-rpath,@loader_path/../fourdst/lib',
|
||||
'-Wl,-rpath,@loader_path/../fourdst/lib/vendor',
|
||||
]
|
||||
gridfire_ext_rpath = ''
|
||||
else
|
||||
gridfire_lib_rpath_args = []
|
||||
gridfire_lib_rpath = '$ORIGIN:' + '$ORIGIN/../../fourdst/lib:' + '$ORIGIN/../../fourdst/lib/vendor'
|
||||
|
||||
gridfire_ext_rpath_args = []
|
||||
gridfire_ext_rpath = '$ORIGIN/lib:' + '$ORIGIN/../fourdst/lib:' + '$ORIGIN/../fourdst/lib/vendor'
|
||||
endif
|
||||
|
||||
libgridfire = shared_library('gridfire',
|
||||
gridfire_sources,
|
||||
include_directories: include_directories('include'),
|
||||
dependencies: gridfire_build_dependencies,
|
||||
cpp_args: gridfire_args,
|
||||
link_whole: gridfire_link_whole,
|
||||
link_args: gridfire_link_args,
|
||||
install: true,
|
||||
install_dir: gridfire_libdir)
|
||||
gridfire_sources,
|
||||
include_directories: include_directories('include'),
|
||||
dependencies: gridfire_build_dependencies,
|
||||
cpp_args: gridfire_args,
|
||||
link_whole: gridfire_link_whole,
|
||||
link_args: gridfire_link_args + gridfire_lib_rpath_args,
|
||||
install: true,
|
||||
install_dir: gridfire_libdir,
|
||||
build_rpath: gridfire_lib_rpath,
|
||||
install_rpath: gridfire_lib_rpath,
|
||||
)
|
||||
else
|
||||
libgridfire = library('gridfire',
|
||||
gridfire_sources,
|
||||
include_directories: include_directories('include'),
|
||||
dependencies: gridfire_build_dependencies,
|
||||
link_whole: gridfire_link_whole,
|
||||
link_args: gridfire_link_args,
|
||||
cpp_args: gridfire_args,
|
||||
install : true)
|
||||
gridfire_sources,
|
||||
include_directories: include_directories('include'),
|
||||
dependencies: gridfire_build_dependencies,
|
||||
link_whole: gridfire_link_whole,
|
||||
link_args: gridfire_link_args,
|
||||
cpp_args: gridfire_args,
|
||||
install : true
|
||||
)
|
||||
endif
|
||||
|
||||
if get_option('build_python')
|
||||
gridfire_iface_deps = []
|
||||
foreach d : gridfire_build_dependencies
|
||||
gridfire_iface_deps += d.partial_dependency(compile_args: true, includes: true)
|
||||
endforeach
|
||||
gridfire_iface_dep = declare_dependency(
|
||||
dependencies: gridfire_build_dependencies,
|
||||
).partial_dependency(compile_args: true, includes: true)
|
||||
|
||||
gridfire_dep = declare_dependency(
|
||||
include_directories: include_directories('include'),
|
||||
link_with: libgridfire,
|
||||
dependencies: gridfire_iface_deps,
|
||||
dependencies: [gridfire_iface_dep],
|
||||
compile_args: gridfire_args,
|
||||
)
|
||||
else
|
||||
@@ -114,8 +182,8 @@ endif
|
||||
meson.override_dependency('gridfire', gridfire_dep)
|
||||
|
||||
install_subdir('include/gridfire',
|
||||
install_dir: gridfire_includedir,
|
||||
exclude_files: ['utils/config.h.in'],
|
||||
install_dir: gridfire_includedir,
|
||||
exclude_files: ['utils/config.h.in'],
|
||||
)
|
||||
|
||||
|
||||
@@ -126,4 +194,3 @@ if get_option('build_c_api')
|
||||
message('Configuring C API...')
|
||||
subdir('extern')
|
||||
endif
|
||||
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
try:
|
||||
import fourdst as fst
|
||||
except ImportError as e:
|
||||
raise ImportError(
|
||||
"gridfire requires the fourdst package (its C++ types and shared "
|
||||
"libraries come from there). pip install fourdst."
|
||||
) from e
|
||||
|
||||
from ._gridfire import *
|
||||
|
||||
from ._gridfire import *
|
||||
import sys
|
||||
|
||||
@@ -70,4 +80,49 @@ def gf_credits():
|
||||
"Emily M. Boudreaux - Lead Developer",
|
||||
"Aaron Dotter - Co-Developer",
|
||||
"4D-STAR Collaboration - Contributors"
|
||||
]
|
||||
]
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
_PACKAGE_DIR = Path(__file__).resolve().parent
|
||||
def gf_get_include_dirs():
|
||||
return [
|
||||
os.fspath(_PACKAGE_DIR / "include"),
|
||||
os.fspath(_PACKAGE_DIR / "include" / "gridfire" / "vendor"),
|
||||
]
|
||||
|
||||
def gf_get_lib_dirs():
|
||||
return [
|
||||
os.fspath(_PACKAGE_DIR / "lib"),
|
||||
]
|
||||
|
||||
def gf_get_rpath_flags() -> List[str]:
|
||||
return ["-Wl,-rpath," + os.fspath(_PACKAGE_DIR / "lib")]
|
||||
|
||||
|
||||
def gf_get_lib_flags() -> List[str]:
|
||||
flags = ["-L" + d for d in gf_get_lib_dirs()]
|
||||
flags += ["-lgridfire"]
|
||||
return flags
|
||||
|
||||
def gf_get_include_flags() -> List[str]:
|
||||
return ["-I" + d for d in gf_get_include_dirs()]
|
||||
|
||||
def gf_get_extra_flags() -> List[str]:
|
||||
return ['--std=c++23', '-fPIC']
|
||||
def gf_compiler_flags(just_gridfire=False):
|
||||
flags = []
|
||||
if not just_gridfire:
|
||||
flags.extend(fourdst_flags = fst.get_compiler_flags())
|
||||
flags.extend(gf_get_rpath_flags())
|
||||
flags.extend(gf_get_lib_flags())
|
||||
flags.extend(gf_get_include_flags())
|
||||
flags.extend(gf_get_extra_flags())
|
||||
return flags
|
||||
|
||||
def gf_get_compiler_flags_formatted(just_gridfire=False) -> int:
|
||||
flags = gf_compiler_flags(just_gridfire)
|
||||
print(" ".join(flags))
|
||||
return 0
|
||||
|
||||
@@ -17,14 +17,6 @@ namespace py = pybind11;
|
||||
void register_solver_bindings(const py::module &m) {
|
||||
auto py_cvode_timestep_context = py::class_<gridfire::solver::PointSolverTimestepContext>(m, "PointSolverTimestepContext");
|
||||
py_cvode_timestep_context.def_readonly("t", &gridfire::solver::PointSolverTimestepContext::t);
|
||||
py_cvode_timestep_context.def_property_readonly(
|
||||
"state",
|
||||
[](const gridfire::solver::PointSolverTimestepContext& self) -> std::vector<double> {
|
||||
const sunrealtype* nvec_data = N_VGetArrayPointer(self.state);
|
||||
const sunindextype length = N_VGetLength(self.state);
|
||||
return {nvec_data, nvec_data + length};
|
||||
}
|
||||
);
|
||||
py_cvode_timestep_context.def_readonly("dt", &gridfire::solver::PointSolverTimestepContext::dt);
|
||||
py_cvode_timestep_context.def_readonly("last_step_time", &gridfire::solver::PointSolverTimestepContext::last_step_time);
|
||||
py_cvode_timestep_context.def_readonly("T9", &gridfire::solver::PointSolverTimestepContext::T9);
|
||||
@@ -57,6 +49,20 @@ void register_solver_bindings(const py::module &m) {
|
||||
return self.getPhysicalComposition();
|
||||
}
|
||||
);
|
||||
py_cvode_timestep_context.def_property_readonly(
|
||||
"rawState",
|
||||
[](const gridfire::solver::PointSolverTimestepContext& self) -> std::vector<double> {
|
||||
const std::span<const double> s = self.rawState();
|
||||
return std::vector<double>(s.begin(), s.end());
|
||||
}
|
||||
);
|
||||
py_cvode_timestep_context.def("abundance",
|
||||
py::overload_cast<size_t>(&gridfire::solver::PointSolverTimestepContext::abundance, py::const_),
|
||||
py::arg("species_index"));
|
||||
py_cvode_timestep_context.def("abundance",
|
||||
py::overload_cast<const fourdst::atomic::Species&>(&gridfire::solver::PointSolverTimestepContext::abundance, py::const_),
|
||||
py::arg("species"));
|
||||
py_cvode_timestep_context.def_property_readonly("accumulatedSpecificEnergy", &gridfire::solver::PointSolverTimestepContext::accumulatedSpecificEnergy);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[wrap-git]
|
||||
url = https://github.com/4D-STAR/fourdst
|
||||
revision = v0.10.2
|
||||
revision = v0.10.6
|
||||
depth = 1
|
||||
|
||||
@@ -4,5 +4,9 @@
|
||||
#gtest_nomain_dep = dependency('gtest', main: false, required : true)
|
||||
|
||||
# Subdirectories for unit and integration tests
|
||||
subdir('graphnet_sandbox')
|
||||
subdir('extern')
|
||||
if get_option('build_tests') and not get_option('build_python')
|
||||
subdir('graphnet_sandbox')
|
||||
subdir('extern')
|
||||
else
|
||||
message('Tests disabled by build options! To enable them build with build_tests = true and build_python=false')
|
||||
endif
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <git-repo-url>"
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $0 <git-repo-url> [fourdst-wheels-dir]"
|
||||
echo " fourdst-wheels-dir: optional local directory of fourdst wheels to"
|
||||
echo " install from instead of PyPI (for bootstrapping a new fourdst+gridfire pair)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REPO_URL="$1"
|
||||
LOCAL_FOURDST_WHEELS="${2:-}"
|
||||
WORK_DIR="$(pwd)"
|
||||
WHEEL_DIR="${WORK_DIR}/wheels_linux_aarch64"
|
||||
|
||||
@@ -17,21 +20,58 @@ TMPDIR="$(mktemp -d)"
|
||||
echo "➤ Cloning ${REPO_URL} → ${TMPDIR}/project"
|
||||
git clone "${REPO_URL}" "${TMPDIR}/project"
|
||||
|
||||
DOCKER_MOUNTS=(-v "${WHEEL_DIR}":/io/wheels -v "${TMPDIR}/project":/io/project)
|
||||
if [[ -n "${LOCAL_FOURDST_WHEELS}" ]]; then
|
||||
DOCKER_MOUNTS+=(-v "${LOCAL_FOURDST_WHEELS}":/io/fourdst-wheels)
|
||||
fi
|
||||
|
||||
for IMAGE in \
|
||||
tboudreaux/manylinux_2_28_aarch64_boost_1_88_0:latest
|
||||
do
|
||||
docker run --rm \
|
||||
-v "${WHEEL_DIR}":/io/wheels \
|
||||
-v "${TMPDIR}/project":/io/project \
|
||||
"${DOCKER_MOUNTS[@]}" \
|
||||
"${IMAGE}" \
|
||||
/bin/bash -eux -c '
|
||||
cd /io/project
|
||||
|
||||
FOURDST_PIN="$(grep -oE "fourdst==[0-9][0-9a-zA-Z.]*" pyproject.toml | head -n1 || true)"
|
||||
|
||||
if [ -d /io/fourdst-wheels ]; then
|
||||
export PIP_FIND_LINKS=/io/fourdst-wheels
|
||||
fi
|
||||
|
||||
for PY in /opt/python/*/bin/python; do
|
||||
"$PY" -m pip install --upgrade pip setuptools wheel meson meson-python
|
||||
CC=clang CXX=clang++ "$PY" -m pip wheel . --config-settings=setup-args=-Dunity=on -w /io/wheels -vv
|
||||
auditwheel repair /io/wheels/*.whl -w /io/wheels
|
||||
|
||||
BUILD_WHEEL_DIR="$(mktemp -d)"
|
||||
CC=clang CXX=clang++ "$PY" -m pip wheel . \
|
||||
--no-deps --config-settings=setup-args=-Dunity=on \
|
||||
-w "$BUILD_WHEEL_DIR" -vv
|
||||
|
||||
CURRENT_WHEEL="$(find "$BUILD_WHEEL_DIR" -name "*.whl" | head -n1)"
|
||||
|
||||
if [ -n "$FOURDST_PIN" ]; then
|
||||
"$PY" -m pip install --force-reinstall "$FOURDST_PIN"
|
||||
FOURDST_LIB_PATH="$("$PY" -c "import fourdst, os; print(os.pathsep.join(fourdst.get_lib_dirs()))")"
|
||||
LD_LIBRARY_PATH="$FOURDST_LIB_PATH" auditwheel repair \
|
||||
--exclude "libcomposition.so*" \
|
||||
--exclude "liblogging.so*" \
|
||||
--exclude "libconst.so*" \
|
||||
--exclude "libreflect_cpp.so*" \
|
||||
-w /io/wheels "$CURRENT_WHEEL"
|
||||
|
||||
REPAIRED="$(ls -t /io/wheels/*.whl | head -n1)"
|
||||
if unzip -l "$REPAIRED" | grep -E "libcomposition|liblogging|libconst[^a-z]|libreflect_cpp"; then
|
||||
echo "ERROR: repaired wheel contains vendored fourdst libraries"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
auditwheel repair -w /io/wheels "$CURRENT_WHEEL"
|
||||
fi
|
||||
|
||||
rm -rf "$BUILD_WHEEL_DIR"
|
||||
done
|
||||
|
||||
echo "✅ Linux wheels ready in /io/wheels"
|
||||
echo "Linux wheels ready in /io/wheels"
|
||||
'
|
||||
done
|
||||
done
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <git-repo-url>"
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $0 <git-repo-url> [fourdst-wheels-dir]"
|
||||
echo " fourdst-wheels-dir: optional local directory of fourdst wheels to"
|
||||
echo " install from instead of PyPI (for bootstrapping a new fourdst+gridfire pair)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REPO_URL="$1"
|
||||
LOCAL_FOURDST_WHEELS="${2:-}"
|
||||
WORK_DIR="$(pwd)"
|
||||
WHEEL_DIR="${WORK_DIR}/wheels_linux_x86_64"
|
||||
|
||||
@@ -17,21 +20,58 @@ TMPDIR="$(mktemp -d)"
|
||||
echo "➤ Cloning ${REPO_URL} → ${TMPDIR}/project"
|
||||
git clone "${REPO_URL}" "${TMPDIR}/project"
|
||||
|
||||
DOCKER_MOUNTS=(-v "${WHEEL_DIR}":/io/wheels -v "${TMPDIR}/project":/io/project)
|
||||
if [[ -n "${LOCAL_FOURDST_WHEELS}" ]]; then
|
||||
DOCKER_MOUNTS+=(-v "${LOCAL_FOURDST_WHEELS}":/io/fourdst-wheels)
|
||||
fi
|
||||
|
||||
for IMAGE in \
|
||||
tboudreaux/manylinux_2_28_x86_64_boost_1_88_0:latest
|
||||
do
|
||||
docker run --rm \
|
||||
-v "${WHEEL_DIR}":/io/wheels \
|
||||
-v "${TMPDIR}/project":/io/project \
|
||||
"${DOCKER_MOUNTS[@]}" \
|
||||
"${IMAGE}" \
|
||||
/bin/bash -eux -c '
|
||||
cd /io/project
|
||||
|
||||
FOURDST_PIN="$(grep -oE "fourdst==[0-9][0-9a-zA-Z.]*" pyproject.toml | head -n1 || true)"
|
||||
|
||||
if [ -d /io/fourdst-wheels ]; then
|
||||
export PIP_FIND_LINKS=/io/fourdst-wheels
|
||||
fi
|
||||
|
||||
for PY in /opt/python/*/bin/python; do
|
||||
"$PY" -m pip install --upgrade pip setuptools wheel meson meson-python
|
||||
CC=clang CXX=clang++ "$PY" -m pip wheel . --config-settings=setup-args=-Dunity=on -w /io/wheels -vv
|
||||
auditwheel repair /io/wheels/*.whl -w /io/wheels
|
||||
|
||||
BUILD_WHEEL_DIR="$(mktemp -d)"
|
||||
CC=clang CXX=clang++ "$PY" -m pip wheel . \
|
||||
--no-deps --config-settings=setup-args=-Dunity=on \
|
||||
-w "$BUILD_WHEEL_DIR" -vv
|
||||
|
||||
CURRENT_WHEEL="$(find "$BUILD_WHEEL_DIR" -name "*.whl" | head -n1)"
|
||||
|
||||
if [ -n "$FOURDST_PIN" ]; then
|
||||
"$PY" -m pip install --force-reinstall "$FOURDST_PIN"
|
||||
FOURDST_LIB_PATH="$("$PY" -c "import fourdst, os; print(os.pathsep.join(fourdst.get_lib_dirs()))")"
|
||||
LD_LIBRARY_PATH="$FOURDST_LIB_PATH" auditwheel repair \
|
||||
--exclude "libcomposition.so*" \
|
||||
--exclude "liblogging.so*" \
|
||||
--exclude "libconst.so*" \
|
||||
--exclude "libreflect_cpp.so*" \
|
||||
-w /io/wheels "$CURRENT_WHEEL"
|
||||
|
||||
REPAIRED="$(ls -t /io/wheels/*.whl | head -n1)"
|
||||
if unzip -l "$REPAIRED" | grep -E "libcomposition|liblogging|libconst[^a-z]|libreflect_cpp"; then
|
||||
echo "ERROR: repaired wheel contains vendored fourdst libraries"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
auditwheel repair -w /io/wheels "$CURRENT_WHEEL"
|
||||
fi
|
||||
|
||||
rm -rf "$BUILD_WHEEL_DIR"
|
||||
done
|
||||
|
||||
echo "✅ Linux wheels ready in /io/wheels"
|
||||
echo "Linux wheels ready in /io/wheels"
|
||||
'
|
||||
done
|
||||
@@ -1,74 +1,158 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# 1. Validation
|
||||
if [[ $(uname -m) != "arm64" ]]; then
|
||||
echo "Error: This script is intended to run on an Apple Silicon (arm64) Mac."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <git-repo-url>"
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $0 <git-repo-url> [fourdst-wheels-dir]"
|
||||
echo " fourdst-wheels-dir: optional local directory of fourdst wheels to"
|
||||
echo " install from instead of PyPI (for bootstrapping a new fourdst+gridfire pair)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 2. Setup Directories
|
||||
for TOOL in pyenv cmake git; do
|
||||
if ! command -v "$TOOL" &> /dev/null; then
|
||||
echo "Error: ${TOOL} not found."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
REPO_URL="$1"
|
||||
LOCAL_FOURDST_WHEELS="${2:-}"
|
||||
WORK_DIR="$(pwd)"
|
||||
WHEEL_DIR="${WORK_DIR}/wheels_macos_aarch64_tmp"
|
||||
FINAL_WHEEL_DIR="${WORK_DIR}/wheels_macos_aarch64"
|
||||
RPATH_SCRIPT="${WORK_DIR}/../../build-python/fix_rpaths.py" # Assumes script is in this location relative to execution
|
||||
|
||||
echo "➤ Creating wheel output directories"
|
||||
mkdir -p "${WHEEL_DIR}"
|
||||
mkdir -p "${FINAL_WHEEL_DIR}"
|
||||
|
||||
export MACOSX_DEPLOYMENT_TARGET=15.0
|
||||
|
||||
LLVM_VER="17.0.6"
|
||||
LIBOMP_PREFIX="${WORK_DIR}/libomp-${MACOSX_DEPLOYMENT_TARGET}-${LLVM_VER}"
|
||||
|
||||
if [[ ! -f "${LIBOMP_PREFIX}/lib/libomp.dylib" ]]; then
|
||||
echo "➤ Building libomp ${LLVM_VER} for macOS ${MACOSX_DEPLOYMENT_TARGET} → ${LIBOMP_PREFIX}"
|
||||
LIBOMP_SRC_DIR="$(mktemp -d)"
|
||||
pushd "${LIBOMP_SRC_DIR}" > /dev/null
|
||||
|
||||
curl -fLO "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VER}/openmp-${LLVM_VER}.src.tar.xz"
|
||||
curl -fLO "https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VER}/cmake-${LLVM_VER}.src.tar.xz"
|
||||
tar xf "openmp-${LLVM_VER}.src.tar.xz"
|
||||
tar xf "cmake-${LLVM_VER}.src.tar.xz"
|
||||
mv "cmake-${LLVM_VER}.src" cmake
|
||||
|
||||
cmake -S "openmp-${LLVM_VER}.src" -B libomp-build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET}" \
|
||||
-DCMAKE_OSX_ARCHITECTURES=arm64 \
|
||||
-DCMAKE_INSTALL_PREFIX="${LIBOMP_PREFIX}" \
|
||||
-DLIBOMP_INSTALL_ALIASES=OFF
|
||||
cmake --build libomp-build -j "$(sysctl -n hw.ncpu)"
|
||||
cmake --install libomp-build
|
||||
|
||||
popd > /dev/null
|
||||
rm -rf "${LIBOMP_SRC_DIR}"
|
||||
fi
|
||||
|
||||
LIBOMP_MINOS="$(otool -l "${LIBOMP_PREFIX}/lib/libomp.dylib" | awk '/minos/ {print $2; exit}')"
|
||||
if [[ "${LIBOMP_MINOS}" != "${MACOSX_DEPLOYMENT_TARGET}"* ]]; then
|
||||
echo "Error: cached libomp at ${LIBOMP_PREFIX} targets macOS ${LIBOMP_MINOS}," \
|
||||
"expected ${MACOSX_DEPLOYMENT_TARGET}. Delete the directory and re-run."
|
||||
exit 1
|
||||
fi
|
||||
echo "➤ Using libomp ${LLVM_VER} (min macOS ${LIBOMP_MINOS}) from ${LIBOMP_PREFIX}"
|
||||
|
||||
export CPPFLAGS="-I${LIBOMP_PREFIX}/include ${CPPFLAGS:-}"
|
||||
export LDFLAGS="-L${LIBOMP_PREFIX}/lib ${LDFLAGS:-}"
|
||||
export LIBRARY_PATH="${LIBOMP_PREFIX}/lib${LIBRARY_PATH:+:${LIBRARY_PATH}}"
|
||||
|
||||
TMPDIR="$(mktemp -d)"
|
||||
echo "➤ Cloning ${REPO_URL} → ${TMPDIR}/project"
|
||||
git clone --depth 1 "${REPO_URL}" "${TMPDIR}/project"
|
||||
cd "${TMPDIR}/project"
|
||||
|
||||
# 3. Build Configuration
|
||||
export MACOSX_DEPLOYMENT_TARGET=15.0
|
||||
|
||||
PYTHON_VERSIONS=("3.9.23" "3.10.18" "3.11.13" "3.12.11" "3.13.5" "3.13.5t" "3.14.0rc1" "3.14.0rc1t" 'pypy3.10-7.3.19' "pypy3.11-7.3.20")
|
||||
|
||||
if ! command -v pyenv &> /dev/null; then
|
||||
echo "Error: pyenv not found. Please install it to manage Python versions."
|
||||
exit 1
|
||||
FOURDST_PIN="$(grep -oE 'fourdst==[0-9][0-9a-zA-Z.]*' pyproject.toml | head -n1 || true)"
|
||||
if [[ -n "${FOURDST_PIN}" ]]; then
|
||||
echo "➤ Project depends on ${FOURDST_PIN}; wheel repair will exclude fourdst libraries"
|
||||
fi
|
||||
|
||||
PYTHON_VERSIONS=("3.9.23" "3.10.18" "3.11.13" "3.12.11" "3.13.5" "3.14.0rc1" "3.14.0rc1t")
|
||||
|
||||
eval "$(pyenv init -)"
|
||||
|
||||
# 4. Build Loop
|
||||
for PY_VERSION in "${PYTHON_VERSIONS[@]}"; do
|
||||
(
|
||||
set -e
|
||||
|
||||
pyenv shell "${PY_VERSION}"
|
||||
PY="$(pyenv which python)"
|
||||
|
||||
|
||||
echo "----------------------------------------------------------------"
|
||||
echo "➤ Building for $($PY --version) on macOS arm64"
|
||||
echo "----------------------------------------------------------------"
|
||||
|
||||
# Install build deps explicitly so we can skip build isolation
|
||||
"$PY" -m pip install --upgrade pip setuptools wheel meson-python delocate
|
||||
"$PY" -m pip install meson==1.9.1
|
||||
|
||||
if [[ -n "${FOURDST_PIN}" ]]; then
|
||||
if [[ -n "${LOCAL_FOURDST_WHEELS}" ]]; then
|
||||
"$PY" -m pip install --force-reinstall \
|
||||
--find-links "${LOCAL_FOURDST_WHEELS}" "${FOURDST_PIN}"
|
||||
else
|
||||
"$PY" -m pip install --force-reinstall "${FOURDST_PIN}"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "➤ Building wheel with ccache enabled"
|
||||
echo "➤ Found meson version $(meson --version)"
|
||||
|
||||
# for every single build, saving significant I/O and network time.
|
||||
CC="ccache clang" CXX="ccache clang++" "$PY" -m pip wheel . --no-build-isolation -w "${WHEEL_DIR}" -v
|
||||
|
||||
# We expect exactly one new wheel in the tmp dir per iteration
|
||||
CC="ccache clang" CXX="ccache clang++" \
|
||||
"$PY" -m pip wheel . --no-deps --no-build-isolation \
|
||||
--config-settings=setup-args="-Dlibomp_prefix=${LIBOMP_PREFIX}" \
|
||||
-w "${WHEEL_DIR}" -v
|
||||
CURRENT_WHEEL=$(find "${WHEEL_DIR}" -name "*.whl" | head -n 1)
|
||||
|
||||
echo "➤ Repairing wheel with delocate"
|
||||
# Delocate moves the repaired wheel to FINAL_WHEEL_DIR
|
||||
delocate-wheel -w "${FINAL_WHEEL_DIR}" "$CURRENT_WHEEL"
|
||||
DELOCATE_DYLD_PATH="${LIBOMP_PREFIX}/lib"
|
||||
if [[ -n "${FOURDST_PIN}" ]]; then
|
||||
FOURDST_LIB_PATH="$("$PY" -c 'import fourdst, os; print(os.pathsep.join(fourdst.get_lib_dirs()))')"
|
||||
DELOCATE_DYLD_PATH="${FOURDST_LIB_PATH}:${DELOCATE_DYLD_PATH}"
|
||||
DYLD_LIBRARY_PATH="${DELOCATE_DYLD_PATH}" \
|
||||
delocate-wheel --require-archs arm64 \
|
||||
-e composition -e logging -e const -e reflect_cpp \
|
||||
-w "${FINAL_WHEEL_DIR}" -v "$CURRENT_WHEEL"
|
||||
else
|
||||
DYLD_LIBRARY_PATH="${DELOCATE_DYLD_PATH}" \
|
||||
delocate-wheel --require-archs arm64 \
|
||||
-w "${FINAL_WHEEL_DIR}" -v "$CURRENT_WHEEL"
|
||||
fi
|
||||
|
||||
REPAIRED_WHEEL="${FINAL_WHEEL_DIR}/$(basename "$CURRENT_WHEEL")"
|
||||
|
||||
if [[ -n "${FOURDST_PIN}" ]]; then
|
||||
if unzip -l "${REPAIRED_WHEEL}" | grep -E 'libcomposition|liblogging|libconst|libreflect_cpp'; then
|
||||
echo "ERROR: repaired wheel contains vendored fourdst libraries"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if unzip -l "${REPAIRED_WHEEL}" | grep -q 'libomp.dylib'; then
|
||||
CHECK_DIR="$(mktemp -d)"
|
||||
unzip -q "${REPAIRED_WHEEL}" '*/libomp.dylib' -d "${CHECK_DIR}" || true
|
||||
BUNDLED_OMP="$(find "${CHECK_DIR}" -name 'libomp.dylib' | head -n1)"
|
||||
BUNDLED_MINOS="$(otool -l "${BUNDLED_OMP}" | awk '/minos/ {print $2; exit}')"
|
||||
rm -rf "${CHECK_DIR}"
|
||||
if [[ "${BUNDLED_MINOS}" != "${MACOSX_DEPLOYMENT_TARGET}"* ]]; then
|
||||
echo "ERROR: bundled libomp targets macOS ${BUNDLED_MINOS}, expected ${MACOSX_DEPLOYMENT_TARGET}"
|
||||
exit 1
|
||||
fi
|
||||
echo "➤ Bundled libomp targets macOS ${BUNDLED_MINOS} ✓"
|
||||
fi
|
||||
|
||||
# Clean up the intermediate wheel from this iteration so it doesn't confuse the next
|
||||
rm "$CURRENT_WHEEL"
|
||||
)
|
||||
done
|
||||
@@ -77,4 +161,4 @@ done
|
||||
rm -rf "${TMPDIR}"
|
||||
rm -rf "${WHEEL_DIR}"
|
||||
|
||||
echo "✅ All builds complete. Artifacts in ${FINAL_WHEEL_DIR}"
|
||||
echo "✅ All builds complete. Artifacts in ${FINAL_WHEEL_DIR}"
|
||||
Reference in New Issue
Block a user