Minimal configuration for creating Ruby native extensions in Rust (for now Mac only)

Currently, when writing native extensions to Ruby in Rust, it seems common to use rutie. (Helix and ruru are not maintained.) However, I personally didn't like it for the following reasons, so I investigated how to make a native extension of Ruby without relying on the library.

The code below is a sample that defines the HelloRust module on the Rust side.

Refer to Continued when running on Windows or Linux.

Source code solid paste

run.rb


require __dir__ + "/hello_rust"

if defined?(HelloRust)
  puts "HelloRust is defined"
else
  puts "HelloRust is not defined"
end

src/lib.rs


use std::ffi;

#[repr(transparent)]
pub struct Value(usize);

#[link(name = "ruby")]
extern "C" {
  fn rb_define_module(name: *const i8) -> Value;
}

fn define_module(name: &ffi::CStr) -> Value {
  unsafe { rb_define_module(name.as_ptr()) }
}

#[export_name = "Init_hello_rust"]
pub extern "C" fn init() {
  let s = ffi::CString::new("HelloRust").unwrap();
  define_module(&s);
}

build.rs


use std::process::Command;

fn libdir() -> String {
  let output = Command::new("ruby")
    .args(&["-e", "print RbConfig::CONFIG['libdir']"])
    .output()
    .expect("failed run ruby");

  return String::from_utf8(output.stdout).unwrap();
}

fn main() {
  println!("cargo:rustc-link-search={}", libdir());
}

Cargo.toml


[package]
name = "hello_rust"
version = "0.1.0"
authors = ["irxground"]
edition = "2018"

[lib]
crate-type = ["cdylib"]

Makefile


.PHONY: build
build: hello_rust.bundle

hello_rust.bundle: cargo_build
	cp -a target/release/libhello_rust.dylib $@

.PHONY: cargo_build
cargo_build:
	cargo build --release

.PHONY: run
run: clean build
	ruby run.rb

.PHONY: clean
clean:
	rm *.bundle
	cargo clean

Execution result

$ make run
rm *.bundle
cargo clean
cargo build --release
   Compiling hello_rust v0.1.0 (/Users/user/work/private/ruby_rust/minimam_rust_example)
    Finished release [optimized] target(s) in 0.75s
cp target/release/libhello_rust.dylib hello_rust.bundle
ruby run.rb
HelloRust is defined

Recommended Posts

Minimal configuration for creating Ruby native extensions in Rust (for now Mac only)
Create a native extension of Ruby in Rust