Skip to content

interop: modularize native bindings #120

interop: modularize native bindings

interop: modularize native bindings #120

Workflow file for this run

name: build-and-pack
permissions:
contents: read
packages: write
on:
push:
branches: [ main, master ]
tags: [ 'v*.*.*' ]
pull_request:
workflow_dispatch:
jobs:
native:
name: native-${{ matrix.rid }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
rid: linux-x64
libname: libratatui_ffi.so
target: x86_64-unknown-linux-gnu
- os: ubuntu-latest
rid: linux-arm64
libname: libratatui_ffi.so
target: aarch64-unknown-linux-gnu
- os: ubuntu-latest
rid: linux-musl-x64
libname: libratatui_ffi.so
target: x86_64-unknown-linux-musl
zigbuild: true
- os: windows-latest
rid: win-x64
libname: ratatui_ffi.dll
- os: windows-latest
rid: win-arm64
libname: ratatui_ffi.dll
target: aarch64-pc-windows-msvc
- os: macos-13
rid: osx-x64
libname: libratatui_ffi.dylib
- os: macos-14
rid: osx-arm64
libname: libratatui_ffi.dylib
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: dtolnay/rust-toolchain@stable
- name: Install toolchains (Linux)
if: ${{ runner.os == 'Linux' && matrix.target != '' }}
run: |
rustup target add ${{ matrix.target }}
if [[ "${{ matrix.target }}" == aarch64-unknown-linux-gnu ]]; then sudo apt-get update && sudo apt-get install -y gcc-aarch64-linux-gnu; fi
# Set cross-compile linker/archiver for aarch64 gnu
if [[ "${{ matrix.target }}" == aarch64-unknown-linux-gnu ]]; then \
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV; \
echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_AR=aarch64-linux-gnu-ar" >> $GITHUB_ENV; \
echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV; \
echo "AR_aarch64_unknown_linux_gnu=aarch64-linux-gnu-ar" >> $GITHUB_ENV; \
fi
- name: Setup zig (for musl cross)
if: ${{ runner.os == 'Linux' && matrix.zigbuild == true }}
uses: goto-bus-stop/setup-zig@v2
with:
version: 0.12.0
- name: Install cargo-zigbuild
if: ${{ runner.os == 'Linux' && matrix.zigbuild == true }}
run: cargo install cargo-zigbuild --locked
- name: Install toolchains (Windows)
if: ${{ runner.os == 'Windows' && matrix.target != '' }}
run: |
rustup target add ${{ matrix.target }}
- name: Setup MSVC dev-cmd (win-arm64)
if: ${{ runner.os == 'Windows' && matrix.rid == 'win-arm64' }}
uses: ilammy/msvc-dev-cmd@v1
with:
arch: amd64_arm64
- name: Build native (musl via zig)
if: ${{ runner.os == 'Linux' && matrix.zigbuild == true }}
working-directory: native/ratatui-ffi
shell: bash
env:
RUSTFLAGS: -C target-feature=-crt-static
run: |
cargo zigbuild --release --target ${{ matrix.target }}
- name: Build native (targeted)
if: ${{ (matrix.target != '') && !(runner.os == 'Linux' && matrix.zigbuild == true) }}
working-directory: native/ratatui-ffi
run: cargo build --release --target ${{ matrix.target }}
- name: Build native (default)
if: ${{ (matrix.target == '') && !(runner.os == 'Linux' && matrix.zigbuild == true) }}
working-directory: native/ratatui-ffi
run: cargo build --release
- name: Upload native artifact
uses: actions/upload-artifact@v4
with:
name: native-${{ matrix.rid }}
path: |
native/ratatui-ffi/target/release/${{ matrix.libname }}
native/ratatui-ffi/target/${{ matrix.target }}/release/${{ matrix.libname }}
if-no-files-found: warn
native-optional:
name: native-optional
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: dtolnay/rust-toolchain@stable
- uses: goto-bus-stop/setup-zig@v2
with:
version: 0.12.0
- name: Install cargo-zigbuild
run: cargo install cargo-zigbuild --locked
- name: Build linux-musl-arm64
working-directory: native/ratatui-ffi
env:
RUSTFLAGS: -C target-feature=-crt-static
run: |
rustup target add aarch64-unknown-linux-musl
cargo zigbuild --release --target aarch64-unknown-linux-musl
- name: Upload artifact linux-musl-arm64
uses: actions/upload-artifact@v4
with:
name: native-linux-musl-arm64
path: native/ratatui-ffi/target/aarch64-unknown-linux-musl/release/libratatui_ffi.so
pack:
name: pack-nuget
runs-on: ubuntu-latest
needs: [native, native-optional]
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Download native artifacts
uses: actions/download-artifact@v4
with:
path: native_out
- name: Prepare runtimes directory
shell: bash
run: |
set -euo pipefail
mkdir -p src/Ratatui/runtimes/linux-x64/native
mkdir -p src/Ratatui/runtimes/linux-arm64/native
mkdir -p src/Ratatui/runtimes/linux-musl-x64/native
mkdir -p src/Ratatui/runtimes/linux-musl-arm64/native
mkdir -p src/Ratatui/runtimes/win-x64/native
mkdir -p src/Ratatui/runtimes/win-arm64/native
mkdir -p src/Ratatui/runtimes/osx-x64/native
mkdir -p src/Ratatui/runtimes/osx-arm64/native
copy_first() { local dir="$1" name="$2" dest="$3"; local f; f=$(find "$dir" -type f -name "$name" | head -n1 || true); if [ -n "${f:-}" ]; then cp "$f" "$dest/"; else echo "warn: not found: $name in $dir"; fi; }
copy_first native_out/native-linux-x64 libratatui_ffi.so src/Ratatui/runtimes/linux-x64/native
copy_first native_out/native-linux-arm64 libratatui_ffi.so src/Ratatui/runtimes/linux-arm64/native
copy_first native_out/native-linux-musl-x64 libratatui_ffi.so src/Ratatui/runtimes/linux-musl-x64/native
copy_first native_out/native-linux-musl-arm64 libratatui_ffi.so src/Ratatui/runtimes/linux-musl-arm64/native
copy_first native_out/native-win-x64 ratatui_ffi.dll src/Ratatui/runtimes/win-x64/native
copy_first native_out/native-win-arm64 ratatui_ffi.dll src/Ratatui/runtimes/win-arm64/native
copy_first native_out/native-osx-x64 libratatui_ffi.dylib src/Ratatui/runtimes/osx-x64/native
copy_first native_out/native-osx-arm64 libratatui_ffi.dylib src/Ratatui/runtimes/osx-arm64/native
- name: Guard required runtimes exist
run: |
set -e
test -f src/Ratatui/runtimes/linux-x64/native/libratatui_ffi.so
test -f src/Ratatui/runtimes/win-x64/native/ratatui_ffi.dll
test -f src/Ratatui/runtimes/osx-arm64/native/libratatui_ffi.dylib
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Pack
run: |
VER=${{ github.ref_name }}
if [[ "$VER" == v* ]]; then VER=${VER#v}; else VER=0.1.0-ci.${{ github.run_number }}; fi
# Skip in-MSBuild FFI coverage to avoid parallel races; run it explicitly next.
dotnet pack src/Ratatui/Ratatui.csproj -c Release -o artifacts -p:PackageVersion=$VER -p:SkipFfiCoverage=true
- name: FFI coverage (CI)
shell: bash
run: |
set -euo pipefail
# Build the coverage tool once
dotnet build tools/BindingCoverage/BindingCoverage.csproj -c Release
TOOL=tools/BindingCoverage/bin/Release/net9.0/BindingCoverage.dll
ASM=src/Ratatui/bin/Release/net9.0/Ratatui.dll
# Run coverage check; fail build on mismatch
dotnet exec "$TOOL" --assembly "$ASM" --project-dir src/Ratatui --allow-extra
- name: Upload package
uses: actions/upload-artifact@v4
with:
name: nuget
path: artifacts/*.nupkg
- name: Ensure NUGET_API_KEY present (tags only)
if: ${{ github.ref_type == 'tag' }}
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: |
if [ -z "$NUGET_API_KEY" ]; then
echo "NUGET_API_KEY is not set for tag publish. Failing." >&2
exit 1
fi
- name: Publish to GitHub Packages (tag or main)
if: ${{ github.ref_type == 'tag' || github.ref_name == 'main' || github.ref_name == 'master' }}
env:
OWNER: ${{ github.repository_owner }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
for pkg in artifacts/*.nupkg; do
dotnet nuget push "$pkg" \
--source "https://nuget.pkg.github.com/${OWNER}/index.json" \
--api-key "$GITHUB_TOKEN" \
--skip-duplicate
done
- name: Publish to nuget.org (tags only)
if: ${{ github.ref_type == 'tag' }}
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
run: |
for pkg in artifacts/*.nupkg; do
dotnet nuget push "$pkg" \
--source "https://api.nuget.org/v3/index.json" \
--api-key "$NUGET_API_KEY" \
--skip-duplicate
done
- name: Create GitHub Release (attach NuGet)
if: ${{ github.ref_type == 'tag' }}
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: Ratatui.cs ${{ github.ref_name }}
generate_release_notes: true
files: |
artifacts/*.nupkg
aot-test:
name: aot-test
runs-on: ubuntu-latest
needs: pack
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Build native linux-x64 for local run
run: |
cd native/ratatui-ffi
cargo build --release
- name: Put native into sample runtime
run: |
mkdir -p examples/Aot/runtimes/linux-x64/native
cp native/ratatui-ffi/target/release/libratatui_ffi.so examples/Aot/runtimes/linux-x64/native/
- name: Publish AOT sample
run: |
dotnet publish examples/Aot/Aot.csproj -r linux-x64 -c Release