diff --git a/.github/workflows/build-tcmlib.yml b/.github/workflows/build-tcmlib.yml new file mode 100644 index 000000000..c3961de75 --- /dev/null +++ b/.github/workflows/build-tcmlib.yml @@ -0,0 +1,146 @@ +# 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' + - 'patches/tcmlib/**' + +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: Checkout python-wheels + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + path: python-wheels + persist-credentials: false + + # TCM's own cmake/compilers/GNU.cmake applies -fcf-protection=full (x86 CET + # hardening) unconditionally, unlike oneTBB's own copy of the same file, which + # gates it to x86 - GCC rejects the flag outright on other architectures. + - name: Patch TCM source + run: git apply python-wheels/patches/tcmlib/${{ env.TCM_VERSION }}/*.patch + + - 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/ + 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.1 + cp thread_composability_manager/licensing/LICENSE.txt LICENSE.txt + cp "hwloc-${HWLOC_VERSION}/COPYING" LICENSE-hwloc.txt + cat > setup.py < +--- + 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) +