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
250 changes: 250 additions & 0 deletions .github/workflows/build-austin-dist.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on: https://github.com/P403n1x87/austin/blob/v4.0.0/.github/workflows/release_arch.yml
# and https://github.com/P403n1x87/austin/blob/v4.0.0/.github/workflows/tests.yml
name: Build austin-dist wheels (riscv64)

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

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

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

env:
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64
UV_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/
# austin-python pins protobuf~=3.12 and our registry only carries 7.x, which
# first-index resolution stops at.
UV_INDEX_STRATEGY: unsafe-best-match

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

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

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

steps:
- name: Checkout austin v${{ matrix.version }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: P403n1x87/austin
ref: v${{ env.AUSTIN_DIST_VERSION }}
persist-credentials: false

- name: Checkout python-wheels
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: python-wheels
persist-credentials: false

- name: Apply patches
run: git apply -v python-wheels/patches/austin-dist/${{ env.AUSTIN_DIST_VERSION }}/*.patch

# The wheel carries austin alone, the way upstream's musl wheels do:
# austinp's native unwinding segfaults on riscv64, in austin's own MOJO
# emitter and inside libunwind's riscv64 symbol lookup.
- name: Build austin and package the wheel
run: |
docker run --rm \
-v "$(pwd)":/workspace \
--workdir /workspace \
-e AUSTIN_DIST_VERSION \
"${{ env.MANYLINUX_RISCV64_IMAGE }}" \
bash -c '
set -euxo pipefail
dnf -y --disablerepo=extras install autoconf automake
autoreconf --install
./configure
make -j"$(nproc)"
/opt/python/cp312-cp312/bin/python -m pip install -q wheel
/opt/python/cp312-cp312/bin/python scripts/build-wheel.py \
--version "$AUSTIN_DIST_VERSION" \
--platform manylinux_2_39_riscv64 \
--files austin:src/austin
'

- name: Verify the wheel ships the riscv64 binary
run: |
python3 - dist/*.whl <<'EOF'
import sys, zipfile
with zipfile.ZipFile(sys.argv[1]) as zf:
names = zf.namelist()
print("\n".join(names))
scripts = sorted(n.rsplit("/", 1)[-1] for n in names if ".data/scripts/" in n)
assert scripts == ["austin"], scripts
licenses = sorted(n.rsplit("/", 1)[-1] for n in names if ".dist-info/licenses/" in n)
assert licenses == ["LICENSE.md"], licenses
header = zf.read(next(n for n in names if ".data/scripts/" in n))[:20]
assert header[:4] == b"\x7fELF", header
assert header[18] == 0xF3, header
EOF

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

test_wheel:
name: Test austin-dist ${{ matrix.version }} on Python ${{ matrix.python-version }}
needs: [setup, build_wheel]
if: needs.setup.outputs.versions != '[]'
runs-on: ubuntu-24.04-riscv
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
# Upstream tests 3.9 to 3.14; trimmed to the interpreters this registry targets.
python-version: ['3.12', '3.13', '3.14']

env:
AUSTIN_DIST_VERSION: ${{ matrix.version }}
AUSTIN_TESTS_PYTHON_VERSIONS: ${{ matrix.python-version }}

steps:
- name: Checkout austin v${{ matrix.version }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: P403n1x87/austin
ref: v${{ env.AUSTIN_DIST_VERSION }}
persist-credentials: false

- name: Checkout python-wheels
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: python-wheels
persist-credentials: false

- name: Apply patches
run: git apply -v python-wheels/patches/austin-dist/${{ env.AUSTIN_DIST_VERSION }}/*.patch

- name: Download wheel
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: austin-dist-${{ env.AUSTIN_DIST_VERSION }}-py3-none-manylinux_riscv64
path: wheelhouse

- name: Install Python
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
python-version: ${{ matrix.python-version }}
activate-environment: true
enable-cache: false

- name: Install the wheel and upstream's test dependencies
run: uv pip install -r test/requirements.txt wheelhouse/*.whl

# The suite runs the binary from src/, which is where upstream's own test
# jobs download it to; here it comes out of the installed wheel.
- name: Stage the wheel's binary
run: cp "$(command -v austin)" src/

# Upstream's own test jobs do this so that the suite can print a
# backtrace of a crashed austin process.
- name: Enable crash diagnostics
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq --no-install-recommends gdb
echo "core.%p" | sudo tee /proc/sys/kernel/core_pattern

- name: Run upstream's tests
run: |
ulimit -c unlimited
python -m pytest -svr a test/functional test/integrity

# test_where_multiprocess asserts that a single -w snapshot catches both
# children inside fact(); upstream marks it flaky and these runners are
# slow enough to lose that race on every attempt.
- name: Run upstream's tests as root
run: |
ulimit -c unlimited
sudo -E env PATH="$PATH" python -m pytest -svr a test/functional test/integrity \
--deselect test/functional/test_attach.py::test_where_multiprocess

gpl_sources:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Collect GPL sources for austin-dist ${{ matrix.version }}
runs-on: ubuntu-24.04-riscv

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

steps:
- name: Checkout python-wheels
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- uses: ./actions/collect-gpl-sources
with:
image: ${{ env.MANYLINUX_RISCV64_IMAGE }}
packages: gcc
output: gpl-sources.tar

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: austin-dist-${{ env.AUSTIN_DIST_VERSION }}-gpl-sources
path: gpl-sources.tar
if-no-files-found: error

publish:
name: Publish austin-dist ${{ matrix.version }}
needs: [setup, build_wheel, test_wheel, gpl_sources]
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: austin-dist-${{ matrix.version }}-py3-none-manylinux_riscv64
gpl-sources-artifact: austin-dist-${{ matrix.version }}-gpl-sources
gpl-sources-description: gcc
11 changes: 11 additions & 0 deletions docs/packages/austin-dist.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package-name: austin-dist
source-code: https://github.com/P403n1x87/austin
license: GPL-3.0-or-later
versions:
- version: 4.0.0
patched: true
warning: >-
The riscv64 wheel ships the austin binary only, as upstream's musllinux wheels do.
austinp, the variant that also samples native stacks, segfaults on riscv64 while
sampling: once in austin's own MOJO emitter, and once inside libunwind's riscv64
ELF symbol lookup.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Mon, 21 Sep 2026 00:00:00 +0000
Subject: [PATCH] build-wheel: add a riscv64 Linux wheel platform

scripts/build-wheel.py drives --platform off the AUSTIN_WHEELS table, so a
platform missing from it cannot be built at all:

build-wheel.py: error: argument --platform: invalid choice: 'manylinux_2_39_riscv64'

Add the riscv64 entry. manylinux_2_39 is the oldest manylinux profile that
exists for riscv64 (glibc 2.39, Rocky 10). The wheel carries austin alone, as
the musl wheels do: austinp needs libunwind to walk native stacks, and on
riscv64 both austin's MOJO emitter and libunwind's own ELF symbol lookup
segfault while it samples.

Upstream-Status: To upstream [the release asset this entry names, austin-<version>-gnu-linux-riscv64.tar.xz, is not produced by upstream yet, so the table entry is only useful there together with a riscv64 leg in release_arch.yml; the port builds the binary from source and passes it with --files]

Signed-off-by: Ludovic Henry <git@ludovic.dev>
---
diff --git a/scripts/build-wheel.py b/scripts/build-wheel.py
--- a/scripts/build-wheel.py
+++ b/scripts/build-wheel.py
@@ -53,6 +53,7 @@ AUSTIN_WHEELS = {
"gnu-linux-ppc64le.tar.xz",
("austin", "austinp"),
),
+ "manylinux_2_39_riscv64": ("gnu-linux-riscv64.tar.xz", ("austin",)),
"macosx_11_0_x86_64": ("mac64.zip", ("austin",)),
"macosx_11_0_arm64": ("mac-arm64.zip", ("austin",)),
"musllinux_1_1_aarch64": ("musl-linux-aarch64.tar.xz", ("austin",)),
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Mon, 21 Sep 2026 00:00:00 +0000
Subject: [PATCH] build-wheel: ship the licence files in the wheel

The wheels ship the austin and austinp binaries, and austin is GPL-3.0, but
no copy of the licence travels with them: the only trace of it is the
"License: GPLv3+" metadata field. Section 4 of the GPL asks whoever
distributes the program to hand out the licence text with it, and the
binaries also carry statically linked third-party code (libunwind, and
binutils' libbfd, libiberty and libsframe for austinp) whose licences belong
in the wheel too.

Write every file named by the new --licenses option into
<dist-info>/licenses/ and declare it with License-File, which needs
Metadata-Version 2.4 (PEP 639). The default keeps the project's own
LICENSE.md in every wheel.

Upstream-Status: To upstream [not yet submitted]

Signed-off-by: Ludovic Henry <git@ludovic.dev>
---
diff --git a/scripts/build-wheel.py b/scripts/build-wheel.py
--- a/scripts/build-wheel.py
+++ b/scripts/build-wheel.py
@@ -80,7 +80,7 @@ def make_message(headers, payload=None):
return message.getvalue().encode("utf-8")


-def write_austin_wheel(out_dir, *, version, platform, austin_bin_data):
+def write_austin_wheel(out_dir, *, version, platform, austin_bin_data, license_files):
package_name = "austin-dist"
python = "py3"
dist_name = package_name.replace("-", "_")
@@ -99,10 +99,11 @@ def write_austin_wheel(out_dir, *, version, platform, austin_bin_data):

contents[f"{dist_info}/METADATA"] = make_message(
{
- "Metadata-Version": "2.1",
+ "Metadata-Version": "2.4",
"Name": package_name,
"Version": version,
**METADATA,
+ "License-File": [_.name for _ in license_files],
},
Path("README.md")
.read_text("utf-8")
@@ -111,6 +112,9 @@ def write_austin_wheel(out_dir, *, version, platform, austin_bin_data):
'img src="https://raw.githubusercontent.com/P403n1x87/austin/refs/heads/master/art',
),
)
+ for license_file in license_files:
+ contents[f"{dist_info}/licenses/{license_file.name}"] = license_file.read_bytes()
+
contents[f"{dist_info}/WHEEL"] = make_message(
{
"Wheel-Version": "1.0",
@@ -179,6 +183,14 @@ if __name__ == "__main__":
default=None,
)

+ argp.add_argument(
+ "--licenses",
+ help="Licence files to ship in the wheel",
+ nargs="+",
+ type=Path,
+ default=[Path("LICENSE.md")],
+ )
+
argp.add_argument(
"--files",
help="The variant to binary file mapping (e.g. austin:src/austin)",
@@ -215,4 +227,5 @@ if __name__ == "__main__":
version=version,
platform=platform,
austin_bin_data=bin_data,
+ license_files=args.licenses,
)
Loading
Loading