以前このブログRust を利用して rubygems を作成した rust_uuidRuby 3.2 がリリース によりコンパイルできなくなったのでその修正顛末。

環境

system failed version succeed version
ruby 3.2.0 3.2.0
gem 3.4.1 3.4.2
bundler 2.3.19 2.4.2
rb-sys 0.9.29 0.9.53
magnus 0.3.2 0.4.4

what’s happened?

Ruby 3.2 が出てたのでアップデートして試してみるかーとおもいコマンドを実行!!!!

$ bundle exec rake build
.
.
...
error[E0425]: cannot find value `RUBY_ABI_VERSION` in the crate root
  --> /path/to/cargo/dir/registry/src/github.com-1ecc6299db9ec823/rb-sys-0.9.29/src/ruby_abi_version.rs:14:73
   |
14 | pub const __RB_SYS_RUBY_ABI_VERSION: std::os::raw::c_ulonglong = crate::RUBY_ABI_VERSION as _;
   |                                                                         ^^^^^^^^^^^^^^^^ not found in the crate root

For more information about this error, try `rustc --explain E0425`.
error: could not compile `rb-sys` due to previous error
warning: build failed, waiting for other jobs to finish...
gmake: *** [Makefile:564: target/release/librust_uuid.so] エラー 101
rake aborted!
Command failed with status (2): [/usr/bin/gmake...]
/path/to/rbenv/versions/3.2.0/bin/bundle:25:in `load'
/path/to/rbenv/versions/3.2.0/bin/bundle:25:in `<main>'
Tasks: TOP => build => compile => compile:x86_64-linux => compile:rust_uuid:x86_64-linux => copy:rust_uuid:x86_64-linux:3.2.0 => tmp/x86_64-linux/rust_uuid/3.2.0/rust_uuid.so
(See full trace by running task with --trace)
bundle exec rake build  63.55s user 10.61s system 541% cpu 13.705 total

おーなるほどなるほど、 cargorb-sysRuby 3.2 に対応していないバージョンつかってるんだなと理解。cargo を更新っするぞい。

うpだて cargo ぱっけーじ

ということで cargo build が通るようにパッケージを更新するぞい。 cargobundler 同様、 cargo update でいい感じにアップデートしてくれます。

$ cd ext/rust_uuid
$ cargo update
$ cargo build
   Compiling magnus v0.3.2
error[E0432]: unresolved import `crate::ruby_sys::ruby_rstring_consts`
  --> /path/to/cargo/dir/registry/src/github.com-1ecc6299db9ec823/magnus-0.3.2/src/r_string.rs:23:47
   |
23 | use crate::ruby_sys::{rb_str_to_interned_str, ruby_rstring_consts::RSTRING_EMBED_LEN_SHIFT};
   |                                               ^^^^^^^^^^^^^^^^^^^ could not find `ruby_rstring_consts` in `ruby_sys`

error[E0599]: no variant or associated item named `RSTRING_EMBED_LEN_MASK` found for enum `ruby_rstring_flags` in the current scope
   --> /path/to/cargo/dir/registry/src/github.com-1ecc6299db9ec823/magnus-0.3.2/src/r_string.rs:368:38
    |
368 |             f &= ruby_rstring_flags::RSTRING_EMBED_LEN_MASK as VALUE;
    |                                      ^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `ruby_rstring_flags`

error[E0599]: no variant or associated item named `RSTRING_EMBED_LEN_MASK` found for enum `ruby_rstring_flags` in the current scope
   --> /path/to/cargo/dir/registry/src/github.com-1ecc6299db9ec823/magnus-0.3.2/src/r_string.rs:968:42
    |
968 |                 f &= ruby_rstring_flags::RSTRING_EMBED_LEN_MASK as VALUE;
    |                                          ^^^^^^^^^^^^^^^^^^^^^^ variant or associated item not found in `ruby_rstring_flags`

Some errors have detailed explanations: E0432, E0599.
For more information about an error, try `rustc --explain E0432`.
error: could not compile `magnus` due to 3 previous errors

cargo update しましたが、やっぱり駄目でしたね。今度は magnus が駄目そう。 Cargo.toml を見てみると、 magnus = { version = "0.3", features = ["rb-sys-interop"] } と指定してあり、 version 0.3 系が駄目そうということが類推されます。ということで公式ページを見ると新しいバージョンが出ているのでこちらにします。

--- a/ext/rust_uuid/Cargo.toml
+++ b/ext/rust_uuid/Cargo.toml
@@ -10,7 +10,7 @@ crate-type = ["cdylib"]
 [dependencies]
 rb-sys = "0.9"
 rb-allocator = "0.9"
-magnus = { version = "0.3", features = ["rb-sys-interop"] }
+magnus = { version = "0.4", features = ["rb-sys-interop"] }

 [dependencies.uuid]
 version = "1.1.2"

再度ビルド!

$ cargo update
$ cargo build
   Compiling rust_uuid v0.1.0 (/home/katsyoshi/Program/Ruby/rust_uuid/ext/rust_uuid)
    Finished dev [unoptimized + debuginfo] target(s) in 0.18s

