Created a native extension of Ruby with Rust and published it as a gem

Until the other day, I was researching How to build a native extension of Ruby with Rust, but finally I was able to publish it as ruby ​​gems. I've given it a pretty bold name.

hello_rust_gem

RubyGems: https://rubygems.org/gems/hello_rust GitHub: https://github.com/irxground/hello_rust_gem (It would be very helpful if you could review the code !!)

This gem itself is meaningless, and I created it for the purpose of being a reference when I want to write a Ruby gem in Rust. hello_rust_gem does not depend on any other library. (However, libraries used during development such as rspec are excluded)

How to use

require "hello_rust"

p HelloRust::VERSION

Description of each file

src/lib.rs

This file is the body of Ruby's native extension. It's not a big deal because it only contains the definitions of the HelloRust module and the HelloRust :: VERSION constants. When writing a real native extension, you can extend it here.

Cargo.toml

Rust project definition. Only the crate-type = ["cdylib "] part is important

build.rs

I'm generating settings for linking the Ruby API from Rust code. build.rs is called automatically when you do cargo build.

lib/hello_rust.rb

This will be the file that will be read when you require" hello_rust " from the outside. If you suddenly load the native library, you may be in trouble when you want to write Ruby code, so it is good to make the first entrance a Ruby file. Rather, bundle gem --ext is so, so I followed it.

There is require" hello_rust/hello_rust " in it, but the native library is loaded in this part.

hello_rust.gemspec

A file to write RubyGems settings. This time, as an example, I tried to reuse the data written in Cargo.toml, but it is not necessary to do so. (However, updating the version number is easy to make a mistake, so it may be better to put it in one place as in this example)

The important part is spec.extensions = ["ext/Rakefile "] gem install will deploy the source code and then run ext/Rakefile to build the native extension.

Rakefile

Rakefile for the rake command used by developers Erase the artifacts with rake, build and run the test. Rust and Ruby formatters run on rake fmt. See rake -T for more.

ext/Rakefile

As written in gemspec, it is called during gem install. An environment variable called RUBYLIBDIR is passed, so place the native library there. This time, the file path will be $ RUBYLIBDIR/hello_rust/hello_rust.so (for Linux) so that it can be read byrequire "hello_rust/hello_rust".

ext/build_task.rb

When developing locally and when installing the gem, you will have to compile and place the library in the appropriate path, so I've summarized the common parts here.

When building on Windows, the RUSTUP_TOOLCHAIN environment variable is set. Ruby entered by RubyInstaller is mingw, but Rust on Windows can be selected from two types, mingw and msvc, so to force mingw.

other than that

The rest is tests, license files, etc. spec/hello_rust_spec.rb tests HelloRust :: VERSION, which is minimal but notices that the native library will fail to compile.

from now on

I have confirmed that it works on most platforms, so I would like to enhance CI.

Recommended Posts

Created a native extension of Ruby with Rust and published it as a gem
Create a native extension of Ruby in Rust
[Tutorial] [Ruby] Creating and debugging C native extension gem
Install Ruby 3.0.0 Preview 1 with a combination of Homebrew and rbenv
Extract a part of a string with Ruby
[Ruby] Arguments with keywords and default values of arguments
Experienced Ruby touches Rust and compares it Winter 2020
Ruby and Gem
Run Scala with GraalVM & make it a native image
[Ruby] I made a crawler with anemone and nokogiri.
Ruby / Rust integration (7) Create Rust extension gem built at installation
I searched for a web framework with Gem in Ruby
The nth and n + 1st characters of a Ruby string
The difference between programming with Ruby classes and programming without it
How to deal with different versions of rbenv and Ruby
Convert Excel to Blob with java, save it, read it from DB and output it as a file!
Graph the sensor information of Raspberry Pi in Java and check it with a web browser
Generate a serial number with Hibernate (JPA) TableGenerator and store it in the Id of String.
When installing a gem with C extension in Ruby, I want to finish it quickly using multiple CPU cores like make -j4