From 3eb53263558a42fcf17ac3019a3619fba3c986f5 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 10 Sep 2026 22:14:24 +0200 Subject: [PATCH 1/3] tcmlib: add build-tcmlib.yml for riscv64 wheels --- .github/workflows/build-tcmlib.yml | 133 +++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 .github/workflows/build-tcmlib.yml diff --git a/.github/workflows/build-tcmlib.yml b/.github/workflows/build-tcmlib.yml new file mode 100644 index 000000000..a287d06a5 --- /dev/null +++ b/.github/workflows/build-tcmlib.yml @@ -0,0 +1,133 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# PyPI's tcmlib wheel is Intel's own prebuilt x86_64/win_amd64-only binary under a closed +# redistribution licence with no sdist; this builds the Apache-2.0 TCM source instead (same +# shape as the tbb port, see build-tbb.yml). TCM lives inside the oneTBB repo as a +# git-subtree-merged subdirectory, not a separate project, and is versioned independently of +# oneTBB itself, so there is no oneTBB tag for a given TCM release - pin the commit instead. +# Based on: https://github.com/uxlfoundation/oneTBB/tree/master/thread_composability_manager +# (no upstream CI builds this wheel) +name: Build tcmlib wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'tcmlib version to build' + required: true + default: '1.5.0' + pull_request: + paths: + - '.github/workflows/build-tcmlib.yml' + +concurrency: + group: ${{ github.workflow }}-${{ inputs.version || '1.5.0' }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + TCM_VERSION: ${{ inputs.version || '1.5.0' }} + # oneTBB commit that introduced TCM at version 1.5.0 (git-subtree merge of TCM's own + # history, one day before the matching PyPI upload). Update alongside TCM_VERSION. + TCM_REF: 7bc8577403df32b69b25157caad45677a8552861 + HWLOC_VERSION: 2.14.0 + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + + build_wheels: + needs: [setup] + name: Build tcmlib ${{ inputs.version || '1.5.0' }} py2.py3-none-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 120 + + steps: + - name: Checkout oneTBB @ TCM ${{ env.TCM_VERSION }} (thread_composability_manager) + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: uxlfoundation/oneTBB + ref: ${{ env.TCM_REF }} + persist-credentials: false + + - name: Pull manylinux_riscv64 image + run: docker pull "${MANYLINUX_RISCV64_IMAGE}" + + # TCM requires HWLOC >= 2.5 to build (find_package(HWLOC REQUIRED)); it isn't + # manylinux-portable as a system dependency (same fact that made tbb drop its + # optional libtbbbind), so build it from source and bundle it alongside libtcm.so, + # exactly like Intel's own wheel does. TCM_TEST=OFF skips its test suite, + # TCM_STRICT=OFF avoids upstream's warnings-as-errors on a newer GCC than they test. + - name: Build HWLOC, TCM, and the wheel + run: | + docker run --rm -v "$(pwd):/work" -w /work -e TCM_VERSION -e HWLOC_VERSION "${MANYLINUX_RISCV64_IMAGE}" bash -c ' + set -euxo pipefail + curl -fsSL -o hwloc.tar.gz "https://download.open-mpi.org/release/hwloc/v${HWLOC_VERSION%.*}/hwloc-${HWLOC_VERSION}.tar.gz" + tar xzf hwloc.tar.gz + (cd "hwloc-${HWLOC_VERSION}" && ./configure --prefix=/work/hwloc-install --disable-static && make -j"$(nproc)" && make install) + export HWLOCROOT=/work/hwloc-install + cmake -S thread_composability_manager -B build -DCMAKE_BUILD_TYPE=Release -DTCM_TEST=OFF -DTCM_STRICT=OFF -DCMAKE_INSTALL_LIBDIR=lib + cmake --build build -j"$(nproc)" + cmake --install build --prefix /work/install + mkdir -p dist_libs + cp -L install/lib/libtcm.so* hwloc-install/lib/libhwloc.so* dist_libs/ + patchelf --set-rpath "\$ORIGIN" dist_libs/libtcm.so + strip dist_libs/*.so* + file dist_libs/*.so* + ldd dist_libs/libtcm.so + cp thread_composability_manager/licensing/LICENSE.txt LICENSE.txt + cp "hwloc-${HWLOC_VERSION}/COPYING" LICENSE-hwloc.txt + cat > setup.py < +Date: Thu, 10 Sep 2026 22:32:07 +0200 +Subject: [PATCH] build: gate -fcf-protection=full to x86 in TCM's GNU.cmake + +Upstream-Status: To upstream [python-wheels does not open issues/PRs on third-party repos, so this can't be submitted to uxlfoundation/oneTBB from here; flagging for a human to upstream] + +thread_composability_manager/cmake/compilers/GNU.cmake adds +-fcf-protection=full unconditionally for GCC >= 8, unlike oneTBB's own +cmake/compilers/GNU.cmake, which gates the same flag behind +CMAKE_SYSTEM_PROCESSOR MATCHES "(AMD64|amd64|i.86|x86)". -fcf-protection is +Intel CET control-flow hardening; on riscv64 GCC 13 rejects it outright: + + cc1plus: error: '-fcf-protection=full' is not supported for this target + compilation terminated due to -Wfatal-errors. + +Restore the same x86 guard TBB's copy already has. Reproduces on riscv64 +only; x86_64 and aarch64 builds are unaffected. + +Signed-off-by: Ludovic Henry +--- + thread_composability_manager/cmake/compilers/GNU.cmake | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/thread_composability_manager/cmake/compilers/GNU.cmake b/thread_composability_manager/cmake/compilers/GNU.cmake +index d7c1a46..abfbbce 100644 +--- a/thread_composability_manager/cmake/compilers/GNU.cmake ++++ b/thread_composability_manager/cmake/compilers/GNU.cmake +@@ -26,7 +26,12 @@ endif() + set(TCM_COMMON_COMPILE_FLAGS ${TCM_COMMON_COMPILE_FLAGS} -fno-strict-overflow -fno-delete-null-pointer-checks -fwrapv + -Wformat -Wformat-security -Werror=format-security -fstack-protector-strong $<$>:-D_FORTIFY_SOURCE=2>) + +-set(TCM_LIB_COMPILE_FLAGS $<$>:-flto> $<$>:-fcf-protection=full>) ++set(TCM_LIB_COMPILE_FLAGS $<$>:-flto>) ++# -fcf-protection is x86 CET hardening; GCC rejects it outright ("is not supported for ++# this target") on other architectures, unlike -fstack-clash-protection above. ++if (CMAKE_SYSTEM_PROCESSOR MATCHES "(AMD64|amd64|i.86|x86)") ++ set(TCM_LIB_COMPILE_FLAGS ${TCM_LIB_COMPILE_FLAGS} $<$>:-fcf-protection=full>) ++endif() + + set(TCM_LIB_LINK_FLAGS ${TCM_LIB_LINK_FLAGS} $<$>:-flto> -Wl,-z,relro,-z,now,-z,noexecstack) + set(TCM_COMPILE_DEFINITIONS "") +-- +2.50.1 (Apple Git-155) + From 332e6626dfba73e0cfb46ac0d613d596e6d245e2 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Thu, 10 Sep 2026 22:59:03 +0200 Subject: [PATCH 3/3] tcmlib: set $ORIGIN rpath on every libtcm.so* copy, not just the dev symlink cp -L produces independent files for libtcm.so, .so.1, and .so.1.5.0; patchelf only patched the bare .so, so the SONAME file the smoke test dlopens (libtcm.so.1) had no rpath and couldn't find libhwloc.so.15 sitting next to it: 'OSError: libhwloc.so.15: cannot open shared object file'. --- .github/workflows/build-tcmlib.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-tcmlib.yml b/.github/workflows/build-tcmlib.yml index 616c8de31..c3961de75 100644 --- a/.github/workflows/build-tcmlib.yml +++ b/.github/workflows/build-tcmlib.yml @@ -88,10 +88,10 @@ jobs: cmake --install build --prefix /work/install mkdir -p dist_libs cp -L install/lib/libtcm.so* hwloc-install/lib/libhwloc.so* dist_libs/ - patchelf --set-rpath "\$ORIGIN" dist_libs/libtcm.so + for f in dist_libs/libtcm.so*; do patchelf --set-rpath "\$ORIGIN" "$f"; done strip dist_libs/*.so* file dist_libs/*.so* - ldd dist_libs/libtcm.so + ldd dist_libs/libtcm.so.1 cp thread_composability_manager/licensing/LICENSE.txt LICENSE.txt cp "hwloc-${HWLOC_VERSION}/COPYING" LICENSE-hwloc.txt cat > setup.py <