From 96f102f8d0722085707f1161200d803fd3272bfa Mon Sep 17 00:00:00 2001 From: Mason Rowe Date: Sat, 31 Oct 2026 00:56:40 -0400 Subject: [PATCH] add riscv64 to fio/iperf3 binary build workflows (#97) --- .github/workflows/build-fio.yml | 25 +++++++++++++++++++++---- .github/workflows/build-iperf3.yml | 24 +++++++++++++++++++++--- bin/README.md | 16 +++++++++++++--- bin/cross-compile.sh | 9 ++++++--- 4 files changed, 61 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build-fio.yml b/.github/workflows/build-fio.yml index 9e101fc..cb60223 100644 --- a/.github/workflows/build-fio.yml +++ b/.github/workflows/build-fio.yml @@ -2,6 +2,11 @@ name: Build fio Static Binaries on: workflow_dispatch: + inputs: + force: + description: 'Rebuild even if a release for the latest upstream version already exists (e.g. to add a new architecture)' + type: boolean + default: false schedule: # check upstream for a new fio release once a day - cron: '23 5 * * *' @@ -36,8 +41,15 @@ jobs: # Check if this version already exists in our releases (upstream tag is # already prefixed, e.g. "fio-3.41", so it can be used as-is) if gh release view "$VERSION" --repo ${{ github.repository }} >/dev/null 2>&1; then - echo "Version $VERSION already exists in releases" - echo "should-build=false" >> $GITHUB_OUTPUT + # an existing release normally skips the build, but a manual dispatch with + # force=true rebuilds anyway (e.g. to add a new architecture to the assets) + if [ "${{ inputs.force }}" = "true" ]; then + echo "Version $VERSION already exists but force rebuild requested" + echo "should-build=true" >> $GITHUB_OUTPUT + else + echo "Version $VERSION already exists in releases" + echo "should-build=false" >> $GITHUB_OUTPUT + fi else echo "Version $VERSION does not exist, should build" echo "should-build=true" >> $GITHUB_OUTPUT @@ -65,6 +77,9 @@ jobs: - arch: arm cross: arm-linux-musleabihf host: arm-linux-gnueabihf + - arch: riscv64 + cross: riscv64-linux-musl + host: riscv64-linux-gnu steps: - name: Create compilation script @@ -113,8 +128,9 @@ jobs: # redefines struct prctl_mm_map under musl; sys/prctl.h alone is sufficient sed -i '/#include /d' backend.c CC=/root/$CROSS-cross/bin/$CROSS-gcc ./configure --disable-native --build-static - # link against libatomic for 32-bit/ARM targets that lack native 64-bit atomics - make EXTLIBS+=' -latomic' + # link against libatomic for 32-bit/ARM targets that lack native 64-bit atomics; -no-pie forces a + # classic static executable on default-PIE toolchains (riscv64), where a static-PIE fails to link + make EXTLIBS+=' -latomic -no-pie' # verify no external shared library links libcheck fio @@ -326,6 +342,7 @@ jobs: - `fio_x86` - i686 (32-bit) - `fio_aarch64` - ARM 64-bit - `fio_arm` - ARM 32-bit + - `fio_riscv64` - RISC-V 64-bit **Security Verification:** All binaries have been scanned by VirusTotal and verified clean. diff --git a/.github/workflows/build-iperf3.yml b/.github/workflows/build-iperf3.yml index ddb05a5..eaba75a 100644 --- a/.github/workflows/build-iperf3.yml +++ b/.github/workflows/build-iperf3.yml @@ -2,6 +2,11 @@ name: Build iperf3 Static Binaries on: workflow_dispatch: + inputs: + force: + description: 'Rebuild even if a release for the latest upstream version already exists (e.g. to add a new architecture)' + type: boolean + default: false schedule: # check upstream for a new iperf3 release once a day - cron: '47 5 * * *' @@ -35,8 +40,15 @@ jobs: # Check if this version already exists in our releases if gh release view "iperf3-$VERSION" --repo ${{ github.repository }} >/dev/null 2>&1; then - echo "Version $VERSION already exists in releases" - echo "should-build=false" >> $GITHUB_OUTPUT + # an existing release normally skips the build, but a manual dispatch with + # force=true rebuilds anyway (e.g. to add a new architecture to the assets) + if [ "${{ inputs.force }}" = "true" ]; then + echo "Version $VERSION already exists but force rebuild requested" + echo "should-build=true" >> $GITHUB_OUTPUT + else + echo "Version $VERSION already exists in releases" + echo "should-build=false" >> $GITHUB_OUTPUT + fi else echo "Version $VERSION does not exist, should build" echo "should-build=true" >> $GITHUB_OUTPUT @@ -67,6 +79,9 @@ jobs: - arch: arm cross: arm-linux-musleabihf host: arm-linux-gnueabihf + - arch: riscv64 + cross: riscv64-linux-musl + host: riscv64-linux-gnu steps: - name: Create compilation script @@ -104,7 +119,9 @@ jobs: curl -L -4 --retry 5 --retry-delay 2 --connect-timeout 15 "https://github.com/esnet/iperf/archive/$VERSION.tar.gz" -o "iperf.tar.gz" tar xf iperf.tar.gz cd iperf-* - CC=/root/$CROSS-cross/bin/$CROSS-gcc ./configure --disable-shared --disable-profiling --build x86_64-pc-linux-gnu --host "$HOST" --with-openssl=no --enable-static-bin + # -no-pie must be set via LDFLAGS at configure time (passing it to make overrides automake's LDFLAGS and + # drops --static); on default-PIE toolchains (riscv64) a static-PIE iperf3 links but segfaults at runtime + LDFLAGS="${LDFLAGS} -no-pie" CC=/root/$CROSS-cross/bin/$CROSS-gcc ./configure --disable-shared --disable-profiling --build x86_64-pc-linux-gnu --host "$HOST" --with-openssl=no --enable-static-bin # remove libatomic.la so libtool links the static libatomic.a rather than # attempting to link libatomic.so into the static binary (breaks arm32 builds) rm -f /root/$CROSS-cross/$CROSS/lib/libatomic.la @@ -349,6 +366,7 @@ jobs: - `iperf3_x86` - i686 (32-bit) - `iperf3_aarch64` - ARM 64-bit - `iperf3_arm` - ARM 32-bit (if available) + - `iperf3_riscv64` - RISC-V 64-bit ${{ steps.check-arm.outputs.arm-note }} diff --git a/bin/README.md b/bin/README.md index 05a5b8e..cc37b99 100644 --- a/bin/README.md +++ b/bin/README.md @@ -7,8 +7,8 @@ repository** - they are built automatically by GitHub Actions workflows [build-iperf3.yml](../.github/workflows/build-iperf3.yml)) on GitHub-hosted runners and published as release assets on this repository: -* `fio-*` releases (e.g. `fio-3.42`) - contain `fio_x64`, `fio_x86`, `fio_aarch64`, `fio_arm` -* `iperf3-*` releases (e.g. `iperf3-3.21`) - contain `iperf3_x64`, `iperf3_x86`, `iperf3_aarch64`, `iperf3_arm` +* `fio-*` releases (e.g. `fio-3.42`) - contain `fio_x64`, `fio_x86`, `fio_aarch64`, `fio_arm`, `fio_riscv64` +* `iperf3-*` releases (e.g. `iperf3-3.21`) - contain `iperf3_x64`, `iperf3_x86`, `iperf3_aarch64`, `iperf3_arm`, `iperf3_riscv64` * `toolchains` release - musl cross-compilation toolchains mirrored from [musl.cc](https://musl.cc/) (which blocks GitHub Actions IP ranges); see the NOTICE.txt asset for licensing/source info @@ -33,7 +33,7 @@ issue if the binaries are out of date and lacking any security-related and/or performance updates - the daily scheduled workflows should pick up new upstream releases automatically. -Note: ARM compatibility is considered experimental. +Note: ARM and RISC-V compatibility is considered experimental. ### Compile Notes (manual builds) @@ -57,6 +57,10 @@ Compilation of 32-bit and ARM-compatible binaries requires additional environment variables to identify the proper musl toolchain and architecture to target for cross-compilation. +The musl.cc riscv64 toolchain is default-PIE, so the scripts pass `-no-pie` to +produce classic static executables (a static-PIE fio fails to link, and a +static-PIE iperf3 links but segfaults at runtime). + **Compiling 32-bit x86 binaries**: ```sh @@ -74,3 +78,9 @@ docker run -t -i --rm -v `pwd`:/io --env ARCH=aarch64 --env CROSS=aarch64-linux- ```sh docker run -t -i --rm -v `pwd`:/io --env ARCH=arm --env CROSS=arm-linux-musleabihf --env HOST=arm-linux-gnueabihf phusion/holy-build-box-64:latest bash /io/cross-compile.sh ``` + +**Compiling RISC-V 64-bit binaries**: + +```sh +docker run -t -i --rm -v `pwd`:/io --env ARCH=riscv64 --env CROSS=riscv64-linux-musl --env HOST=riscv64-linux-gnu phusion/holy-build-box-64:latest bash /io/cross-compile.sh +``` diff --git a/bin/cross-compile.sh b/bin/cross-compile.sh index 183a522..41dbe2e 100755 --- a/bin/cross-compile.sh +++ b/bin/cross-compile.sh @@ -39,8 +39,9 @@ cd fio-fio-* # conflicts under musl; sys/prctl.h alone is sufficient sed -i '/#include /d' backend.c CC=/root/${CROSS}-cross/bin/${CROSS}-gcc ./configure --disable-native --build-static -# link against libatomic for 32-bit/ARM targets that lack native 64-bit atomics -make EXTLIBS+=' -latomic' +# link against libatomic for 32-bit/ARM targets that lack native 64-bit atomics; -no-pie forces a +# classic static executable on default-PIE toolchains (riscv64), where a static-PIE fails to link +make EXTLIBS+=' -latomic -no-pie' # verify no external shared library links libcheck fio @@ -52,7 +53,9 @@ cd ~ curl -L https://github.com/esnet/iperf/archive/3.21.tar.gz -o "iperf.tar.gz" tar xf iperf.tar.gz cd iperf-* -CC=/root/${CROSS}-cross/bin/${CROSS}-gcc ./configure --disable-shared --disable-profiling --build x86_64-pc-linux-gnu --host "${HOST}" --with-openssl=no --enable-static-bin +# -no-pie must be set via LDFLAGS at configure time (passing it to make overrides automake's LDFLAGS and +# drops --static); on default-PIE toolchains (riscv64) a static-PIE iperf3 links but segfaults at runtime +LDFLAGS="${LDFLAGS} -no-pie" CC=/root/${CROSS}-cross/bin/${CROSS}-gcc ./configure --disable-shared --disable-profiling --build x86_64-pc-linux-gnu --host "${HOST}" --with-openssl=no --enable-static-bin # remove libatomic.la so libtool links the static libatomic.a rather than # attempting to link libatomic.so into the static binary (breaks arm32 builds) rm -f "/root/${CROSS}-cross/${CROSS}/lib/libatomic.la"