おおっ通りました!やったね!

build

ということ cargo build 通ったので gem install しましよう。

$ cd /path/to/rust_uuid
$ bundle exec rake build
cd tmp/x86_64-linux/rust_uuid/3.2.0
/usr/bin/gmake
generating target/release/librust_uuid.so (release)
cargo rustc --target-dir target --manifest-path ../../../../ext/rust_uuid/Cargo.toml --lib --release -- -C linker=gcc -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/home/katsyoshi/.local/lib:-L/home/katsyoshi/.local/lib: -C link-arg=-lm -l pthread
   Compiling libc v0.2.139
   Compiling proc-macro2 v1.0.49
   Compiling quote v1.0.23
   Compiling unicode-ident v1.0.6
   Compiling clang-sys v1.4.0
   Compiling regex-syntax v0.6.28
   Compiling syn v1.0.107
   Compiling rb-sys-env v0.1.1
   Compiling libloading v0.7.4
   Compiling nom v7.1.2
   Compiling aho-corasick v0.7.20
   Compiling magnus v0.4.4
   Compiling bindgen v0.60.1
   Compiling getrandom v0.2.8
   Compiling uuid v1.2.2
   Compiling cexpr v0.6.0
   Compiling regex v1.7.0
   Compiling magnus-macros v0.3.0
   Compiling rb-sys-build v0.9.53
   Compiling rb-sys v0.9.53
   Compiling rb-allocator v0.9.6
   Compiling rust_uuid v0.1.0 (/path/to/rust_uuid/ext/rust_uuid)
    Finished release [optimized] target(s) in 12.03s
cd -
mkdir -p tmp/x86_64-linux/stage/lib/rust_uuid
/usr/bin/gmake install target_prefix=
generating target/release/librust_uuid.so (release)
cargo rustc --target-dir target --manifest-path ../../../../ext/rust_uuid/Cargo.toml --lib --release -- -C linker=gcc -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/home/katsyoshi/.local/lib:-L/home/katsyoshi/.local/lib: -C link-arg=-lm -l pthread
    Finished release [optimized] target(s) in 0.02s
installing rust_uuid.so to /path/to/rust_uuid/lib/rust_uuid
/usr/bin/install -c -m 0755 rust_uuid.so /path/to/rust_uuid/lib/rust_uuid
cp tmp/x86_64-linux/rust_uuid/3.2.0/rust_uuid.so tmp/x86_64-linux/stage/lib/rust_uuid/rust_uuid.so
rake aborted!
Running `gem build -V /path/to/rust_uuid/rust_uuid.gemspec` failed with the following output:

WARNING:  description and summary are identical
WARNING:  open-ended dependency on benchmark-ips (>= 0, development) is not recommended
  use a bounded requirement, such as '~> x.y'
WARNING:  open-ended dependency on rake (>= 13.0.0, development) is not recommended
  if rake is semantically versioned, use:
    add_development_dependency 'rake', '~> 13.0', '>= 13.0.0'
WARNING:  open-ended dependency on rake-compiler (>= 0, development) is not recommended
  use a bounded requirement, such as '~> x.y'
WARNING:  open-ended dependency on rb_sys (>= 0, development) is not recommended
  use a bounded requirement, such as '~> x.y'
WARNING:  open-ended dependency on rspec (>= 0, development) is not recommended
  use a bounded requirement, such as '~> x.y'
WARNING:  See https://guides.rubygems.org/specification-reference/ for help
ERROR:  While executing gem ... (Gem::InvalidSpecificationException)
    You have specified rust based extension, but Cargo.lock is not part of the gem files. Please run `cargo generate-lockfile` or any other command to generate Cargo.lock and ensure it is added to your gem files section in gemspec.

/path/to/rbenv/versions/3.2.0/bin/bundle:25:in `load'
/path/to/rbenv/versions/3.2.0/bin/bundle:25:in `<main>'
Tasks: TOP => build
(See full trace by running task with --trace)
bundle exec rake build  32.87s user 4.33s system 291% cpu 12.741 total

なるほど? Cargo.lock ファイルもあるし問題なさそうだな。よくわからんので rubygems のリポジトリでエラーメッセージを探してみます。

すると以下のようなコード

  def validate_rust_extensions(builder) # :nodoc:
    rust_extension = @specification.extensions.any? {|s| builder.builder_for(s).is_a? Gem::Ext::CargoBuilder }
    missing_cargo_lock = !@specification.files.include?("Cargo.lock")

    error <<-ERROR if rust_extension && missing_cargo_lock
You have specified rust based extension, but Cargo.lock is not part of the gem files. Please run `cargo generate-lockfile` or any other command to generate Cargo.lock and ensure it is added to your gem files section in gemspec.
    ERROR
  end

なろほどなろほど、プロジェクトの root 直下に置いておく必要があるのね。でもそのファイルどういうものなの?

gem, bundler update

