LoginSignup
3
2

More than 3 years have passed since last update.

Rubyのネイティブ拡張をRustで作成する

Posted at

昨日、Mac環境でRubyのネイティブ拡張を作る記事を投稿したが、WindowsとLinuxでも動く設定が確認できた。

構成

基本は前回と同じ。

まず変わったのは build.rs で、ライブラリ名もRubyのコンフィグからWin, Mac, Linux共通の値が取得できた。

build.rs
use std::process::Command;

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

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

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

次が Rakefile で、Windowsでも動かしやすいようにMakefileから変更した。
RustがサポートするWindows環境はmingwとmsvcがあるが、mingwを強制している。

Rakefile
require 'fileutils'
require 'json'

NAME = JSON.parse(`cargo metadata --format-version=1`).dig("packages", 0, "name")
TARGET_SO = "#{NAME}.#{RbConfig::CONFIG["DLEXT"]}"

desc "Delete artifacts"
task :clean do
  sh "cargo clean"
  FileUtils.rm_f(TARGET_SO)
end

desc "Create native extension"
task :build do
  env = {}
  case RUBY_PLATFORM
  when /mingw/
    env = {"RUSTUP_TOOLCHAIN" => "stable-#{RbConfig::CONFIG["host_cpu"]}-pc-windows-gnu"}
    cargo_out = "target/release/#{NAME}.dll"
  when /darwin/
    cargo_out = "target/release/lib#{NAME}.dylib"
  when /linux/
    cargo_out = "target/release/lib#{NAME}.so"
  else
    raise "Platform #{RUBY_PLATFORM} is not supported"
  end
  sh env, "cargo build --release"
  cp cargo_out, TARGET_SO, preserve: true, verbose: true
end

desc "Run Ruby script"
task :run => [:clean, :build] do
  ruby "run.rb"
end

他は変更なし

今後

gemとして公開するには gemspec 等が必要なので今後調べていくつもり。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2