Skip to content
Draft
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
76 changes: 76 additions & 0 deletions .ci/install.kenref
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#! /usr/bin/env bash

set -e
set -x

# Build and install the KEnRef core library, which the (default-off) kenref module links against.
#
# The version is PINNED. configure can fetch KEnRef itself, but CI must not depend on whatever happens
# to be on a branch today, and a pinned tag also lets the install directory be cached.
# KENREF_VERSION and KENREF_URL are parsed out of this file by the workflow (to resolve the ref to a
# commit for the cache key), so keep them as plain, unquoted assignments at the start of a line.
KENREF_VERSION=v2.0.0
KENREF_URL=https://github.com/Smith-Group/KEnRef.git
KENREF_INSTALL_DIR="$HOME/opt/kenref"

# The module needs the plumedinterface include paths, which come from kenref_plumed.pc. That file
# `Requires: eigen3`, and a bare CI runner has no eigen3.pc -- so on such a machine only the
# self-contained kenref_plumed_and_eigen3.pc (Eigen embedded, no Requires:) can resolve. A KENREF_VERSION
# predating that file therefore installs a prefix that looks complete but cannot configure the module.
#
# Checked on the cache-restore path as well as after a fresh build: a cache saved by an older revision of
# this script can outlive the assumptions it was built under.
check_prefix() {
for pc in kenref_core.pc kenref_plumed.pc kenref_plumed_and_eigen3.pc ; do
test -f "$KENREF_INSTALL_DIR/lib/pkgconfig/$pc" || {
echo "ERROR: $pc missing from the KEnRef install in $KENREF_INSTALL_DIR." >&2
echo " KENREF_VERSION=$KENREF_VERSION is too old, or a stale cache was restored: this" >&2
echo " prefix predates the self-contained plumedinterface pkg-config file, without which" >&2
echo " the module cannot be configured on a machine that has no eigen3.pc." >&2
return 1
}
done
}

# Nothing to do if a cache restored a usable prefix.
if test -f "$KENREF_INSTALL_DIR/lib/pkgconfig/kenref_core.pc" ; then
echo "kenref already present in $KENREF_INSTALL_DIR"
check_prefix
exit $?
fi

cd "$(mktemp -dt plumed.XXXXXX)"

git clone --depth 1 --branch "$KENREF_VERSION" "$KENREF_URL"
cd KEnRef

# ACCEL is set explicitly rather than left to KEnRef's per-machine auto-detection. KEnRef stores Eigen
# objects inside its own containers, so the SIMD width fixes EIGEN_MAX_ALIGN_BYTES and therefore its
# ABI; pinning the tier keeps the build reproducible across whatever runner GitHub allocates. AVX2_256
# is KEnRef's portable default.
#
# KENREF_EXPORT_PLUMEDINTERFACE=ON installs the headers and the source that the kenref module compiles
# in-tree, plus kenref_plumed.pc.
#
# The compiler is passed through explicitly rather than left to cmake's own search. libkenref_core and
# PLUMED end up in ONE process, so if they are built by different toolchains they bring in two different
# OpenMP runtimes (libgomp beside libiomp5). Both are then loaded at once, which is unsupported: thread
# counts and the order of threaded reductions stop being well defined, and PLUMED's regtests fail in the
# last digits right across the threaded modules. Building KEnRef with whatever CXX the job has already
# selected keeps it on the same runtime as PLUMED.
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
${CC:+-DCMAKE_C_COMPILER="$CC"} \
${CXX:+-DCMAKE_CXX_COMPILER="$CXX"} \
-DBUILD_KENREF_CORE=ON \
-DBUILD_KENREF_GMX=OFF \
-DKENREF_EXPORT_PLUMEDINTERFACE=ON \
-DACCEL=AVX2_256 \
-DKENREF_EIGEN_GIT_TAG=5.0.1 \
-DCMAKE_INSTALL_PREFIX="$KENREF_INSTALL_DIR"

cmake --build build -j "$(nproc)"
cmake --install build

