Oleg Antonyan
Oleg Antonyan

Reputation: 3113

How can I build a Rust library when installing a gem?

I'm building a gem with Rust and I need to know how to run the Rust compiler when installing the gem. With a C-extension, I can use mkmf to generate a Makefile. But how can I run cargo build --release?

The directory structure looks like this:

.
├── bin
│   ├── console
│   └── setup
├── CODE_OF_CONDUCT.md
├── Gemfile
├── Gemfile.lock
├── lib
│   ├── rmpd_adschedule
│   │   └── version.rb
│   └── rustgem.rb
├── LICENSE.txt
├── Rakefile
├── README.md
├── rustgem.gemspec
├── rust
│   ├── Cargo.lock
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
└── spec
    ├── rustgem.rb
    └── spec_helper.rb

I've created a Rake task to build the Rust library:

task :compile do
  sh "cd #{File.dirname(__FILE__)}/rust && cargo build --release"
end

But how to run this Rake task when installing the gem? Or how to generate a suitable Makefile with mkmf? The Makefile should look like this:

all:
    cd rust/ && cargo build --release

But it doesn't work if I put it into the root directory, and I don't know how to tell mkmf to generate this exact Makefile.

I found one stupid way to do this when the gem is loading:

module Rustgem
  system("cd #{File.dirname(__FILE__)}/../rust && cargo build --release")
end

But this is not a good solution.

Upvotes: 0

Views: 406

Answers (1)

Oleg Antonyan
Oleg Antonyan

Reputation: 3113

Turns out I can do this:

# rust/extconf.rb
require 'mkmf'
create_makefile 'rust/rustgem'
system("cd #{File.dirname(__FILE__)} && cargo build --release")

In this case, create_makefile will create an empty Makefile. Then make will return 0 make: Nothing to be done for 'all'. which is what we need, and then system call will do the work.

Or somewhat better:

require 'mkmf'
create_makefile 'rutgem'
File.write('Makefile', "all:\n\tcargo build --release\nclean:\n\trm -rf target\ninstall: ;")

I'm not sure if this is good solution. If you know a better one please tell it.

UPDATE Actually, you can put Makefile along with empty extconf.rb in the same directory and it will work. Blog post about Ruby-Rust integration: http://undefined-reference.org/2016/05/14/writing-rubygem-in-rust.html

Upvotes: 2

Related Questions