Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 71 additions & 21 deletions .github/actions/build_pypi_dist/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,11 @@ runs:
# Built from source at the *exact* version Ubuntu 24.04's apt
# package provides (see setup_nwx_dev_env), not EPEL's openmpi3
# (3.1.3) as before -- OpenMPI's ABI is not guaranteed compatible
# across major versions. EPEL7 (manylinux2014's package repo) has
# no openmpi4 package at all, so this can't be a yum install. Still
# across major versions. (manylinux_2_28's AppStream does carry
# an openmpi 4.1.1, but a source build pins the exact version
# instead of whatever the distro floats to, so this stays as it
# is; EPEL7, the package repo before the 2_28 switch, had no
# openmpi4 at all and left no choice in the matter.) Still
# needed even though the wheel no longer vendors MPI (see
# CIBW_REPAIR_WHEEL_COMMAND_LINUX below): the extension must be
# *compiled* against a matching OpenMPI to link correctly against
Expand Down Expand Up @@ -248,19 +251,22 @@ runs:
# provides ambient (libopenmpi-dev/openmpi-bin) and which end users
# need to install themselves (documented as a runtime requirement).
#
# Exact sonames (libmpi.so.40), NOT a glob (libmpi*): cibuildwheel
# v2.22.0's manylinux2014 image (quay.io/pypa/manylinux2014_x86_64:
# 2024.11.16-1) bakes in auditwheel 6.1.0, whose --exclude does a
# Exact sonames (libmpi.so.40), NOT a glob (libmpi*). The old
# manylinux2014 image (quay.io/pypa/manylinux2014_x86_64:
# 2024.11.16-1) baked in auditwheel 6.1.0, whose --exclude did a
# plain `soname in exclude` set-membership check (confirmed by
# reading that exact container's lddtree.py) -- fnmatch/glob
# support for --exclude was only added in a later auditwheel
# release. A glob pattern silently matches nothing and bundles the
# library anyway (reproduced locally via Docker: 'libmpi*' bundled
# libmpi/libopen-rte/libopen-pal same as no --exclude at all;
# 'libmpi.so.40' correctly excluded it, and since libopen-rte/
# libopen-pal are only reachable *through* libmpi in this tree,
# excluding libmpi.so.40 alone is sufficient -- auditwheel doesn't
# recurse into an excluded library's own dependencies).
# reading that exact container's lddtree.py); fnmatch/glob support
# for --exclude only arrived in a later release, so a glob
# silently matched nothing and bundled the library anyway
# (reproduced via Docker against 6.1.0: 'libmpi*' bundled
# libmpi/libopen-rte/libopen-pal same as no --exclude at all,
# while 'libmpi.so.40' correctly excluded it). manylinux_2_28
# ships auditwheel 6.7.0, which does support globs, but the exact
# sonames are kept: they work under both, and they name precisely
# what is meant. Since libopen-rte/libopen-pal are only reachable
# *through* libmpi in this tree, excluding libmpi.so.40 alone is
# sufficient -- auditwheel doesn't recurse into an excluded
# library's own dependencies.
{
echo "CIBW_REPAIR_WHEEL_COMMAND_LINUX=auditwheel repair --exclude 'libmpi.so.40' --exclude 'libopen-rte.so.40' --exclude 'libopen-pal.so.40' -w {dest_dir} {wheel}"
} >> "$GITHUB_ENV"
Expand All @@ -276,13 +282,23 @@ runs:
fi

