Compare commits

..

11 Commits

Author SHA1 Message Date
ef840c07ea fix(pybind): pinned pybind to 3.0.0 for ABI compatibility 2026-06-12 14:00:40 -04:00
790e50d5c0 fix(libcomposition): atomic header install location fixed
updated to the version of libcomposition which fixes the atomic header installation directory
2026-06-12 10:53:13 -04:00
405c68bdf6 build(wheel): added auto wheel building scripts 2026-06-11 14:29:27 -04:00
1540d2c4b8 fix(python): fully working and portable python build 2026-06-11 13:58:17 -04:00
0e4cdcd278 docs(version): v0.10.2 -> v0.10.3
this version brings more python bindings for standard solar composition work as well as a few typo corrections and correctness fixes
2026-06-11 07:43:13 -04:00
25b8495a2c feat(libcomposition): python bindings for standard solar compositions 2026-06-11 07:42:17 -04:00
e1f26598ba fix(rpath): updated all versions to versions which include correct rpath injection 2026-06-10 15:11:39 -04:00
821ae91438 fix(libcomposition): utils header path fix
version v0.10.0 -> v0.10.1 (libcomposition v2.4.0 -> v2.4.1)
2026-06-10 14:19:08 -04:00
9890e100e3 docs(version): v0.9.22 -> v0.10.0
standardized install location and solar compositions
2026-06-08 09:33:42 -04:00
18873ab714 fix(libconfig): fixed CLI11 case issue
This version brings libconfig v2.2.3 which resolves a case issue with the CLI11 dependency
2026-06-05 09:11:21 +02:00
ad26aa0a7c fix(composition.utils): properly registered utils as module
previouly utils was not being registered as a module properly in python. This has been resolved so standard imports will work for fourdst.composition.utils
2026-04-11 08:39:31 -04:00
23 changed files with 489 additions and 35 deletions

2
.gitignore vendored
View File

@@ -110,3 +110,5 @@ output/
scratch/
node_modules/
*.whl

View File

@@ -2,7 +2,8 @@ composition_p = subproject('libcomposition',
default_options: [
'pkg_config=' + get_option('pkg_config').to_string(),
'build_tests=' + get_option('build_tests').to_string(),
'build_examples=false'
'build_examples=false',
'build_python=' + get_option('build_python').to_string()
])
comp_dep = composition_p.get_variable('composition_dep')
libcomposition = composition_p.get_variable('libcomposition')

View File

@@ -2,6 +2,7 @@ config_p = subproject('libconfig',
default_options:[
'pkg_config=' + get_option('pkg_config').to_string(),
'build_tests=' + get_option('build_tests').to_string(),
'build_examples=false'
])
'build_examples=false',
'build_python=' + get_option('build_python').to_string()
])
config_dep = config_p.get_variable('config_dep')

View File

@@ -1,8 +1,9 @@
const_p = subproject('libconstants', default_options: [
'pkg_config=' + get_option('pkg_config').to_string(),
'build_tests=' + get_option('build_tests').to_string(),
'build_examples=false'
])
'build_examples=false',
'build_python=' + get_option('build_python').to_string()
])
const_dep = const_p.get_variable('const_dep')
libconst = const_p.get_variable('libconst')

View File

@@ -1,7 +1,8 @@
logging_p = subproject('liblogging', default_options: [
'pkg_config=' + get_option('pkg_config').to_string(),
'build_tests=' + get_option('build_tests').to_string(),
'build_examples=false'
'build_examples=false',
'build_python=' + get_option('build_python').to_string()
])
liblogging = logging_p.get_variable('liblogging')

View File

@@ -1,16 +1,16 @@
if get_option('build_lib_comp') or get_option('build_lib_all') or get_option('build_python')
subdir('libcomposition')
endif
if get_option('build_lib_config') or get_option('build_lib_all') or get_option('build_python')
subdir('libconfig')
endif
if get_option('build_lib_const') or get_option('build_lib_all') or get_option('build_python')
subdir('libconstants')
endif
if get_option('build_lib_log') or get_option('build_lib_all')
if get_option('build_lib_log') or get_option('build_lib_all') or get_option('build_python')
subdir('liblogging')
endif
if get_option('build_lib_plugin') or get_option('build_lib_all')
if get_option('build_lib_comp') or get_option('build_lib_all') or get_option('build_python')
subdir('libcomposition')
endif
if get_option('build_lib_plugin') or get_option('build_lib_all') and not get_option('build_python')
subdir('libplugin')
endif