ってなわけで、今度は正式に rubygems で正式にサポートされ、 bundler でも gem を作成するときにも bundle gem --ext=rust gem_nameスケルトンが作成されるようになりました。ということでこれを利用して Cargo.toml を作ってみましょう

$ bundle gem --mit --ext=rust gem_name
ERROR: "bundle gem" was called with arguments ["rust", "gem_name"]
Usage: "bundle gem NAME [OPTIONS]"

ok, ok, これは bundler のバージョンが古いな

$ bundle version
Bundler version 2.3.19 (2022-07-27 commit 4f496f93e6)

さっきの PR は入ったのは Ruby 3.2 リリース直前なのでまだ入ってないよなとおもったけど、実際は Gemfile.lockBUNDLED WITH2.3.19 を指定してるだけだったのです。 なので対象の 2 行を削除して bundle update を実行し、続いて rust サポートした gem を生成して、 Cargo.toml を見てみましょう。

$ bundle gem --mit --ext=rust gem_name
Creating gem 'gem_name'...
MIT License enabled in config
Changelog enabled in config
Initializing git repo in /path/to/rust_uuid/gem_name
      create  gem_name/Gemfile
      create  gem_name/lib/gem_name.rb
      create  gem_name/lib/gem_name/version.rb
      create  gem_name/sig/gem_name.rbs
      create  gem_name/gem_name.gemspec
      create  gem_name/Rakefile
      create  gem_name/README.md
      create  gem_name/bin/console
      create  gem_name/bin/setup
      create  gem_name/.gitignore
      create  gem_name/.github/workflows/main.yml
      create  gem_name/LICENSE.txt
      create  gem_name/CHANGELOG.md
      create  gem_name/Cargo.toml
      create  gem_name/ext/gem_name/Cargo.toml
      create  gem_name/ext/gem_name/extconf.rb
      create  gem_name/ext/gem_name/src/lib.rs
Gem 'gem_name' was successfully created. For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html
$ cat Cargo.toml
# This Cargo.toml is here to let externals tools (IDEs, etc.) know that this is
# a Rust project. Your extensions depedencies should be added to the Cargo.toml
# in the ext/ directory.

[workspace]
members = ["./ext/gem_name"]
resolver = "2"

というようなファイルが得られるので真似して作成しちゃいましょう。

[workspace]
members = ["./ext/rust_uuid"]
resolver = "2"

そうしたらもう一度ビルドしてしまいます!

$ cargo generate-lockfile
$ git add Cargo.toml Carog.lock
$ bundle exec rake build
/usr/bin/gmake install target_prefix=
generating target/release/librust_uuid.so (release)
cargo rustc --target-dir target --manifest-path ../../../../ext/rust_uuid/Cargo.toml --lib --release -- -C linker=gcc -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/home/katsyoshi/.local/lib:-L/home/katsyoshi/.local/lib: -C link-arg=-lm -l pthread
   Compiling rust_uuid v0.1.0 (/path/to/rust_uuid/ext/rust_uuid)
    Finished release [optimized] target(s) in 0.26s
installing rust_uuid.so to /path/to/rust_uuid/lib/rust_uuid
/usr/bin/install -c -m 0755 rust_uuid.so /path/to/rust_uuid/lib/rust_uuid
cp tmp/x86_64-linux/rust_uuid/3.2.0/rust_uuid.so tmp/x86_64-linux/stage/lib/rust_uuid/rust_uuid.so
rust_uuid 0.1.0 built to pkg/rust_uuid-0.1.0.gem.
$ bundle exec rake install
/usr/bin/gmake install target_prefix=
generating target/release/librust_uuid.so (release)
cargo rustc --target-dir target --manifest-path ../../../../ext/rust_uuid/Cargo.toml --lib --release -- -C linker=gcc -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/path/to/rbenv/versions/3.2.0/lib -L native=/home/katsyoshi/.local/lib:-L/home/katsyoshi/.local/lib: -C link-arg=-lm -l pthread
    Finished release [optimized] target(s) in 0.03s
installing rust_uuid.so to /path/to/rust_uuid/lib/rust_uuid
/usr/bin/install -c -m 0755 rust_uuid.so /path/to/rust_uuid/lib/rust_uuid
cp tmp/x86_64-linux/rust_uuid/3.2.0/rust_uuid.so tmp/x86_64-linux/stage/lib/rust_uuid/rust_uuid.so
$ bundle exec ruby -rrust_uuid -e 'puts RustUUID.v4'
2eb053de-8ae7-4669-853b-95f06c872300

ようやっと通ったああぁあ!!!!

conclusion

実際は11月の末あたりに head でコンパイルできないなあと気がついていたのですが、そのうち直るやろと思っててなにもしなかったのです。いざ Ruby 3.2 がリリースされたときに試して動かなかったのでやっと対応してみました。

ということで正式に Rust がサポートされるようになったのでまた YARUKI がでてきますね。

それはそうと今度は、jekyllRuby 3.2 で動かなくなった。