# Fail here, with a clear reason, rather than deep inside PLUMED's configure.
check_prefix
44 changes: 44 additions & 0 deletions .github/workflows/linuxWF.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,28 @@ jobs:
path: ~/.ccache
key: ccache-reset1-linux${{ matrix.variant }}hash-${{ github.sha }}
restore-keys: ccache-reset1-linux${{ matrix.variant }}hash-
# kenref_core is built from a pinned ref, so it only needs rebuilding when that ref moves.
# .ci/install.kenref exits early when the cache restored a usable prefix.
#
# The cache key has to name the COMMIT, not just the ref: a tag can be re-pointed while
# .ci/install.kenref stays byte-identical, and keying on the file alone would then restore a prefix
# built from the old commit and silently skip the rebuild. Resolve the ref here so the key follows it.
- name: Resolve the pinned KEnRef commit
id: kenref_commit
run: |
ver="$(sed -n 's/^KENREF_VERSION=//p' .ci/install.kenref)"
url="$(sed -n 's/^KENREF_URL=//p' .ci/install.kenref)"
# An annotated tag needs the ^{} peel to reach the commit; ls-remote sorts its output, so asking
# for several patterns at once and taking the first line would return the tag OBJECT instead.
# Ask for the peeled ref on its own, then fall back for lightweight tags and branches.
sha="$(git ls-remote "$url" "refs/tags/$ver^{}" | cut -f1)"
test -n "$sha" || sha="$(git ls-remote "$url" "refs/tags/$ver" "refs/heads/$ver" | head -n1 | cut -f1)"
test -n "$sha" || { echo "cannot resolve KEnRef ref '$ver' at $url" >&2 ; exit 1 ; }
echo "sha=$sha" >> "$GITHUB_OUTPUT"
- uses: actions/cache@v5
with:
path: ~/opt/kenref
key: kenref-${{ steps.kenref_commit.outputs.sha }}-${{ hashFiles('.ci/install.kenref') }}-linux${{ matrix.variant }}
- name: setup the CI environment
uses: ./.github/actions/linux-setup
with:
Expand Down Expand Up @@ -132,6 +154,28 @@ jobs:
run: |
pip install --user mpi4py
python -c "import mpi4py"
- name: Install KEnRef
# Kept AFTER the compiler steps above, because .ci/install.kenref builds libkenref_core with $CXX
# and that library is loaded into the same process as PLUMED. Built earlier it would pick up the
# default g++ even in the -intel- job, and the two OpenMP runtimes that results in make the
# threaded regtests disagree in their last digits. Anything that rewrites CC/CXX must stay above.
#
# excluded for the same reasons as ITensor: _GLIBCXX_DEBUG changes the STL ABI, and KEnRef stores
# Eigen objects in its own containers, so a debug build of PLUMED and a non-debug libkenref_core
# disagree about their layout. The #ifdef __PLUMED_HAS_KENREF guards keep the module compiling
# when it is not configured.
if: ${{ ! contains( matrix.variant, '-debug-' ) && ! contains( matrix.variant, '-nvhpc-' ) }}
run: |
.ci/install.kenref
- name: Configure KEnRef
if: ${{ ! contains( matrix.variant, '-debug-' ) && ! contains( matrix.variant, '-nvhpc-' ) }}
run: |
# Putting the prefix on PKG_CONFIG_PATH means configure FINDS kenref_core rather than cloning
# and building it itself, so CI never depends on a network fetch during ./configure. The .pc
# also carries the -march the library was built with, which the module must match.
echo "PKG_CONFIG_PATH=$HOME/opt/kenref/lib/pkgconfig:$PKG_CONFIG_PATH" >> $GITHUB_ENV
echo "LD_LIBRARY_PATH=$HOME/opt/kenref/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV
echo "PLUMED_CONFIG=$PLUMED_CONFIG --enable-kenref" >> $GITHUB_ENV
- name: Configure PLUMED
id: config
run: |
Expand Down
6 changes: 6 additions & 0 deletions Makefile.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,9 @@ use_absolute_soname=@use_absolute_soname@
use_loader_path=@use_loader_path@
use_debug_glibcxx=@use_debug_glibcxx@
BASH_COMPLETION_DIR=@BASH_COMPLETION_DIR@
HAVE_KENREF=@HAVE_KENREF@
KENREF_INCLUDE=@KENREF_INCLUDE@
KENREF_LIBS=@KENREF_LIBS@
# kenref module COMPILE includes, resolved at configure time (pkg-config --cflags kenref_plumed) so the
# module Makefile does not re-run pkg-config at parse time. Read by src/kenref/Makefile.
KENREF_PLUMED_CPPFLAGS=@KENREF_PLUMED_INCLUDE@
Loading
Loading