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
196 changes: 196 additions & 0 deletions .github/workflows/build-umf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# PyPI's umf wheel is Intel's own build of the Apache-2.0 UMF C library (no Python bindings,
# just headers/libs/CMake config installed under <wheel>.data/data/), x86_64/win_amd64 only
# with no sdist; this builds the same source instead (same shape as the tbb/tcmlib ports).
# The shipped libumf.so embeds its own UMF_ALL_CMAKE_VARIABLES build string, which pins the
# exact CMake flags Intel builds with: only UMF_BUILD_SHARED_LIBRARY, UMF_BUILD_LEVEL_ZERO_PROVIDER
# and UMF_BUILD_CUDA_PROVIDER are ON, everything else (tests/examples/benchmarks/jemalloc) is
# OFF -- mirrored below. The GPU providers only dlopen() libcuda.so/libze_loader.so at call time
# (src/utils/utils_load_library.c) and compile against header-only FetchContent'd repos, so they
# build and stay fully portable without any proprietary SDK; disabling them would be an
# unwarranted capability regression from the reference x86_64 wheel.
# Based on: https://github.com/oneapi-src/unified-memory-framework (no upstream CI builds this
# wheel; upstream's own reusable_fast.yml enables the same two providers for its plain Linux CI).
name: Build umf wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'Version glob to (re)build; empty builds every version of docs/packages/umf.yaml not released yet'
required: false
default: ''
pull_request:
branches: [main]
paths:
- '.github/workflows/build-umf.yml'
- 'docs/packages/umf.yaml'
push:
branches: [main]
paths:
- '.github/workflows/build-umf.yml'
- 'docs/packages/umf.yaml'

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read # to fetch code (actions/checkout)

env:
HWLOC_VERSION: 2.14.0
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64

jobs:
setup:
uses: $/.github/workflows/_setup.yml
with:
package: umf
version: ${{ inputs.version }}

build_wheels:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Build umf ${{ matrix.version }} py2.py3-none-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 120

env:
UMF_VERSION: ${{ matrix.version }}

