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
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
# ggml-spanker's build.rs runs bindgen over the in-tree
# spanker UAPI header. The GGML submodule itself is also
# pinned for forthcoming Q4_K layout cross-checks, so
# initialise submodules recursively.
submodules: recursive
- name: Install libclang for bindgen
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends libclang-dev
- name: Install Rust toolchain (MSRV per ADR-001)
uses: dtolnay/rust-toolchain@1.75.0
with:
Expand Down
4 changes: 3 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
path = external/ggml
url = https://github.com/ggml-org/ggml.git
shallow = true
branch = master
# Reproducibility anchor is the committed SHA — no `branch =`
# tracking, since `--remote` updates would undermine that anchor.
# When the upstream pin needs to move, bump the commit explicitly.
162 changes: 162 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 12 additions & 8 deletions src/backends/ggml/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ version = "0.1.0"
description = "GGML int4 matmul backend for the PopSolutions Sails."
keywords = ["ggml", "matmul", "popsolutions", "fpga"]
categories = ["hardware-support", "science"]
build = "build.rs"

edition.workspace = true
license.workspace = true
Expand All @@ -22,11 +23,14 @@ path = "src/lib.rs"
spanker-runtime = { path = "../../runtime" }
thiserror = { workspace = true }

# NOTE on bindgen — the upstream GGML submodule under
# external/ggml/ is pinned by this PR so that PR #5b can wire
# bindgen + a build.rs over `wrapper.h` once SailMatmul gains a
# real-device path. Bindgen itself is deferred from this PR
# because its transitive deps (home → rustc-hash) require Rust
# >= 1.81, conflicting with ADR-001's 1.75 MSRV. Resolution path:
# (a) wait for bindgen / home to publish back-compat releases, or
# (b) the ADR-001 amendment revisits MSRV in light of FFI needs.
[build-dependencies]
# bindgen 0.69 is the last release line that resolves cleanly
# under ADR-001's MSRV 1.75; newer bindgens drag in transitive
# crates (home / rustc-hash) that require Rust >= 1.81. The
# build.rs binds the spanker UAPI header (PING + GET_VERSION
# today; WORK_SUBMIT lands when the kernel driver gains it under
# Spanker #9 / DDR3 stream). Upstream GGML headers are NOT bound
# here yet because doing so would require cloning GGML's build
# graph; the Q4_K layout is cross-checked separately in
# `tests/q4_k_layout.rs` via a standalone C-side static_assert.
bindgen = { version = "0.69", default-features = false, features = ["runtime"] }
59 changes: 59 additions & 0 deletions src/backends/ggml/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2026 PopSolutions Cooperative

//! bindgen build script for `ggml-spanker`.
//!
//! Generates `$OUT_DIR/bindings.rs` from `wrapper.h`, which itself
//! `#include`s the spanker UAPI header at
//! `src/driver/include/uapi/spanker_ioctl.h`.
//!
//! See `wrapper.h` for the rationale on which symbols are bound
//! today vs deferred to the kernel-driver work-submit PR.

use std::env;
use std::path::PathBuf;

fn main() {
// Resolve the spanker UAPI header relative to this crate. The
// workspace layout is fixed (`src/backends/ggml/` ← crate,
// `src/driver/include/uapi/` ← UAPI), so we walk up three
// levels from CARGO_MANIFEST_DIR to land on the workspace
// root and then descend into the driver's include path.
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"));
let workspace_root = manifest_dir
.parent() // src/backends
.and_then(|p| p.parent()) // src
.and_then(|p| p.parent()) // workspace root
.expect("ggml-spanker is expected to live at <workspace>/src/backends/ggml")
.to_path_buf();
let uapi_dir = workspace_root.join("src/driver/include/uapi");
let wrapper = manifest_dir.join("wrapper.h");

// Tell cargo to re-run only when the inputs change.
println!("cargo:rerun-if-changed={}", wrapper.display());
println!(
"cargo:rerun-if-changed={}",
uapi_dir.join("spanker_ioctl.h").display()
);

let bindings = bindgen::Builder::default()
.header(wrapper.to_string_lossy())
.clang_arg(format!("-I{}", uapi_dir.display()))
// Allow the spanker UAPI symbols only — keeps the binding
// surface tight and avoids pulling in the host's libc /
// kernel headers transitively pulled by `<linux/types.h>`
// and `<linux/ioctl.h>`.
.allowlist_type("spanker_.*")
.allowlist_var("SPANKER_.*")
.derive_default(true)
.derive_debug(true)
.derive_copy(true)
.layout_tests(false)
.generate()
.expect("bindgen failed to generate spanker UAPI bindings");

let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR"));
bindings
.write_to_file(out_dir.join("bindings.rs"))
.expect("failed to write bindings.rs");
}
Loading
Loading