View File

@@ -1,5 +1,10 @@
py_installation = import('python').find_installation('python3', pure: false)
if host_machine.system() == 'darwin'
fourdst_ext_rpath = '@loader_path/lib'
else
fourdst_ext_rpath = '$ORIGIN/lib'
endif
py_mod = py_installation.extension_module(
'_phys',
sources: [
@@ -16,6 +21,8 @@ py_mod = py_installation.extension_module(
],
cpp_args : ['-UNDEBUG'],
install : true,
build_rpath: fourdst_ext_rpath,
install_rpath: fourdst_ext_rpath,
subdir: 'fourdst',
)

View File

@@ -1,8 +1,15 @@
project('fourdst', 'cpp', version: 'v0.9.20', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0')
project('fourdst', 'cpp', version: 'v0.10.6', default_options: ['cpp_std=c++23'], meson_version: '>=1.5.0')
add_project_arguments('-fvisibility=default', language: 'cpp')
if get_option('build_python')
py_installation = import('python').find_installation('python3', pure: false)
fourdst_wheel_libdir = 'fourdst/lib' # relative to the python platlib
fourdst_wheel_headerdir = 'fourdst/include'
else
fourdst_wheel_libdir = ''
fourdst_wheel_headerdir = ''
endif
# Configure vendor libraries
subdir('build-config')

View File

@@ -1,14 +1,10 @@
[build-system]
requires = [
"meson-python>=0.15.0", # Use a recent version
"meson>=1.6.0", # Specify your Meson version requirement
"pybind11>=2.10" # pybind11 headers needed at build time
]
requires = ["meson-python>=0.19,<0.20", "meson>=1.9.1,<1.10", "pybind11==3.0.0"]
build-backend = "mesonpy"
[project]
name = "fourdst" # Choose your Python package name
version = "v0.9.11" # Your project's version
dynamic = ["version"]
description = "Python interface to the utility fourdst modules from the 4D-STAR project"
readme = "readme.md"
license = { file = "LICENSE.txt" } # Reference your license file [cite: 2]
@@ -33,6 +29,12 @@ dependencies = [
[project.scripts]
fourdst-cli = "fourdst.cli.main:app"
fourdst-compiler-flags = "fourdst:get_compiler_flags_formatted"
fourdst-include-dirs = "fourdst:get_include_dirs"
fourdst-lib-dirs = "fourdst:get_lib_dirs"
fourdst-rpath-flags = "fourdst:get_rpath_flags"
fourdst-version = "fourdst:print_fourdst_version"
fourdst-extra-flags = "fourdst:get_extra_flags"
[tool.meson-python.args]
setup = [

View File

@@ -3,6 +3,7 @@
#include <pybind11/stl_bind.h> // Needed for binding std::vector, std::map etc. if needed directly
#include <string>
#include <ranges>
#include "fourdst/composition/composition.h"
#include "fourdst/atomic/atomicSpecies.h"
@@ -10,9 +11,10 @@
#include "bindings.h"
#include "fourdst/atomic/species.h"
#include "fourdst/composition/utils.h"
#include "fourdst/composition/utils/utils.h"
#include "fourdst/composition/utils/composition_hash.h"
#include "fourdst/composition/exceptions/exceptions_composition.h"
#include "fourdst/composition/io/standard_compositions.h"
namespace py = pybind11;
@@ -326,7 +328,127 @@ void register_comp_bindings(pybind11::module &m) {
"Build a Composition object from a map of species to mass fractions."
);
auto io = m.def_submodule("io", "IO library for standard solar compositions");
py::class_<fourdst::composition::io::CompositionData> (io, "CompositionData")
.def(py::init<>())
.def_readwrite("comment_str", &fourdst::composition::io::CompositionData::comment_str)
.def_readwrite("he_abundance", &fourdst::composition::io::CompositionData::he_abundance)
.def_readwrite("requires_atomic_weight", &fourdst::composition::io::CompositionData::requires_atomic_weight)
.def_property("elements",
[](fourdst::composition::io::CompositionData &self) -> const std::vector<std::string>& {
return self.elements;
},
[](fourdst::composition::io::CompositionData &self, const std::vector<std::string> &value) {
self.elements = value;
},
py::return_value_policy::reference_internal
)
.def_property("abundances",
[](fourdst::composition::io::CompositionData &self) -> const std::vector<double>& {
return self.abundances;
},
[](fourdst::composition::io::CompositionData &self, const std::vector<double> &value) {
self.abundances = value;
},
py::return_value_policy::reference_internal
);
py::class_<fourdst::composition::io::IsotopicPercentage>(io, "IsotopicPercentage")
.def(py::init<>())
.def_readwrite("comment_str", &fourdst::composition::io::IsotopicPercentage::comment_str)
.def_property("atomic_numbers",
[](fourdst::composition::io::IsotopicPercentage &self) -> const std::vector<int>& {
return self.atomic_numbers;
},
[](fourdst::composition::io::IsotopicPercentage &self, const std::vector<int> &value) {
self.atomic_numbers = value;
},
py::return_value_policy::reference_internal
)
.def_property("elements",
[](fourdst::composition::io::IsotopicPercentage &self) -> const std::vector<std::string>& {
return self.elements;
},
[](fourdst::composition::io::IsotopicPercentage &self, const std::vector<std::string> &value) {
self.elements = value;
},
py::return_value_policy::reference_internal
)
.def_property("mass_numbers",
[](fourdst::composition::io::IsotopicPercentage &self) -> const std::vector<int>& {
return self.mass_numbers;
},
[](fourdst::composition::io::IsotopicPercentage &self, const std::vector<int> &value) {
self.mass_numbers = value;
},
py::return_value_policy::reference_internal
)
.def_property("percentages",
[](fourdst::composition::io::IsotopicPercentage &self) -> const std::vector<double>& {
return self.percentages;
},
[](fourdst::composition::io::IsotopicPercentage &self, const std::vector<double> &value) {
self.percentages = value;
},
py::return_value_policy::reference_internal
);
py::enum_<fourdst::composition::io::SolarCompositions>(io,"SolarCompositions")
.value("AG89", fourdst::composition::io::SolarCompositions::AG89)
.value("GN93", fourdst::composition::io::SolarCompositions::GN93)
.value("GS98", fourdst::composition::io::SolarCompositions::GS98)
.value("L03", fourdst::composition::io::SolarCompositions::L03)
.value("AGS05", fourdst::composition::io::SolarCompositions::AGS05)
.value("AGSS09", fourdst::composition::io::SolarCompositions::AGSS09)
.value("A09_Przybilla", fourdst::composition::io::SolarCompositions::A09_Przybilla)
.value("MB22_photospheric", fourdst::composition::io::SolarCompositions::MB22_photospheric)
.value("AAG21_photospheric", fourdst::composition::io::SolarCompositions::AAG21_photospheric)
.value("L09", fourdst::composition::io::SolarCompositions::L09)
.export_values();
py::enum_<fourdst::composition::io::IsotopicPercentages>(io,"IsotopicPercentages")
.value("L03", fourdst::composition::io::IsotopicPercentages::L03)
.value("L09", fourdst::composition::io::IsotopicPercentages::L09);
io.attr("SolarCompositions_to_string_map") = fourdst::composition::io::SolarCompositions_to_string_map;
io.attr("IsotopicPercentages_to_string_map") = fourdst::composition::io::IsotopicPercentages_to_string_map;
io.def("get_raw_standard_solar_composition_data",
[]() -> std::vector<unsigned char> {
std::span<const unsigned char> raw = fourdst::composition::io::get_raw_standard_solar_composition_data();
return std::ranges::to<std::vector<unsigned char>>(raw);
}
);
py::class_<fourdst::composition::io::ChemicalFileParser>(io,"ChemicalFileParser")
.def(py::init<>())
.def_static("parse_composition_data",
&fourdst::composition::io::ChemicalFileParser::parse_composition_data,
py::arg("data"),
py::arg("scheme")
)
.def_static("parse_isotopic_percentage",
&fourdst::composition::io::ChemicalFileParser::parse_isotopic_percentage,
py::arg("data"),
py::arg("scheme")
);
m.def("get_composition_record",
py::overload_cast<const std::string&, const std::string&, double, double>(&fourdst::composition::get_composition_record),
py::arg("metal_fraction_scheme"),
py::arg("isotopic_percentage_scheme"),
py::arg("initial_z"),
py::arg("initial_y")
);
m.def("get_composition_record",
py::overload_cast<fourdst::composition::io::SolarCompositions, fourdst::composition::io::IsotopicPercentages, double, double>(&fourdst::composition::get_composition_record),
py::arg("metal_fraction_scheme"),
py::arg("isotopic_percentage_scheme"),
py::arg("initial_z"),
py::arg("initial_y")
);
}
void register_species_bindings(pybind11::module &chem_submodule) {

View File

@@ -3,12 +3,66 @@ from __future__ import annotations
import sys
from ._phys import atomic, composition, constants, config
from ._phys.composition import utils, io
sys.modules['fourdst.atomic'] = atomic
sys.modules['fourdst.composition'] = composition
sys.modules['fourdst.constants'] = constants
sys.modules['fourdst.config'] = config
sys.modules['fourdst.composition.utils'] = utils
sys.modules['fourdst.composition.io'] = io
__all__ = ['atomic', 'composition', 'constants', 'config', 'core', 'cli']
__version__ = 'v0.9.11'
from importlib.metadata import version, PackageNotFoundError
try:
__version__ = version("fourdst")
except PackageNotFoundError:
__version__ = "0.0.0+unknown"
import os
from pathlib import Path
from typing import List
_PACKAGE_DIR = Path(__file__).resolve().parent
def get_lib_dirs() -> List[str]:
return [
os.fspath(_PACKAGE_DIR / "lib"),
os.fspath(_PACKAGE_DIR / "lib" / "vendor"),
]
def get_include_dirs() -> List[str]:
return [
os.fspath(_PACKAGE_DIR / "include"),
os.fspath(_PACKAGE_DIR / "include" / "fourdst" / "vendor"),
]
def get_rpath_flags() -> List[str]:
return ["-Wl,-rpath," + os.fspath(_PACKAGE_DIR / "lib")]
def get_lib_flags() -> List[str]:
flags = ["-L" + d for d in get_lib_dirs()]
flags += ["-lcomposition", "-llogging", "-lconst", "-lreflect_cpp"]
flags += get_rpath_flags()
return flags
def get_include_flags() -> List[str]:
return ["-I" + d for d in get_include_dirs()]
def get_compiler_flags() -> List[str]:
return get_include_flags() + get_lib_flags()
def get_extra_flags() -> List[str]:
return ['-fPIC', '-std=c++23']
def get_compiler_flags_formatted() -> int:
flags = get_compiler_flags()
flags.extend(get_extra_flags())
print(' '.join(flags))
return 0
def print_fourdst_version() -> int:
print("fourdst version: " + __version__)
return 0

View File

@@ -1,4 +1,4 @@
[wrap-git]
url = https://github.com/4D-STAR/libcomposition.git
revision = v2.3.1
revision = v2.4.9
depth = 1

View File

@@ -1,4 +1,4 @@
[wrap-git]
url = https://github.com/4D-STAR/libconfig.git
revision = v2.2.2
revision = v2.2.10
depth = 1

View File

@@ -1,4 +1,4 @@
[wrap-git]
url = https://github.com/4D-STAR/libconstants.git
revision = v1.1.1
revision = v1.1.7
depth = 1

View File

@@ -1,4 +1,4 @@
[wrap-git]
url = https://github.com/4D-STAR/liblogging.git
revision = v1.1.1
revision = v1.1.7
depth = 1

View File

@@ -0,0 +1,19 @@
Copyright (c) 2021 The Meson development team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,8 @@
project('pybind11', 'cpp',
version : 'v3.0.0',
license : 'BSD-3-Clause')
pybind11_incdir = include_directories('include')
pybind11_dep = declare_dependency(
include_directories : pybind11_incdir)

View File

@@ -1,13 +1,8 @@
[wrap-file]
directory = pybind11-2.13.5
source_url = https://github.com/pybind/pybind11/archive/refs/tags/v2.13.5.tar.gz
source_filename = pybind11-2.13.5.tar.gz
source_hash = b1e209c42b3a9ed74da3e0b25a4f4cd478d89d5efbb48f04b277df427faf6252
patch_filename = pybind11_2.13.5-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/pybind11_2.13.5-1/get_patch
patch_hash = ecb031b830481560b3d8487ed63ba4f5509a074be42f5d19af64d844c795e15b
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/pybind11_2.13.5-1/pybind11-2.13.5.tar.gz
wrapdb_version = 2.13.5-1
[wrap-git]
url = https://github.com/pybind/pybind11.git
revision = v3.0.0
depth = 1
patch_directory = pybind11
[provide]
pybind11 = pybind11_dep

View File

@@ -0,0 +1,51 @@
#!/usr/bin/env bash
set -euo pipefail
# Must be run on an aarch64 Linux host (uses docker so arm macos is fine so long as as the daemon is running)
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <git-repo-url>"
echo "Example: $0 https://github.com/4D-STAR/fourdst"
exit 1
fi
REPO_URL="$1"
WORK_DIR="$(pwd)"
WHEEL_DIR="${WORK_DIR}/wheels_linux_aarch64"
echo "➤ Creating wheel output directory at ${WHEEL_DIR}"
mkdir -p "${WHEEL_DIR}"
TMPDIR="$(mktemp -d)"
echo "➤ Cloning ${REPO_URL}${TMPDIR}/project"
git clone --depth 1 "${REPO_URL}" "${TMPDIR}/project"
IMAGE="tboudreaux/manylinux_2_28_aarch64_boost_1_88_0:latest"
docker run --rm \
-v "${WHEEL_DIR}":/io/wheels \
-v "${TMPDIR}/project":/io/project \
"${IMAGE}" \
/bin/bash -eux -c '
cd /io/project
RAW=/tmp/raw_wheels
for PY in /opt/python/*/bin/python; do
"$PY" -m pip install --upgrade pip
rm -rf "$RAW"; mkdir -p "$RAW"
CC=clang CXX=clang++ "$PY" -m pip wheel . \
--no-deps \
-w "$RAW" -vv
for whl in "$RAW"/*.whl; do
auditwheel repair "$whl" -w /io/wheels
done
done
echo "Linux aarch64 wheels ready in /io/wheels"
'
echo "Done. Repaired wheels in ${WHEEL_DIR}"
rm -rf "${TMPDIR}"

View File

@@ -0,0 +1,51 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <git-repo-url>"
echo "Example: $0 https://github.com/4D-STAR/fourdst"
exit 1
fi
REPO_URL="$1"
WORK_DIR="$(pwd)"
WHEEL_DIR="${WORK_DIR}/wheels_linux_x86_64"
echo "➤ Creating wheel output directory at ${WHEEL_DIR}"
mkdir -p "${WHEEL_DIR}"
TMPDIR="$(mktemp -d)"
echo "➤ Cloning ${REPO_URL}${TMPDIR}/project"
git clone --depth 1 "${REPO_URL}" "${TMPDIR}/project"
IMAGE="tboudreaux/manylinux_2_28_x86_64_boost_1_88_0:latest"
docker run --rm \
-v "${WHEEL_DIR}":/io/wheels \
-v "${TMPDIR}/project":/io/project \
"${IMAGE}" \
/bin/bash -eux -c '
cd /io/project
RAW=/tmp/raw_wheels
for PY in /opt/python/*/bin/python; do
"$PY" -m pip install --upgrade pip
rm -rf "$RAW"; mkdir -p "$RAW"
CC=clang CXX=clang++ "$PY" -m pip wheel . \
--no-deps \
--config-settings=setup-args=-Dunity=on \
-w "$RAW" -vv
# Repair only the freshly built wheel into the shared output dir.
for whl in "$RAW"/*.whl; do
auditwheel repair "$whl" -w /io/wheels
done
done
echo "Linux x86_64 wheels ready in /io/wheels"
'
echo "Done. Repaired wheels in ${WHEEL_DIR}"
rm -rf "${TMPDIR}"

View File

@@ -0,0 +1,74 @@
#!/usr/bin/env bash
set -euo pipefail
# Must be run on an Apple Silicon (arm64) Mac.
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>"
echo "Example: $0 https://github.com/4D-STAR/fourdst"
exit 1
fi
REPO_URL="$1"
WORK_DIR="$(pwd)"
WHEEL_DIR="${WORK_DIR}/wheels_macos_aarch64_tmp"
FINAL_WHEEL_DIR="${WORK_DIR}/wheels_macos_aarch64"
echo "➤ Creating wheel output directories"
mkdir -p "${WHEEL_DIR}"
mkdir -p "${FINAL_WHEEL_DIR}"
TMPDIR="$(mktemp -d)"
echo "➤ Cloning ${REPO_URL}${TMPDIR}/project"
git clone --depth 1 "${REPO_URL}" "${TMPDIR}/project"
cd "${TMPDIR}/project"
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" "3.14-dev" "3.14t-dev" )
if ! command -v pyenv &> /dev/null; then
echo "Error: pyenv not found. Please install it to manage Python versions."
echo " Then run installPyEnvVersions.sh to install the interpreters above."
exit 1
fi
eval "$(pyenv init -)"
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 "----------------------------------------------------------------"
"$PY" -m pip install --upgrade pip
"$PY" -m pip install "meson>=1.9.1,<1.10" "meson-python>=0.19,<0.20" "pybind11>=2.10" delocate
echo "➤ Building wheel with ccache enabled"
echo "➤ Found meson version $(meson --version)"
CC="ccache clang" CXX="ccache clang++" "$PY" -m pip wheel . \
--no-deps --no-build-isolation -w "${WHEEL_DIR}" -v
CURRENT_WHEEL=$(find "${WHEEL_DIR}" -name "*.whl" | head -n 1)
echo "➤ Repairing wheel with delocate"
delocate-wheel -w "${FINAL_WHEEL_DIR}" "$CURRENT_WHEEL"
rm "$CURRENT_WHEEL"
)
done
rm -rf "${TMPDIR}"
rm -rf "${WHEEL_DIR}"
echo "➤ All builds complete. Artifacts in ${FINAL_WHEEL_DIR}"

View File

@@ -0,0 +1,16 @@
#!/bin/bash
# Install every interpreter the macOS arm64 build matrix iterates over.
# Run once before build-wheels-macos_aarch64.sh.
pyenv install -s 3.9.23
pyenv install -s 3.10.18
pyenv install -s 3.11.13
pyenv install -s 3.12.11
pyenv install -s 3.13.5
pyenv install -s 3.13.5t
pyenv install -s 3.14.0rc1
pyenv install -s 3.14.0rc1t
pyenv install -s 3.14-dev
pyenv install -s 3.14t-dev
pyenv install -s 3.15-dev
pyenv install -s 3.15t-dev

42
utils/wheels/readme.md Normal file
View File

@@ -0,0 +1,42 @@
# Wheel Generation
This directory contains scripts to generate precompiled Python wheels for **fourdst**.
## Notes
- macOS wheels can only be generated on macOS.
- aarch64 wheels can only be generated on an aarch64 machine.
- x86_64 wheels can only be generated on an x86_64 machine.
- Linux wheels can be generated on any Linux machine, but the target architecture must match the host architecture (Docker runs natively, there is no emulation here).
- Running each script takes **a very long time** (potentially most of a day, depending on the machine) and needs roughly 2 GB of disk space.
- For the macOS build you must have all the listed Python versions installed via `pyenv`. Run `installPyEnvVersions.sh` first to install them.
- The old duplicate-RPATH workaround (`repair_wheel_macos.sh` + `fix_rpaths.py`) is **no longer needed** — the meson-python bug that caused it has been fixed, so the macOS script repairs with a plain `delocate-wheel` pass. Those two files can be deleted.
## Usage
Once you are on the correct machine, run the script for your target platform, passing the repository URL. For example, to build the macOS arm64 wheels:
```bash
./build-wheels-macos_aarch64.sh https://github.com/4D-STAR/fourdst
```
For Linux:
```bash
./build-wheels-linux_x86_64.sh https://github.com/4D-STAR/fourdst # on an x86_64 host
./build-wheels-linux_aarch64.sh https://github.com/4D-STAR/fourdst # on an aarch64 host
```
Each script writes its repaired, redistributable wheels to a per-platform directory (e.g. `wheels_macos_aarch64/`, `wheels_linux_x86_64/`).
## Publishing
Once every platform's wheels are generated (which generally requires multiple machines), copy them all into a single directory — assume it is called `wheels/` at the repository root — then, from the repository root:
```bash
python -m pip install --upgrade build twine
python -m build --sdist --outdir wheels # adds the source distribution
twine upload wheels/*
```
This uploads every wheel plus the sdist to PyPI (also slow, since it has to upload all of them).