if [ "${{ inputs.needs_boost }}" = "true" ]; then
# manylinux2014's plain boost-devel is 1.53.0, too old for headers
# some repos need (e.g. boost/container_hash/hash.hpp). EPEL's
# boost169-devel (parallel-installable, doesn't replace the base
# boost-devel) is the newest available via yum there, but installs
# under a versioned, non-default include path, so CMake's FindBoost
# needs to be pointed at it explicitly via BOOST_INCLUDEDIR.
before_linux+=("yum install -y boost169-devel")
# The image's base boost-devel is too old for headers some repos
# need: boost/container_hash/hash.hpp arrived in Boost 1.67, and
# the base package is 1.53.0 on manylinux2014 and 1.66.0 on
# manylinux_2_28 -- verified absent in both. EPEL's boost169-devel
# (1.69.0, parallel-installable, doesn't replace the base
# boost-devel) carries it, and installs at the same
# /usr/include/boost169 path under EPEL7 and EPEL8 alike. That
# versioned, non-default include path is why CMake's FindBoost has
# to be pointed at it explicitly via BOOST_INCLUDEDIR.
#
# epel-release is installed here rather than assumed: EPEL came
# pre-enabled on manylinux2014, but NOT on the manylinux_2_28
# image cibuildwheel v2.22.0 pins (2024.11.16-1) -- verified, it
# ships only baseos/appstream/extras/powertools, and this
# yum install fails without it. Harmlessly repeated by the
# needs_blas and needs_eigen branches below.
before_linux+=("yum install -y epel-release" "yum install -y boost169-devel")
env_linux+=("BOOST_INCLUDEDIR=/usr/include/boost169")
before_macos+=("brew install boost")
fi
Expand Down Expand Up @@ -369,6 +385,40 @@ runs:
env:
CIBW_BUILD: ${{ inputs.cibw_build }}
CIBW_BUILD_VERBOSITY: "1"
# Overrides cibuildwheel v2.22.0's default manylinux2014 image.
# That image is CentOS 7 + devtoolset-10, whose libstdc++ is built
# with _GLIBCXX_USE_DUAL_ABI 0 -- its <bits/c++config.h> does an
# unconditional "#undef _GLIBCXX_USE_CXX11_ABI" and pins the macro
# to 0, so it *discards* any -D_GLIBCXX_USE_CXX11_ABI=1 passed in.
# The new ABI is not merely off there, it is compiled out of the
# toolchain. Every C++ library in a Linux wheel therefore exported
# the pre-C++11 COW std::string ABI (pluginplay::ModuleManager::at
# taking RKSs rather than RKNSt7__cxx11...), which nothing built on
# a modern distro can link against: the dev matrix
# (ubuntu-24.04, gcc-14/clang-18) defaults to the new ABI, so
# SCF's test_cmake_build died at link with hundreds of undefined
# references to ecosystem symbols once it finally got far enough to
# link at all.
#
# manylinux_2_28 (AlmaLinux 8, gcc 14.2.1) defaults to
# _GLIBCXX_USE_CXX11_ABI 1, and its auditwheel policy permits the
# GLIBCXX_3.4.21 symbols the new ABI needs -- manylinux_2_17 caps
# at 3.4.19, which is the other half of why the flag route is a
# dead end rather than merely risky. Its gcc 14.2.1 also happens to
# match the dev matrix's gcc-14 exactly.
#
# Verified against the exact image cibuildwheel v2.22.0 pins
# (quay.io/pypa/manylinux_2_28_x86_64:2024.11.16-1, NOT :latest,
# which differs): yum is present, PowerTools is enabled out of the
# box so openblas-devel/lapack-devel/eigen3-devel resolve, and
# boost169-devel resolves at the same /usr/include/boost169 path
# once epel-release is installed -- EPEL is pre-enabled on
# manylinux2014 but not here, which is why the needs_boost branch
# above now installs it explicitly.
#
# Raises the minimum glibc for a consumer of these wheels from 2.17
# (CentOS 7, long EOL) to 2.28 (RHEL 8 / Ubuntu 18.10 and newer).
CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28

- name: Collect cibuildwheel Output
if: inputs.cibw_build != ''
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/cmake_build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ description: >-

inputs:
compiler:
description: "One of: gcc-14, clang-18. Installed via the native package manager (apt on Linux, Homebrew on macOS)."
description: "One of: gcc-14, clang-18 (Linux); appleclang (macOS, i.e. /usr/bin/clang++, the compiler that builds the wheels). Installed via the native package manager (apt on Linux, Homebrew on macOS)."
required: true
run_cmake_tests:
description: "Whether to build and run the CTest (C++) test suite (sets -DBUILD_TESTING)."
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/pip_build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ description: >-

inputs:
compiler:
description: "One of: gcc-14, clang-18. Installed via the native package manager (apt on Linux, Homebrew on macOS)."
description: "One of: gcc-14, clang-18 (Linux); appleclang (macOS, i.e. /usr/bin/clang++, the compiler that builds the wheels). Installed via the native package manager (apt on Linux, Homebrew on macOS)."
required: true
run_cmake_tests:
description: "Whether to build and run the CTest (C++) test suite (sets -DBUILD_TESTING)."
Expand Down
28 changes: 21 additions & 7 deletions .github/actions/setup_nwx_dev_env/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ description: >-

