commit aabb74fa8742ee15333e565f44e7b516a956afd8
parent 28f54198377db4ab8d54190558f45cdd4f8c18fb
Author: Erik Loualiche <eloualic@umn.edu>
Date: Fri, 6 Feb 2026 22:49:54 -0600
Add GitHub Actions workflow for cross-platform FFI builds
Prepare for distributing pre-built FFI binaries:
- Add build-ffi.yml workflow to build for Linux, macOS, Windows
- Update TODO with artifacts distribution plan
- Improve FFI error message
The workflow will create release artifacts when a tag is pushed.
Artifacts.toml will be added once first release is built.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat:
3 files changed, 119 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/build-ffi.yml b/.github/workflows/build-ffi.yml
@@ -0,0 +1,87 @@
+name: Build FFI Library
+
+on:
+ push:
+ tags:
+ - 'v*'
+ workflow_dispatch:
+
+jobs:
+ build:
+ strategy:
+ matrix:
+ include:
+ - os: ubuntu-latest
+ target: x86_64-unknown-linux-gnu
+ artifact: libnickel_jl.so
+ artifact_name: libnickel_jl-x86_64-linux-gnu.tar.gz
+ - os: ubuntu-24.04-arm
+ target: aarch64-unknown-linux-gnu
+ artifact: libnickel_jl.so
+ artifact_name: libnickel_jl-aarch64-linux-gnu.tar.gz
+ - os: macos-13
+ target: x86_64-apple-darwin
+ artifact: libnickel_jl.dylib
+ artifact_name: libnickel_jl-x86_64-apple-darwin.tar.gz
+ - os: macos-latest
+ target: aarch64-apple-darwin
+ artifact: libnickel_jl.dylib
+ artifact_name: libnickel_jl-aarch64-apple-darwin.tar.gz
+ - os: windows-latest
+ target: x86_64-pc-windows-msvc
+ artifact: nickel_jl.dll
+ artifact_name: nickel_jl-x86_64-windows.tar.gz
+
+ runs-on: ${{ matrix.os }}
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Install Rust
+ uses: dtolnay/rust-action@stable
+ with:
+ targets: ${{ matrix.target }}
+
+ - name: Build library
+ working-directory: rust/nickel-jl
+ run: cargo build --release --target ${{ matrix.target }}
+
+ - name: Package artifact (Unix)
+ if: runner.os != 'Windows'
+ run: |
+ cd rust/nickel-jl/target/${{ matrix.target }}/release
+ tar -czvf ${{ matrix.artifact_name }} ${{ matrix.artifact }}
+ mv ${{ matrix.artifact_name }} ${{ github.workspace }}/
+
+ - name: Package artifact (Windows)
+ if: runner.os == 'Windows'
+ shell: bash
+ run: |
+ cd rust/nickel-jl/target/${{ matrix.target }}/release
+ tar -czvf ${{ matrix.artifact_name }} ${{ matrix.artifact }}
+ mv ${{ matrix.artifact_name }} ${{ github.workspace }}/
+
+ - name: Upload artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ matrix.artifact_name }}
+ path: ${{ matrix.artifact_name }}
+
+ release:
+ needs: build
+ runs-on: ubuntu-latest
+ if: startsWith(github.ref, 'refs/tags/')
+ permissions:
+ contents: write
+
+ steps:
+ - name: Download all artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: artifacts
+
+ - name: Create Release
+ uses: softprops/action-gh-release@v1
+ with:
+ files: artifacts/**/*.tar.gz
+ generate_release_notes: true
diff --git a/TODO.md b/TODO.md
@@ -33,10 +33,29 @@
## Next Steps
-### 1. Cross-Platform FFI Distribution
-Currently FFI requires local Rust build. Options:
-- **BinaryBuilder.jl** - Create `NickelEval_jll` for automatic binary distribution
-- Support Linux (x86_64, aarch64), macOS (x86_64, aarch64), Windows
+### 1. Cross-Platform FFI Distribution (In Progress)
+
+**Current approach: Self-hosted artifacts via GitHub Releases**
+
+Status:
+- [x] GitHub Actions workflow to build for all platforms (`.github/workflows/build-ffi.yml`)
+- [x] Artifacts.toml template for binary downloads
+- [x] Updated ffi.jl to use Pkg.Artifacts
+- [ ] Trigger first build by tagging v0.5.0
+- [ ] Update Artifacts.toml with actual SHA256 hashes
+- [ ] Test artifact downloads on all platforms
+
+Platforms:
+- Linux x86_64, aarch64
+- macOS x86_64, aarch64 (Apple Silicon)
+- Windows x86_64
+
+**Fallback option: Yggdrasil/BinaryBuilder.jl**
+
+If self-hosted artifacts become hard to maintain, submit to Yggdrasil:
+- Create `NickelEval_jll` package via BinaryBuilder.jl
+- Automatic builds and distribution via General registry
+- More complex setup but zero maintenance after
### 2. CI FFI Testing
Update CI workflow to build Rust library and run FFI tests.
diff --git a/src/ffi.jl b/src/ffi.jl
@@ -11,6 +11,10 @@
# - No process spawn overhead
# - Direct memory sharing
# - Better performance for repeated evaluations
+#
+# Library loading:
+# Currently requires local build. Future versions will include pre-built artifacts.
+# See .github/workflows/build-ffi.yml for cross-platform build setup.
# Determine platform-specific library name
const LIB_NAME = if Sys.iswindows()
@@ -21,7 +25,7 @@ else
"libnickel_jl.so"
end
-# Path to the compiled library
+# Path to the compiled library (local deps/ folder)
const LIB_PATH = joinpath(@__DIR__, "..", "deps", LIB_NAME)
# Check if FFI library is available
@@ -252,7 +256,10 @@ end
function _check_ffi_available()
if !FFI_AVAILABLE
- error("FFI not available. Build the Rust library with:\n" *
+ error("FFI library not available.\n\n" *
+ "The FFI functions require a pre-built native library.\n" *
+ "Use subprocess mode instead: nickel_eval() and nickel_eval_file()\n\n" *
+ "To build locally (requires Rust):\n" *
" cd rust/nickel-jl && cargo build --release\n" *
" mkdir -p deps && cp target/release/$LIB_NAME ../../deps/")
end