Skip to content

Commit 946ccbf

Browse files
authored
tcmlib: add build-tcmlib.yml for riscv64 wheels (#1734)
* **Package**: `tcmlib` * **Version**: `1.5.0` * **Source**: https://github.com/uxlfoundation/oneTBB/tree/master/thread_composability_manager * **Docs**: https://oneapi-src.github.io/oneTBB/GSG/next_steps.html Compiles Intel's Thread Composability Manager (TCM) into libtcm.so. Upstream's PyPI `tcmlib` wheel is Intel's own closed-binary repackage with no sdist, so this builds the Apache-2.0 TCM source (git-subtree-merged into oneTBB) directly instead, same shape as the tbb port. No upstream CI builds this wheel; TCM has no oneTBB tag of its own, so the workflow pins the commit that introduced TCM 1.5.0 rather than a tag. **Differs from upstream** - Builds HWLOC 2.14.0 from source and bundles it - TCM requires it and it isn't a manylinux-portable system dependency. **Testing** - ctypes smoke test: load libtcm.so, call `tcmGetVersion()`, assert it matches the built version. **License**: Apache-2.0 (TCM's own LICENSE.txt); wheel also bundles HWLOC (BSD-3-Clause, its own COPYING file), since the build compiles and ships it as a runtime dependency. Built and smoke-tested on cp312.
1 parent 5da986e commit 946ccbf

2 files changed

Lines changed: 191 additions & 0 deletions

File tree

‎.github/workflows/build-tcmlib.yml‎

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# SPDX-FileCopyrightText: 2026 The RISE Project
2+
# SPDX-License-Identifier: MIT
3+
---
4+
# PyPI's tcmlib wheel is Intel's own prebuilt x86_64/win_amd64-only binary under a closed
5+
# redistribution licence with no sdist; this builds the Apache-2.0 TCM source instead (same
6+
# shape as the tbb port, see build-tbb.yml). TCM lives inside the oneTBB repo as a
7+
# git-subtree-merged subdirectory, not a separate project, and is versioned independently of
8+
# oneTBB itself, so there is no oneTBB tag for a given TCM release - pin the commit instead.
9+
# Based on: https://github.com/uxlfoundation/oneTBB/tree/master/thread_composability_manager
10+
# (no upstream CI builds this wheel)
11+
name: Build tcmlib wheels (riscv64)
12+
13+
on:
14+
workflow_dispatch:
15+
inputs:
16+
version:
17+
description: 'tcmlib version to build'
18+
required: true
19+
default: '1.5.0'
20+
pull_request:
21+
paths:
22+
- '.github/workflows/build-tcmlib.yml'
23+
- 'patches/tcmlib/**'
24+
25+
concurrency:
26+
group: ${{ github.workflow }}-${{ inputs.version || '1.5.0' }}-${{ github.head_ref || github.run_id }}
27+
cancel-in-progress: true
28+
29+
permissions:
30+
contents: read # to fetch code (actions/checkout)
31+
32+
env:
33+
TCM_VERSION: ${{ inputs.version || '1.5.0' }}
34+
# oneTBB commit that introduced TCM at version 1.5.0 (git-subtree merge of TCM's own
35+
# history, one day before the matching PyPI upload). Update alongside TCM_VERSION.
36+
TCM_REF: 7bc8577403df32b69b25157caad45677a8552861
37+
HWLOC_VERSION: 2.14.0
38+
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64
39+
40+
jobs:
41+
setup:
42+
uses: $/.github/workflows/_setup.yml
43+
44+
build_wheels:
45+
needs: [setup]
46+
name: Build tcmlib ${{ inputs.version || '1.5.0' }} py2.py3-none-manylinux_riscv64
47+
runs-on: ubuntu-24.04-riscv
48+
timeout-minutes: 120
49+
50+
steps:
51+
- name: Checkout oneTBB @ TCM ${{ env.TCM_VERSION }} (thread_composability_manager)
52+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
53+
with:
54+
repository: uxlfoundation/oneTBB
55+
ref: ${{ env.TCM_REF }}
56+
persist-credentials: false
57+
58+
- name: Checkout python-wheels
59+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
60+
with:
61+
path: python-wheels
62+
persist-credentials: false
63+
64+
# TCM's own cmake/compilers/GNU.cmake applies -fcf-protection=full (x86 CET
65+
# hardening) unconditionally, unlike oneTBB's own copy of the same file, which
66+
# gates it to x86 - GCC rejects the flag outright on other architectures.
67+
- name: Patch TCM source
68+
run: git apply python-wheels/patches/tcmlib/${{ env.TCM_VERSION }}/*.patch
69+
70+
- name: Pull manylinux_riscv64 image
71+
run: docker pull "${MANYLINUX_RISCV64_IMAGE}"
72+
73+
# TCM requires HWLOC >= 2.5 to build (find_package(HWLOC REQUIRED)); it isn't
74+
# manylinux-portable as a system dependency (same fact that made tbb drop its
75+
# optional libtbbbind), so build it from source and bundle it alongside libtcm.so,
76+
# exactly like Intel's own wheel does. TCM_TEST=OFF skips its test suite,
77+
# TCM_STRICT=OFF avoids upstream's warnings-as-errors on a newer GCC than they test.
78+
- name: Build HWLOC, TCM, and the wheel
79+
run: |
80+
docker run --rm -v "$(pwd):/work" -w /work -e TCM_VERSION -e HWLOC_VERSION "${MANYLINUX_RISCV64_IMAGE}" bash -c '
81+
set -euxo pipefail
82+
curl -fsSL -o hwloc.tar.gz "https://download.open-mpi.org/release/hwloc/v${HWLOC_VERSION%.*}/hwloc-${HWLOC_VERSION}.tar.gz"
83+
tar xzf hwloc.tar.gz
84+
(cd "hwloc-${HWLOC_VERSION}" && ./configure --prefix=/work/hwloc-install --disable-static && make -j"$(nproc)" && make install)
85+
export HWLOCROOT=/work/hwloc-install
86+
cmake -S thread_composability_manager -B build -DCMAKE_BUILD_TYPE=Release -DTCM_TEST=OFF -DTCM_STRICT=OFF -DCMAKE_INSTALL_LIBDIR=lib
87+
cmake --build build -j"$(nproc)"
88+
cmake --install build --prefix /work/install
89+
mkdir -p dist_libs
90+
cp -L install/lib/libtcm.so* hwloc-install/lib/libhwloc.so* dist_libs/
91+
for f in dist_libs/libtcm.so*; do patchelf --set-rpath "\$ORIGIN" "$f"; done
92+
strip dist_libs/*.so*
93+
file dist_libs/*.so*
94+
ldd dist_libs/libtcm.so.1
95+
cp thread_composability_manager/licensing/LICENSE.txt LICENSE.txt
96+
cp "hwloc-${HWLOC_VERSION}/COPYING" LICENSE-hwloc.txt
97+
cat > setup.py <<PYEOF
98+
import glob
99+
import os
100+
from setuptools import setup
101+
setup(
102+
name="tcmlib",
103+
version=os.environ["TCM_VERSION"],
104+
description="Thread Composability Manager",
105+
long_description="Thread Composability Manager (TCM) riscv64 dynamic library for Linux, built from the Apache-2.0 licensed oneTBB source, bundling a BSD-3-Clause HWLOC build it depends on.",
106+
url="https://github.com/uxlfoundation/oneTBB/tree/master/thread_composability_manager",
107+
license="Apache-2.0",
108+
license_files=["LICENSE.txt", "LICENSE-hwloc.txt"],
109+
classifiers=[
110+
"Operating System :: POSIX :: Linux",
111+
"Topic :: Software Development :: Libraries",
112+
],
113+
data_files=[("lib", sorted(glob.glob("dist_libs/*.so*")))],
114+
)
115+
PYEOF
116+
pybin=/opt/python/cp312-cp312/bin
117+
"$pybin/pip" install -q -U setuptools wheel
118+
"$pybin/python3" setup.py bdist_wheel --python-tag py2.py3 --plat-name manylinux_2_39_riscv64
119+
"$pybin/pip" install -q dist/*.whl
120+
"$pybin/python3" - <<PYEOF
121+
import ctypes, os, sysconfig
122+
libdir = os.path.join(sysconfig.get_path("data"), "lib")
123+
tcm = ctypes.CDLL(os.path.join(libdir, "libtcm.so.1"))
124+
tcm.tcmGetVersion.restype = ctypes.c_uint
125+
version = tcm.tcmGetVersion()
126+
major, minor, patch = (int(p) for p in os.environ["TCM_VERSION"].split("."))
127+
assert version == 10000 * major + 100 * minor + patch, version
128+
print("smoke test OK: tcmGetVersion() =", version)
129+
PYEOF
130+
'
131+
132+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
133+
with:
134+
name: tcmlib-${{ env.TCM_VERSION }}-py2.py3-none-manylinux_riscv64
135+
path: dist/*.whl
136+
if-no-files-found: error
137+
138+
publish:
139+
name: Publish tcmlib ${{ inputs.version || '1.5.0' }}
140+
needs: [setup, build_wheels]
141+
permissions:
142+
contents: write
143+
pull-requests: write
144+
uses: $/.github/workflows/_publish-wheel.yml
145+
with:
146+
artifact-pattern: tcmlib-${{ inputs.version || '1.5.0' }}-*-manylinux_riscv64
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
From 384ee8a7590516884d8a8290921864efa2644d55 Mon Sep 17 00:00:00 2001
2+
From: Ludovic Henry <git@ludovic.dev>
3+
Date: Thu, 10 Sep 2026 22:32:07 +0200
4+
Subject: [PATCH] build: gate -fcf-protection=full to x86 in TCM's GNU.cmake
5+
6+
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]
7+
8+
thread_composability_manager/cmake/compilers/GNU.cmake adds
9+
-fcf-protection=full unconditionally for GCC >= 8, unlike oneTBB's own
10+
cmake/compilers/GNU.cmake, which gates the same flag behind
11+
CMAKE_SYSTEM_PROCESSOR MATCHES "(AMD64|amd64|i.86|x86)". -fcf-protection is
12+
Intel CET control-flow hardening; on riscv64 GCC 13 rejects it outright:
13+
14+
cc1plus: error: '-fcf-protection=full' is not supported for this target
15+
compilation terminated due to -Wfatal-errors.
16+
17+
Restore the same x86 guard TBB's copy already has. Reproduces on riscv64
18+
only; x86_64 and aarch64 builds are unaffected.
19+
20+
Signed-off-by: Ludovic Henry <git@ludovic.dev>
21+
---
22+
thread_composability_manager/cmake/compilers/GNU.cmake | 7 ++++++-
23+
1 file changed, 6 insertions(+), 1 deletion(-)
24+
25+
diff --git a/thread_composability_manager/cmake/compilers/GNU.cmake b/thread_composability_manager/cmake/compilers/GNU.cmake
26+
index d7c1a46..abfbbce 100644
27+
--- a/thread_composability_manager/cmake/compilers/GNU.cmake
28+
+++ b/thread_composability_manager/cmake/compilers/GNU.cmake
29+
@@ -26,7 +26,12 @@ endif()
30+
set(TCM_COMMON_COMPILE_FLAGS ${TCM_COMMON_COMPILE_FLAGS} -fno-strict-overflow -fno-delete-null-pointer-checks -fwrapv
31+
-Wformat -Wformat-security -Werror=format-security -fstack-protector-strong $<$<NOT:$<CONFIG:Debug>>:-D_FORTIFY_SOURCE=2>)
32+
33+
-set(TCM_LIB_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto> $<$<NOT:$<VERSION_LESS:${CMAKE_CXX_COMPILER_VERSION},8.0>>:-fcf-protection=full>)
34+
+set(TCM_LIB_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-flto>)
35+
+# -fcf-protection is x86 CET hardening; GCC rejects it outright ("is not supported for
36+
+# this target") on other architectures, unlike -fstack-clash-protection above.
37+
+if (CMAKE_SYSTEM_PROCESSOR MATCHES "(AMD64|amd64|i.86|x86)")
38+
+ set(TCM_LIB_COMPILE_FLAGS ${TCM_LIB_COMPILE_FLAGS} $<$<NOT:$<VERSION_LESS:${CMAKE_CXX_COMPILER_VERSION},8.0>>:-fcf-protection=full>)
39+
+endif()
40+
41+
set(TCM_LIB_LINK_FLAGS ${TCM_LIB_LINK_FLAGS} $<$<NOT:$<CONFIG:Debug>>:-flto> -Wl,-z,relro,-z,now,-z,noexecstack)
42+
set(TCM_COMPILE_DEFINITIONS "")
43+
--
44+
2.50.1 (Apple Git-155)
45+

0 commit comments

Comments
 (0)