inputs:
compiler:
description: "One of: gcc-14, clang-18."
description: "One of: gcc-14, clang-18 (Linux); appleclang (macOS)."
required: true
needs_nwchem:
description: >-
Expand Down Expand Up @@ -62,14 +62,28 @@ runs:
echo "CXX=g++-14" >> "$GITHUB_ENV"
echo "CMAKE_PREFIX_PATH=$(brew --prefix openblas)" >> "$GITHUB_ENV"
;;
macOS_clang-18)
brew install llvm@18 libomp cmake ninja ccache open-mpi boost openblas eigen
prefix=$(brew --prefix llvm@18)
macOS_appleclang)
# /usr/bin/clang++ -- the SAME compiler cibuildwheel uses to build
# the macOS wheels (build_pypi_dist logs "AppleClang 15.0.0" on
# macos-14). Deliberately not Homebrew llvm@18, which was used
# here before: that ships its OWN libc++ (_LIBCPP_VERSION 18.01.00)
# while the wheels are built against the SDK's, and mixing two
# libc++ implementations links cleanly and then dies at dyld with
# "symbol not found in flat namespace" -- the SCF#76 segfault.
#
# It also closes a real gap: AppleClang builds every released
# macOS wheel but was compiled by no CI job, which is how a C++20
# P1091 (structured binding captured in a lambda) use survived in
# grid_from_integratorxx.cpp while all legs stayed green. The
# project requires C++20 and AppleClang 15 compiles the whole tree
# at -std=c++20 today; testing with it makes the ceiling it
# already imposes on releases visible in PR CI.
brew install libomp cmake ninja ccache open-mpi boost openblas eigen
libomp_prefix=$(brew --prefix libomp)
echo "CC=${prefix}/bin/clang" >> "$GITHUB_ENV"
echo "CXX=${prefix}/bin/clang++" >> "$GITHUB_ENV"
echo "CC=/usr/bin/clang" >> "$GITHUB_ENV"
echo "CXX=/usr/bin/clang++" >> "$GITHUB_ENV"
echo "CMAKE_PREFIX_PATH=$(brew --prefix openblas);${libomp_prefix}" >> "$GITHUB_ENV"
# llvm@18's own clang has no bundled OpenMP runtime; find_package(OpenMP)
# AppleClang has no bundled OpenMP runtime either; find_package(OpenMP)
# needs omp.h/libomp.dylib on the compiler's default search paths to pass
# its "-fopenmp compiles" check and locate the library, and CPATH/LIBRARY_PATH
# are how Clang picks those up without needing explicit -I/-L flags threaded
Expand Down
23 changes: 21 additions & 2 deletions .github/workflows/platform_matrix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,30 @@ jobs:
{"os": "ubuntu-latest", "cibw_build": "cp312-manylinux_x86_64"},
{"os": "macos-14", "cibw_build": "cp312-macosx_arm64"}
]'
# macos-14/gcc-14 is deliberately absent. The macOS wheels are
# built by cibuildwheel with AppleClang against libc++, while
# Homebrew's GCC uses libstdc++ and has no working libc++ mode --
# they mangle std::string differently
# (NSt3__112basic_string... vs NSt7__cxx1112basic_string...), so a
# GCC build can never link them. That is a property of the
# platform, not a bug to be fixed, so the leg could only ever be
# red. macOS + GCC is supported only when the whole ecosystem is
# built from source (-DNWX_ECOSYSTEM_FROM_SOURCE=ON); NWXCMake's
# nwx_assert_wheel_toolchain_supported() fails loudly otherwise.
#
# The remaining macOS leg is AppleClang, not Homebrew llvm@18: the
# wheels are built by AppleClang, and llvm@18 carries its own libc++
# (18.01.00 vs the SDK's), which links cleanly and then dies at dyld
# -- the SCF#76 segfault. Matching the release compiler also means
# PR CI finally compiles what actually ships.
#
# Linux keeps both compilers: clang there consumes GCC's own
# libstdc++ headers and links the same libstdc++.so.6, so the two
# share one C++ runtime and agree on the mangling.
dev_matrix='[
{"os": "ubuntu-latest", "compiler": "gcc-14"},
{"os": "ubuntu-latest", "compiler": "clang-18"},
{"os": "macos-14", "compiler": "gcc-14"},
{"os": "macos-14", "compiler": "clang-18"}
{"os": "macos-14", "compiler": "appleclang"}
]'
echo "release_matrix=$(echo "$release_matrix" | jq -c .)" >> "$GITHUB_OUTPUT"
echo "dev_matrix=$(echo "$dev_matrix" | jq -c .)" >> "$GITHUB_OUTPUT"
Loading