steps:
- name: Checkout UMF v${{ env.UMF_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: oneapi-src/unified-memory-framework
ref: v${{ env.UMF_VERSION }}
persist-credentials: false

- name: Pull manylinux_riscv64 image
run: docker pull "${MANYLINUX_RISCV64_IMAGE}"

# hwloc >= 2.3.0 is a required, dynamically-linked dependency (find_package(LIBHWLOC
# REQUIRED)); built and bundled here the same way the tcmlib port does (build-tcmlib.yml).
# numactl-devel is only needed to build UMF's own test suite (test/CMakeLists.txt), not
# the library itself; it is in Rocky 10's appstream repo, no --enablerepo=crb needed.
# --cap-add=SYS_PTRACE: UMF's IPC tests duplicate a memory-mapped fd across a
# pid via pidfd_getfd(2) (gotcha 552), which Docker's default seccomp profile
# blocks (EPERM) without this capability, even for a process duplicating its own fd.
- name: Build HWLOC, UMF, test it, and build the wheel
run: |
docker run --rm --cap-add=SYS_PTRACE -v "$(pwd):/work" -w /work -e UMF_VERSION -e HWLOC_VERSION "${MANYLINUX_RISCV64_IMAGE}" bash -c '
set -euxo pipefail
dnf install -y --setopt=install_weak_deps=False numactl-devel
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 --disable-libxml2 --disable-pci --disable-levelzero --disable-opencl --disable-cuda --disable-nvml --disable-libudev --disable-rsmi && make -j"$(nproc)" && make install)
export PKG_CONFIG_PATH=/work/hwloc-install/lib/pkgconfig
export LD_LIBRARY_PATH=/work/hwloc-install/lib
cmake -S . -B build-test -DCMAKE_BUILD_TYPE=Release -DUMF_BUILD_SHARED_LIBRARY=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON -DUMF_BUILD_CUDA_PROVIDER=ON -DUMF_BUILD_TESTS=ON -DUMF_BUILD_GPU_TESTS=OFF -DUMF_BUILD_EXAMPLES=ON -DUMF_BUILD_GPU_EXAMPLES=OFF -DUMF_BUILD_BENCHMARKS=OFF -DCMAKE_INSTALL_LIBDIR=lib
cmake --build build-test -j"$(nproc)"
# gotcha 553: TrackingProviderPoolTest/umfPoolTest.pow2AlignedAlloc and its
# multiThreaded variant both crash with SIGBUS on riscv64 under this doubly-nested
# tracking-provider stack (confirmed on separate CI runs: one crashed the
# single-threaded case, another the multi-threaded case, from the same shared
# pow2AlignedAllocHelper) -- skipped pending riscv64 hardware access to debug it
# interactively.
export GTEST_FILTER="-TrackingProviderPoolTest/umfPoolTest.pow2AlignedAlloc/*:TrackingProviderPoolTest/umfPoolTest.multiThreadedpow2AlignedAlloc/*"
ctest --test-dir build-test --output-on-failure -j2
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DUMF_BUILD_SHARED_LIBRARY=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON -DUMF_BUILD_CUDA_PROVIDER=ON -DUMF_BUILD_TESTS=OFF -DUMF_BUILD_EXAMPLES=OFF -DUMF_BUILD_BENCHMARKS=OFF -DCMAKE_INSTALL_LIBDIR=lib
cmake --build build -j"$(nproc)"
cmake --install build --prefix /work/install
mkdir -p dist_libs
cp -L install/lib/libumf.so* hwloc-install/lib/libhwloc.so* dist_libs/
for f in dist_libs/libumf.so*; do patchelf --set-rpath "\$ORIGIN" "$f"; done
strip dist_libs/*.so*
file dist_libs/*.so*
ldd dist_libs/libumf.so.1
cp LICENSE.TXT LICENSE.txt
cp licensing/third-party-programs.txt THIRD-PARTY-PROGRAMS.txt
cp "hwloc-${HWLOC_VERSION}/COPYING" LICENSE-hwloc.txt
cat > setup.py <<PYEOF
import glob
import os
from setuptools import setup


def walk(root, dest_prefix):
entries = []
for dirpath, _, filenames in os.walk(root):
if not filenames:
continue
rel = os.path.relpath(dirpath, root)
dest = dest_prefix if rel == "." else os.path.join(dest_prefix, rel)
entries.append((dest, sorted(os.path.join(dirpath, f) for f in filenames)))
return sorted(entries)


setup(
name="umf",
version=os.environ["UMF_VERSION"],
packages=[],
install_requires=["tcmlib>=1.5"],
description="Unified Memory Framework",
long_description="Intel(R) oneAPI Unified Memory Framework (UMF) riscv64 dynamic library, headers, and CMake package config for Linux, built from the Apache-2.0 licensed UMF source, bundling a BSD-3-Clause HWLOC build it depends on.",
url="https://github.com/oneapi-src/unified-memory-framework",
license="Apache-2.0",
license_files=["LICENSE.txt", "LICENSE-hwloc.txt", "THIRD-PARTY-PROGRAMS.txt"],
classifiers=[
"Operating System :: POSIX :: Linux",
"Topic :: Software Development :: Libraries",
],
data_files=(
walk("install/include", "include")
+ walk("install/lib/cmake", "lib/cmake")
+ [("lib", sorted(glob.glob("dist_libs/*.so*")))]
),
)
PYEOF
pybin=/opt/python/cp312-cp312/bin
"$pybin/pip" install -q -U setuptools wheel
"$pybin/python3" setup.py bdist_wheel --python-tag py2.py3 --plat-name manylinux_2_39_riscv64
# tcmlib (install_requires above) only has a riscv64 wheel on our own registry
# (gotcha 30/422), not on public PyPI -- this self-driven container gets none
# of the CIBW_ENVIRONMENT registry wiring other ports rely on, so it needs its
# own PIP_EXTRA_INDEX_URL here on the smoke-install step.
PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ "$pybin/pip" install -q dist/*.whl
"$pybin/python3" - <<PYEOF
import ctypes, os, sysconfig
libdir = os.path.join(sysconfig.get_path("data"), "lib")
umf = ctypes.CDLL(os.path.join(libdir, "libumf.so.1"))
umf.umfGetCurrentVersion.restype = ctypes.c_int
version = umf.umfGetCurrentVersion()
assert version == (1 << 16), version
print("smoke test OK: umfGetCurrentVersion() =", version)
PYEOF
'

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: umf-${{ env.UMF_VERSION }}-py2.py3-none-manylinux_riscv64
path: dist/*.whl
if-no-files-found: error

publish:
name: Publish umf ${{ matrix.version }}
needs: [setup, build_wheels]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
permissions:
contents: write
pull-requests: write
uses: $/.github/workflows/_publish-wheel.yml
secrets:
app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }}
with:
artifact-pattern: umf-${{ matrix.version }}-*-manylinux_riscv64
5 changes: 5 additions & 0 deletions docs/packages/umf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package-name: umf
source-code: https://github.com/oneapi-src/unified-memory-framework
license: Apache-2.0
versions:
- version: 1.1.0
Loading