-
Notifications
You must be signed in to change notification settings - Fork 0
research build wiring extension crate
The gem needs a dedicated Rust crate at ext/duckling/ that compiles to a
native shared library (.so on Linux, .bundle on macOS). This is separate
from the duckling library crate, which stays as an rlib dependency.
Source: examples/rust_blank/ext/rust_blank/
The canonical Magnus example for a gem extension crate. Verified file list:
ext/rust_blank/
├── Cargo.lock
├── Cargo.toml
├── extconf.rb
└── src/
└── lib.rs
Note: no build.rs exists in this example crate. Magnus itself carries the
build.rs that calls rb_sys_env::activate() (at
build.rs),
and that runs when the extension depends on magnus as a crate.
Source: Cargo.toml
[package]
name = "duckling"
version = "0.4.0"
edition = "2021"There is no [lib] section, so the crate-type defaults to rlib. It is
suitable as a dependency of the extension crate.
The crate is published to crates.io as duckling — the package name
matches the crate name. Current crates.io version: 0.4.0 (published
2026-04-16). wafer-inc/duckling@c96b068
is also at 0.4.0, matching the published release.
crates.io: https://crates.io/crates/duckling
Repo: https://github.com/wafer-inc/duckling
Owner: Andre Popovitch (anchpop)
[package]
name = "rust_blank"
version = "0.1.0"
edition = "2024"
[lib]
crate-type = ["cdylib"]
[dependencies]
magnus = { path = "../../../.." }
# enable rb-sys feature to test against Ruby head. This is only needed if you
# want to work with the unreleased, in-development, next version of Ruby
rb-sys = { version = "*", default-features = false, features = ["stable-api-compiled-fallback"] }Key observations:
-
crate-type = ["cdylib"]is required — this produces.so/.bundle -
edition = "2024"(Rust 2024 edition) - rb-sys uses
stable-api-compiled-fallback: pre-compiled stable ABI bindings; no bindgen or libclang required at build time - No
[build-dependencies]orbuild.rs— Magnus's ownbuild.rshandlesrb_sys_env::activate()transitively when magnus is a dependency
[package]
name = "duckling_ext"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
magnus = { version = "0.9", features = ["rb-sys"] }
duckling = "0.4" # published on crates.io as "duckling" by wafer-inc/anchpop
rb-sys = { version = "*", default-features = false, features = ["stable-api-compiled-fallback"] }The rb-sys feature on the magnus dependency unlocks magnus::rb_sys utilities
and ensures the correct feature flags are activated in magnus.
ext/duckling/
├── Cargo.toml (cdylib crate, depends on magnus + duckling lib)
└── src/
└── lib.rs (#[magnus::init] fn init(...))
A build.rs may or may not be needed — see Open Questions below.
Based on the rust_blank #[magnus::init] pattern:
use magnus::{Error, Ruby};
#[magnus::init]
fn init(ruby: &Ruby) -> Result<(), Error> {
// Register Ruby classes/methods wrapping wafer-inc-duckling here
Ok(())
}-
Path vs. git dependency: duckling is not on crates.io.Resolved: The crate is published on crates.io asduckling = "0.4". Use the crates.io dep — no path or git dependency needed. wafer-inc/duckling@c96b068 is the development source for the same 0.4.0 release. -
Does duckling need to be published to crates.io?Resolved: Already published. No crates.io blocker for gem publication. -
Is a build.rs needed in ext/duckling/? The rust_blank example has NO
build.rs. Magnus's ownbuild.rscallsrb_sys_env::activate(), and Cargo propagates link metadata from dependency build scripts up to the final binary. This should be sufficient when depending on magnus from crates.io. If linking issues appear at compile time, adding abuild.rswithrb_sys_env::activate()to the extension crate itself would be the fix. Requires addingrb-sys-env = "0.2"to[build-dependencies]. -
Rust edition: rust_blank uses
edition = "2024"(requires rustc 1.85+). duckling usesedition = "2021". The extension crate can use either, but mixing editions in a workspace is allowed. Using 2024 aligns with the Magnus example.