-
-
Save briankung/d250368e9552dc730c6608727556197d to your computer and use it in GitHub Desktop.
sneak-preview-writing-ruby-gem-native-extensions-in-rust
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ git clone --branch cargo-builder git@github.com:ianks/rubygems.git | |
Cloning into 'rubygems'... | |
remote: Enumerating objects: 224785, done. | |
remote: Counting objects: 100% (5/5), done. | |
remote: Compressing objects: 100% (2/2), done. | |
remote: Total 224785 (delta 3), reused 3 (delta 3), pack-reused 224780 | |
Receiving objects: 100% (224785/224785), 191.82 MiB | 38.18 MiB/s, done. | |
Resolving deltas: 100% (124370/124370), done. | |
$ cd rubygems |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export RUBYGEMS_PATH="$(pwd)" | |
alias gem="ruby -I$RUBYGEMS_PATH/lib $RUBYGEMS_PATH/bin/gem" | |
alias bundle="ruby $RUBYGEMS_PATH/bundler/spec/support/bundle.rb" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ gem --version | |
3.4.0.dev | |
$ bundler --version | |
Bundler version 2.4.0.dev |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ git clone https://github.com/briankung/rust_ruby_example | |
$ cd rust_ruby_example |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ gem build rust_ruby_example.gemspec --output rust_ruby_example.gem | |
WARNING: licenses is empty, but is recommended. Use a license identifier from | |
http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. | |
WARNING: no homepage specified | |
WARNING: See https://guides.rubygems.org/specification-reference/ for help | |
Successfully built RubyGem | |
Name: rust_ruby_example | |
Version: 0.1.0 | |
File: rust_ruby_example.gem |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ gem install rust_ruby_example.gem | |
Building native extensions. This could take a while... | |
Successfully installed rust_ruby_example-0.1.0 | |
1 gem installed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ gem install rust_ruby_example.gem | |
Building native extensions. This could take a while... | |
ERROR: Error installing rust_ruby_example.gem: | |
ERROR: Failed to build gem native extension. | |
current directory: /Users/brian/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/rust_ruby_example-0.1.0 | |
cargo rustc --target-dir /Users/brian/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/extensions/x86_64-darwin-21/3.0.0/rust_ruby_example-0.1.0 --manifest-path /Users/brian/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/rust_ruby_example-0.1.0/Cargo.toml --lib --release --locked -- -C linker\=clang -C link-arg\=-fdeclspec -L native\=/Users/brian/.rbenv/versions/3.0.0/lib -L native\=/Users/brian/.rbenv/versions/3.0.0/lib -L native\=/usr/local/opt/icu4c/lib -C link_arg\=-Wl,-undefined,dynamic_lookup -C link_arg\=-Wl,-multiply_defined,suppress -C debuginfo\=1 | |
cargo failedNo such file or directory - cargo | |
Gem files will remain installed in /Users/brian/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/rust_ruby_example-0.1.0 for inspection. | |
Results logged to /Users/brian/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/extensions/x86_64-darwin-21/3.0.0/rust_ruby_example-0.1.0/gem_make.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ gem install rust_ruby_example.gem | |
Building native extensions. This could take a while... | |
ERROR: Error installing rust_ruby_example.gem: | |
ERROR: Failed to build gem native extension. | |
No builder for extension 'Cargo.toml' | |
Gem files will remain installed in /Library/Ruby/Gems/2.6.0/gems/rust_ruby_example-0.1.0 for inspection. | |
Results logged to /Library/Ruby/Gems/2.6.0/extensions/universal-darwin-21/2.6.0/rust_ruby_example-0.1.0/gem_make.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[no_mangle] | |
unsafe extern "C" fn pub_reverse(_klass: VALUE, mut input: VALUE) -> VALUE { | |
let ruby_string = cstr_to_string(rb_string_value_cstr(&mut input)); | |
let reversed = ruby_string.to_string().chars().rev().collect::<String>(); | |
let reversed_cstring = CString::new(reversed).unwrap(); | |
let size = ruby_string.len() as c_long; | |
rb_utf8_str_new(reversed_cstring.as_ptr(), size) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let reversed = ruby_string.to_string().chars().rev().collect::<String>(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let name = CString::new("RustRubyExample").unwrap(); | |
// ... | |
let klass = unsafe { rb_define_module(name.as_ptr()) }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Name of the function | |
let function_name = CString::new("reverse").unwrap(); | |
// transmute the function for unknown reasons | |
let callback = unsafe { | |
std::mem::transmute::< | |
unsafe extern "C" fn(VALUE, VALUE) -> VALUE, | |
unsafe extern "C" fn() -> VALUE, | |
>(pub_reverse) | |
}; | |
// ...Bind the transmuted function as a module function on the RustRubyExample module | |
unsafe { rb_define_module_function(klass, function_name.as_ptr(), Some(callback), 1) } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ gem install rust_ruby_example.gem | |
Building native extensions. This could take a while... | |
Successfully installed rust_ruby_example-0.1.0 | |
1 gem installed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ irb | |
irb(main):001:0' require 'rust_ruby_example' | |
=> true | |
irb(main):002:0> RustRubyExample.reverse("rust_ruby_example") | |
=> "elpmaxe_ybur_tsur" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ irb | |
irb(main):001:0' require 'rust_ruby_example' | |
=> true | |
irb(main):002:0> RustRubyExample.lowercase("RustRubyExample") | |
=> "rustrubyexample" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ irb | |
irb(main):001:0> require 'rust_ruby_example' | |
=> true | |
irb(main):002:0> RustRubyExample.lowercase("RustRubyExample") | |
Traceback (most recent call last): | |
4: from /Users/brian/.rbenv/versions/3.0.0/bin/irb:23:in `<main>' | |
3: from /Users/brian/.rbenv/versions/3.0.0/bin/irb:23:in `load' | |
2: from /Users/brian/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/irb-1.3.0/exe/irb:11:in `<top (required)>' | |
1: from (irb):2:in `<main>' | |
NoMethodError (undefined method `lowercase' for RustRubyExample:Module) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// in src/lib.rs | |
#[no_mangle] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// in src/lib.rs | |
#[no_mangle] | |
unsafe extern "C" fn pub_lowercase(_klass: VALUE, mut input: VALUE) -> VALUE { | |
// ... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// in src/lib.rs | |
#[no_mangle] | |
unsafe extern "C" fn pub_lowercase(_klass: VALUE, mut input: VALUE) -> VALUE { | |
let ruby_string = cstr_to_string(rb_string_value_cstr(&mut input)); | |
let lowercased = ruby_string.to_lowercase(); | |
// ... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// in src/lib.rs | |
#[no_mangle] | |
unsafe extern "C" fn pub_lowercase(_klass: VALUE, mut input: VALUE) -> VALUE { | |
let ruby_string = cstr_to_string(rb_string_value_cstr(&mut input)); | |
let lowercased = ruby_string.to_lowercase(); | |
let lowercased_cstring = CString::new(lowercased).unwrap(); | |
let size = ruby_string.len() as c_long; | |
rb_utf8_str_new(lowercased_cstring.as_ptr(), size) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// in src/lib.rs | |
#[allow(non_snake_case)] | |
#[no_mangle] | |
pub extern "C" fn Init_rust_ruby_example() { | |
let name = CString::new("RustRubyExample").unwrap(); | |
// ...Code for defining "RustRubyExample#reverse" omitted | |
let function_name = CString::new("lowercase").unwrap(); | |
let callback = unsafe { | |
std::mem::transmute::< | |
unsafe extern "C" fn(VALUE, VALUE) -> VALUE, | |
unsafe extern "C" fn() -> VALUE, | |
>(pub_lowercase) | |
}; | |
let klass = unsafe { rb_define_module(name.as_ptr()) }; | |
unsafe { rb_define_module_function(klass, function_name.as_ptr(), Some(callback), 1) } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ gem build rust_ruby_example.gemspec --output rust_ruby_example.gem | |
// Warnings omitted | |
Successfully built RubyGem | |
Name: rust_ruby_example | |
Version: 0.1.0 | |
File: rust_ruby_example.gem | |
$ gem install rust_ruby_example.gem | |
Building native extensions. This could take a while... | |
Successfully installed rust_ruby_example-0.1.0 | |
1 gem installed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ irb | |
irb(main):001:0> require 'rust_ruby_example' | |
=> true | |
irb(main):002:1* RustRubyExample.lowercase("RustRubyExample") | |
=> "rustrubyexample" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment