“The Tie Between Ruby and Rust.”

Overview

Rutie

Build Status Maintenance GitHub contributors license crates.io version

Rutie — /ro͞oˈˌtī/rOOˈˌtI/rüˈˌtaI/

Integrate Ruby with your Rust application. Or integrate Rust with your Ruby application. This project allows you to do either with relative ease.

You are highly encouraged to read the source code for this project. Every method that has been mapped from Ruby for public use in src/class/* is very well documented with example code. This is the best way to take off running with Rutie. There are also integration examples in the examples directory which are based off of this README.

This project is a continuation of:

Index

Using Ruby in Rust

First add the dependency to your Cargo.toml file.

[dependencies]
rutie = "0.8.2"

Then in your Rust program add VM::init() to the beginning of its code execution path and begin to use Rutie.

extern crate rutie;

use rutie::{Object, RString, VM};

fn try_it(s: &str) -> String {
    let a = RString::new_utf8(s);

    // The `send` method returns an AnyObject type.
    let b = unsafe { a.send("reverse", &[]) };

    // We must try to convert the AnyObject
    // type back to our usable type.
    match b.try_convert_to::<RString>() {
        Ok(ruby_string) => ruby_string.to_string(),
        Err(_) => "Fail!".to_string(),
    }
}

#[test]
fn it_works() {

    // Rust projects must start the Ruby VM
    VM::init();

    assert_eq!("selppa", try_it("apples"));
}

fn main() {}

NOTE: Currently in Linux you need to set LD_LIBRARY_PATH to point at the directory of your current Ruby library and in Mac you need to set DYLD_LIBRARY_PATH with that info. You can get the path information with the following command:

ruby -e "puts RbConfig::CONFIG['libdir']"

This should let you run cargo test and cargo run.

Running cargo test should have this test pass.

Using Rust in Ruby

You can start a Ruby project with bundle gem rutie_ruby_example and then once you change into that directory run cargo init --lib. Remove the TODOs from the gemspec file. Add Rutie to the Cargo.toml file and define the lib type.

[dependencies]
rutie = {version="xxx"}

[lib]
name = "rutie_ruby_example"
crate-type = ["cdylib"]

Then edit your src/lib.rs file for your Rutie code.

#[macro_use]
extern crate rutie;

use rutie::{Class, Object, RString, VM};

class!(RutieExample);

methods!(
    RutieExample,
    _rtself,

    fn pub_reverse(input: RString) -> RString {
        let ruby_string = input.
          map_err(|e| VM::raise_ex(e) ).
          unwrap();

        RString::new_utf8(
          &ruby_string.
          to_string().
          chars().
          rev().
          collect::<String>()
        )
    }
);

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn Init_rutie_ruby_example() {
    Class::new("RutieExample", None).define(|klass| {
        klass.def_self("reverse", pub_reverse);
    });
}

And that's it for the Rust side. When using the methods! macro or extern functions make sure the method name won't clash with any others. This is why this example is prefixed with pub_.

Now you just need to load the library in Ruby. Add the rutie gem to your gemspec or Gemfile.

# gemspec
spec.add_dependency 'rutie', '~> 0.0.3'

# Gemfile
gem 'rutie', '~> 0.0.3'

And then load the library in your main project file lib/rutie_ruby_example.rb.

require 'rutie_ruby_example/version'
require 'rutie'

module RutieRubyExample
  Rutie.new(:rutie_ruby_example).init 'Init_rutie_ruby_example', __dir__
end

That's all you need to load your Ruby things from Rust. Now to write the test in test/rutie_ruby_example_test.rb:

require "test_helper"

class RutieRubyExampleTest < Minitest::Test
  def test_it_reverses
    assert_equal "selppa", RutieExample.reverse("apples")
  end
end

And to properly test it you will always need to run cargo build --release whenever you make any changes to the Rust code. Run the test with:

cargo build --release; rake test

Or better yet change your Rakefile to always run the cargo build --release before every test suite run. Feel free to change the test input to prove it fails because the above test works as is.

Custom Ruby Objects in Rust

To create a Ruby object in Rust that can be returned directly to Ruby it needs just a few simple things.

Here's an example excerpt of code from FasterPath.

use rutie::types::{ Value, ValueType };
use rutie::{ RString, AnyObject, Object, Class, VerifiedObject };

pub struct Pathname {
    value: Value
}

impl Pathname {
    pub fn new(path: &str) -> Pathname {
        let arguments = [RString::new_utf8(path).to_any_object()];
        let instance = Class::from_existing("Pathname").new_instance(Some(&arguments));

        Pathname { value: instance.value() }
    }

    pub fn to_any_object(&self) -> AnyObject {
        AnyObject::from(self.value())
    }
}

impl From<Value> for Pathname {
    fn from(value: Value) -> Self {
        Pathname { value }
    }
}

impl Object for Pathname {
    #[inline]
    fn value(&self) -> Value {
        self.value
    }
}

impl VerifiedObject for Pathname {
    fn is_correct_type<T: Object>(object: &T) -> bool {
        Class::from_existing("Pathname").case_equals(object)
    }

    fn error_message() -> &'static str {
        "Error converting to Pathname"
    }
}

If the class does not yet exist in Ruby you'll need to account for creating it before generating a new instance of it. This object is now compatible to be returned into Ruby directly from Rust/Rutie. Note that this definition is merely a Rust compatible representation of the Ruby object and doesn't define any Ruby methods which can be used from Ruby.

Variadic Functions / Splat Operator

A preferred way to integrate a dynamic amount of parameters has not yet been implemented in Rutie, but you can still manage to get it done in the following way.

use rutie::{AnyObject, Array};
use rutie::types::{Argc, Value};
use rutie::util::str_to_cstring;
use rutie::rubysys::class;
use std::mem;

pub extern fn example_method(argc: Argc, argv: *const AnyObject, _rtself: AnyObject) -> AnyObject {
    let args = Value::from(0);

    unsafe {
        let p_argv: *const Value = mem::transmute(argv);

        class::rb_scan_args(
            argc,
            p_argv,
            str_to_cstring("*").as_ptr(),
            &args
        )
    };

    let arguments = Array::from(args);

    let output = // YOUR CODE HERE.  Use arguments as you see fit.

    output.to_any_object()
}

This style of code is meant to be used outside of the methods! macro for now. You may place this method on a class or module as you normally would from a methods! macro definition.

#[macro_use]
extern crate rutie;

use rutie::{Class, Object, VM};

class!(Example);

// Code from above

fn main() {
    VM::init();
    Class::new("Example", None).define(|klass| {
        klass.def("example_method", example_method);
    });
}

The Rutie project has in its plans to remove the need for anyone to write unsafe code for variadic support and will likely be updating the methods! macro to support this natively.

Migrating from Ruru to Rutie

<0.1

For using Rutie versions less than 0.1 the change is simple. Replace all occurrences of the string ruru with rutie in your program. And if you would like to use ruby-sys code from Rutie rather than requiring ruby-sys you can change all existing references to ruby_sys to rutie::rubysys.

0.1

You will have additional considerations to change like Error being removed. For that; change instances of type ruru::result::Error to rutie::AnyException.

0.2

Migrated parse_arguments from VM to util.

0.3

Internal changes util from binding and rubysys have been replaced to reduce confusion and reduce duplication.

Safety — The Rutie Philosophy vs The Rust Philosophy on Safety

I'm writing this section to bring to light that, as of this writing, the safety that Rust likes to guarantee for its crates and the Rutie crate aren't currently aligned. The typical Rust safety for libraries wrapping C code is to have one unsafe crate with a -sys extension in its name and then a crate that wraps that to make it safe.

Rutie is an official fork of the project Ruru and because of this a great deal of the decisions in design for the project remain unchanged. Rutie also brought in the ruby-sys crate and treats it as an internal private API/module; and yet shares it openly for other developers to have full control to design their own API on top of it.

One of the glaring things that Rutie has that goes against the Rust Philosophy on Safety is that any of the methods that call Ruby code, can potentially raise an exception, and don't return the type Option<AnyObject, AnyException> will panic when an exception is raised from Ruby… which kills the application process running. The way to avoid panics is simple: either guarantee the Ruby code you're running will never raise an exception, or Handling exceptions raised from Ruby in Rust code with "protect" methods that return the type Option<AnyObject, AnyException>. Anyone can implement this safety by reading and understanding how the protect methods are written in this library and working with them.

The important thing to consider as to “why doesn't every method guarantee the safety as Rust would prescribe to?” is that exception handling in Ruby is not a zero cost abstraction. So there is a cost in performance when you need to implement it. One can easily argue that the guarantee of safety is far more important than leaving the risk in the hands of inexperienced developers. But one could also argue that it is better to leave the choice of performance cost, and the fact that exception capturing is occasionally unnecessary, up to the developer. Seeing how the legacy of design decisions is largely inherited this project leans towards the latter argument where the choice of being absolutely safe everywhere vs some extra speed in performance is up to the developer.

I'm not opposed to this project being 100% safe, but that will be a major change and a totally different API with many decisions that need to come into play. Also since this project doesn't strictly adhere to Rust safety principles, as a crate library would be expected to be, this project will not reach the stable 1.0 release as the idea of stability and safety are hand in hand.

I do like safety guarantees and as much as possible new features and language APIs will be built toward this. You can see what the design of a safe API would look like by examing the Enumerator features that have been implemented in this way (largely wrapping method names with calls to protect_send).

Troubleshooting

It panics for some Rubies on CI server tests

Sometimes the Ruby binary built isn't the best for the system. Be sure to compile Ruby for that system if this is the issue. With RVM do rvm reinstall --disable-binary with your choice of Ruby version.

Rust signal: 11, SIGSEGV: invalid memory reference

This is an indication that you haven't started a Ruby VM in Rust yet with VM::init();. Do this once before using Ruby code from Rust.

Error while loading shared libraries: libruby.so.#.#: cannot open shared object file: No such file or directory

This happens when the Rutie build is trying to link with libruby, but it's not found on your library search path. Either add it to LD_LIBRARY_PATH/DYLD_LIBRARY_PATH if you're building a standalone program that calls VM::init(), or if you're building a library to load into a running Ruby VM then you can disable linking by either setting the environment variable NO_LINK_RUTIE, or enabling the cargo feature no-link for Rutie in your Cargo.toml like this:

[dependencies]
rutie = {version="xxx", features=["no-link"]}

Calling methods from other methods within the methods! macro doesn't work

The way the macro is designed doesn't use the same parameter signatures you've provided and therefore it is recommended to implement any methods you want to re-use in Rust with functions outside of the methods! macro. You can simply call that new external method in the methods! macro when defining methods for Ruby to use.

Handling exceptions raised from Ruby in Rust code

If you're using any method that doesn't return a Result<AnyObject, AnyException> then any exception raised from the Ruby side will interfere with that Ruby thread and cause Rust to panic and stop. Ruby internally uses exceptions to effect the entire thread through an internal thread global value. To handle places where Ruby may raise an exception during Rust code execution you should use methods that are designed to handle that.

  • VM::eval
  • Object.protect_send
  • Object.protect_public_send

If you are writing lower level code and want to work more directly with the internal Ruby exception you may use VM::protect and read the source code for Object.protect_send to see how it's done.

Segfault during GC when using a Ruby method written in C

One possible issue that may cause this is when you store an item in Rust in heap memory rather than the stack.

An example case that caused this issue is the following:

Class::from_existing("Pathname").new_instance(&vec![RString::new_utf8(path).to_any_object()])

Ruby's GC traces objects from the stack. Rust's Vec, on the other hand, stores elements in the heap. So Ruby's GC may not be able to find the string you created and may release it. — @irxground

To rememdy the issue it required not using Vec but rather Rust's array type to store the argument on the stack rather than the heap.

let arguments = [RString::new_utf8(path).to_any_object()];
Class::from_existing("Pathname").new_instance(&arguments)

Operating System Requirements

Everything is tested against 64 bit operating systems with 64 bit Ruby & Rust builds. 32 bit isn't currently supported.

Linux & Mac

  • Rust 1.26 or later
  • Ruby (64 bit) 2.5 or later

NOTE: Known issues with Ruby 3.0 compatiility with the GC. GC#mark, GC#is_marked, GC#marked_locations do not work with Ruby 3.

Windows

  • Rust 1.26 or later
  • Ruby 2.5+ built with MingW (64 bit)
  • MS Visual Studio (Build Tools)

Dynamic vs Static Builds

Ruby needs to be compiled with the --enable shared option. Dynamic linking to the Ruby library provides the best performance and best support. Static build support is incomplete for now.

If using RBENV then the following is recommended:

CONFIGURE_OPTS=--enable-shared rbenv install 2.7.1

You can check if your Ruby is compiled to be dynamically linked to by running the following and getting a "yes" response.

ruby -e "pp RbConfig::CONFIG['ENABLE_SHARED']"

If you still run into ld: library not found for -lruby-static issue, try running cargo clean. This'll clean any artifacts from previous attempts.

If you'd like to make a pull request for adding static build support there are currently 3 methods not working with it and linking to the proper name of the ruby static lib file & path needs to be updated.

Contributing

Contributors are welcome!

The code is organized in 3 main layers. The rubysys folder is the raw mapping to Ruby C code and all the methods from there are unsafe. The binding folder is where we wrap those methods to abstract away all the unsafe methods to safe methods. The class folder is where the public API is implemented for using Ruby with Rust code. These methods in the class folder must all be documented and tested within the documentation. There is a subfolder under class for traits called traits.

Macros for abstracting away complexity are in src/dsl.rs.

Ruby's helper gem is in the submodule folder gem.

Rutie's Future

Rutie will continue to be improved upon to be more and more compatible with every aspect of Ruby. It will also gradually change toward Rust safety, semantics, and best practices.

I imagine a future where Rutie is the stepping stone that helps Ruby switch from C to Rust.

SemVer

As this package has taken 1.0 to mean both stable and safe and won't likely make a 1.0, then there can be breaking changes expected in each MINOR version update. These MINOR version breaking changes will occur in the public API of src/class/* and src/helpers/*. For private APIs there can be breaking changes in each PATCH version update which includes src/rubysys/*, src/binding/*, and src/util.rs.

Additional Project History

If you need some more examples of usage or the git blame history please look at the Ruru project as Rutie has had the README completely rewritten and this first git commit is from Ruru. Note that there are some fundamental changes which that README won't account for. This project also had ruby-sys merged in which may have some additional beneficial git history.

LICENSE

Both projects that were merged into this project contained identifiers under the MIT license. This project follows with the same licensing. ruby-sys marked MIT as the license in the Cargo.toml file whereas ruru had that and included a LICENSE file. This projects LICENSE has credited the original author by preserving the MIT license author line and appending new author(s) which is permitted by the MIT LICENSE.

MIT LICENSE — see LICENSE

Comments
  • Remove Option wrapper around arguments that are passed to ruby functions

    Remove Option wrapper around arguments that are passed to ruby functions

    Remove Option wrapper around arguments that are passed to ruby functions

    Instead of passing None use &[] when no arguments are needed.

    ~~Since is it not possible to dynamically allocate a slice, we should allow to pass vectors as arguments that are used to call ruby functions.~~

    ~~This allows to dynamically define the arguments in rust as vectors.~~

    ~~Due to the generic type calling those functions with no arguments (None) requires to define the type for T even though it is not used.~~

    @danielpclark What do you think about changing the signatures to this?

    fn send<T>(&self, method: &str, arguments: &T) -> AnyObject
        where
            T: AsRef<[AnyObject]>
    

    I think object.send("method", &[]) would write and read nicer than object.send::<&[AnyObject]>("method", None)

    opened by dsander 27
  • Thread::call_with_gvl causes pointer being freed was not allocated

    Thread::call_with_gvl causes pointer being freed was not allocated

    Hi,

    I am using rutie to create a ruby gem for a rust library that basically fetches units of work from a server and then calls ruby classes to process those units. To make concurrent I am using Thread::call_without_gvl to release the GVL while doing network operations in rust and then Thread::call_with_gvl to make ruby calls. I could probably restructure the code to avoid the call_with_gvl call, but the 'static requirement for the closures makes it a bit tricky.

    When calling the method below from ruby it fails with

    ruby(9818,0x117bcb5c0) malloc: *** error for object 0x7fa850ef40a0: pointer being freed was not allocated
    ruby(9818,0x117bcb5c0) malloc: *** set a breakpoint in malloc_error_break to debug
    

    The weird thing is that the rust test works without issues.

    Rust source
    #[macro_use]
    extern crate rutie;
    
    use rutie::{Class, Object, RString, Thread, VM};
    
    class!(RutieExample);
    
    methods!(
        RutieExample,
        _itself,
        fn work(_input: RString) -> RString {
            let worker_class = "Object".to_string();
            let b = Thread::call_without_gvl(
                move || {
                    // Releasing the GVL here to do network IO
                    // After we fetched a unit of work I wanto to call a ruby object
                    Thread::call_with_gvl(move || {
                        // Uncommenting this line "fixes" the issue
                        // let worker_class = "Object".to_string();
                        let ruby_worker = Class::from_existing(&worker_class);
                        ruby_worker.send("name", None)
                    })
                },
                Some(|| {}),
            );
    
            match b.try_convert_to::<RString>() {
                Ok(ruby_string) => ruby_string,
                Err(_) => RString::new_utf8("Fail!"),
            }
        }
    );
    
    #[allow(non_snake_case)]
    #[no_mangle]
    pub extern "C" fn Init_rutie_ruby_example() {
        Class::new("RutieExample", None).define(|itself| {
            itself.def_self("work", work);
        });
    }
    
    #[test]
    fn it_works() {
        // Rust projects must start the Ruby VM
        VM::init();
    
        Init_rutie_ruby_example();
    
        let ruby_worker = Class::from_existing("RutieExample");
        let res = ruby_worker.send("work", None);
    
        let res = match res.try_convert_to::<RString>() {
            Ok(ruby_string) => ruby_string,
            Err(_) => RString::new_utf8("Fail!"),
        };
        assert_eq!("Object", &res.to_string());
    }
    
    
    lldb stack strace
    Current executable set to '~/.rbenv/versions/2.5.3/bin/ruby' (x86_64).
    (lldb) breakpoint set --name malloc_error_break
    Breakpoint 1: where = libsystem_malloc.dylib`malloc_error_break, address = 0x00000000000170de
    (lldb) run -Ilib fail.rb
    Process 8370 launched: '/Users/dominik/.rbenv/versions/2.5.3/bin/ruby' (x86_64)
    ruby(8370,0x1000b95c0) malloc: *** error for object 0x10070d790: pointer being freed was not allocated
    ruby(8370,0x1000b95c0) malloc: *** set a breakpoint in malloc_error_break to debug
    Process 8370 stopped
    * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
        frame #0: 0x00007fff5e9a00de libsystem_malloc.dylib`malloc_error_break
    libsystem_malloc.dylib`malloc_error_break:
    ->  0x7fff5e9a00de <+0>: pushq  %rbp
        0x7fff5e9a00df <+1>: movq   %rsp, %rbp
        0x7fff5e9a00e2 <+4>: nop
        0x7fff5e9a00e3 <+5>: nopl   (%rax)
    Target 0: (ruby) stopped.
    (lldb) up
    frame #1: 0x00007fff5e993676 libsystem_malloc.dylib`malloc_vreport + 437
    libsystem_malloc.dylib`malloc_vreport:
        0x7fff5e993676 <+437>: cmpb   $0x1, 0x32c47d6f(%rip)    ; debug_mode + 3
        0x7fff5e99367d <+444>: jne    0x7fff5e9936a3            ; <+482>
        0x7fff5e99367f <+446>: leaq   0x18458(%rip), %rsi       ; "*** sending SIGSTOP to help debug\n"
        0x7fff5e993686 <+453>: movl   $0x5, %edi
    (lldb) up
    frame #2: 0x00007fff5e9934a3 libsystem_malloc.dylib`malloc_report + 152
    libsystem_malloc.dylib`malloc_report:
        0x7fff5e9934a3 <+152>: movq   0x32c45b66(%rip), %rax    ; (void *)0x00007fff915c6070: __stack_chk_guard
        0x7fff5e9934aa <+159>: movq   (%rax), %rax
        0x7fff5e9934ad <+162>: cmpq   -0x8(%rbp), %rax
        0x7fff5e9934b1 <+166>: jne    0x7fff5e9934bc            ; <+177>
    (lldb) up
    frame #3: 0x000000010194709a librutie_ruby_example.dylib`alloc::alloc::dealloc::hef07b11e979696ba(ptr="", layout=Layout @ 0x00007ffeefbfeb40) at alloc.rs:96
    (lldb) up
    frame #4: 0x00000001019470f9 librutie_ruby_example.dylib`alloc::alloc::box_free::h1a8734277b8c0de7(ptr=Unique<rutie::class::any_object::AnyObject> @ 0x00007ffeefbfeb60) at alloc.rs:206
    (lldb) up
    frame #5: 0x00000001019464ad librutie_ruby_example.dylib`rutie::util::ptr_to_data::h4762f8239518f213(ptr=0x000000010070d790) at util.rs:101
       98
       99  	pub unsafe fn ptr_to_data<R>(ptr: *mut c_void) -> R {
       100 	    *Box::from_raw(ptr as *mut R)
    -> 101 	}
    (lldb) up
    frame #6: 0x000000010194715c librutie_ruby_example.dylib`rutie::binding::thread::call_with_gvl::hbebc4468eca2e309(func=<unavailable>) at thread.rs:92
       89  	            util::closure_to_ptr(func),
       90  	        );
       91
    -> 92  	        util::ptr_to_data(ptr)
       93  	    }
       94  	}
       95
    (lldb) up
    frame #7: 0x0000000101946c08 librutie_ruby_example.dylib`rutie::class::thread::Thread::call_with_gvl::h24af48b7283f4583(func=<unavailable>) at thread.rs:138
       135 	    where
       136 	        F: 'static + FnOnce() -> R,
       137 	    {
    -> 138 	        thread::call_with_gvl(func)
       139 	    }
       140 	}
       141
    (lldb) up
    frame #8: 0x0000000101946458 librutie_ruby_example.dylib`rutie_ruby_example::work::_$u7b$$u7b$closure$u7d$$u7d$::h3a14ca771a91723e at lib.rs:17
       14  	            move || {
       15  	                // Releasing the GVL here to do network IO
       16  	                // After we fetched a unit of work I wanto to call a ruby object
    -> 17  	                Thread::call_with_gvl(move || {
       18  	                    // Uncommenting this line "fixes" the issue
       19  	                    // let worker_class = "Object".to_string();
       20  	                    let ruby_worker = Class::from_existing(&worker_class);
    (lldb)
    
    opened by dsander 10
  • Unable to run tests

    Unable to run tests

    Hello, I'm having issue getting the example app in readme up and running. Here's the error:

    ~/p/rutie_ruby_example$ env CONFIGURE_OPTS=--enable-shared RUBY_STATIC=true rbenv install 2.6.1
    rbenv: /Users/senthilarivudainambi/.rbenv/versions/2.6.1 already exists
    continue with installation? (y/N) y
    ruby-build: use openssl from homebrew
    Downloading ruby-2.6.1.tar.bz2...
    -> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.1.tar.bz2
    Installing ruby-2.6.1...
    ruby-build: use readline from homebrew
    Installed ruby-2.6.1 to /Users/senthilarivudainambi/.rbenv/versions/2.6.1
    
    ~/p/rutie_ruby_example$ rbenv shell 2.6.1
    
    ~/p/rutie_ruby_example$ cargo build --release; rake test
       Compiling rutie_ruby_example v0.1.0 (/Users/senthilarivudainambi/play/rutie_ruby_example)
    error: linking with `cc` failed: exit code: 1
      |
      = note: "cc" "-m64" "-L" "/Users/senthilarivudainambi/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.0.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.1.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.10.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.11.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.12.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.13.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.14.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.15.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.2.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.3.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.4.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.5.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.6.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.7.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.8.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.rutie_ruby_example.3w3pe43h-cgu.9.rcgu.o" "-o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/librutie_ruby_example.dylib" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.2s9ba8i8h1iie73v.rcgu.o" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps/rutie_ruby_example.4hd42g73j2fxvw4s.rcgu.o" "-Wl,-dead_strip" "-nodefaultlibs" "-L" "/Users/senthilarivudainambi/play/rutie_ruby_example/target/release/deps" "-L" "/Users/senthilarivudainambi/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib" "-Wl,-force_load" "-Wl,/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/librutie-3e019247df7a85c2.rlib" "-Wl,-force_load" "-Wl,/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/liblibc-7ef1d07239f6e565.rlib" "-Wl,-force_load" "-Wl,/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/liblazy_static-2c76c9c092088406.rlib" "-Wl,-force_load" "-Wl,/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/libstd-6985814064069a76.rlib" "-Wl,-force_load" "-Wl,/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/libpanic_unwind-2a66b0a73d4df562.rlib" "-Wl,-force_load" "-Wl,/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/libbacktrace_sys-50ddadbae01d4f58.rlib" "-Wl,-force_load" "-Wl,/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/libunwind-01e9a61c51f689e0.rlib" "-Wl,-force_load" "-Wl,/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/librustc_demangle-1c356999b4cc6064.rlib" "-Wl,-force_load" "-Wl,/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/liblibc-eab5804665781140.rlib" "-Wl,-force_load" "-Wl,/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/liballoc-a7e3679ffd9daddc.rlib" "-Wl,-force_load" "-Wl,/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/librustc_std_workspace_core-315b27a66378d597.rlib" "-Wl,-force_load" "-Wl,/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/libcore-9d059fde79137499.rlib" "/var/folders/rp/_tv7mndd70g45sy1dp9lh8cm0000gp/T/rustc5McPXK/libcompiler_builtins-35a7b98264276399.rlib" "-framework" "Foundation" "-lruby-static" "-lSystem" "-lresolv" "-lc" "-lm" "-dynamiclib" "-Wl,-dylib"
      = note: ld: library not found for -lruby-static
              clang: error: linker command failed with exit code 1 (use -v to see invocation)
    
    
    error: aborting due to previous error
    
    error: Could not compile `rutie_ruby_example`.
    
    To learn more, run the command again with --verbose.
    rake aborted!
    LoadError: cannot load such file -- rspec/core/rake_task
    /Users/senthilarivudainambi/play/rutie_ruby_example/Rakefile:2:in `<top (required)>'
    (See full trace by running task with --trace)
    
    

    I did rebuild ruby 2.6.1 with --enabled-shared and still same error:

    ~/p/rutie_ruby_example$ ruby -e "require 'rbconfig'; puts RbConfig::CONFIG['ENABLE_SHARED']"
    yes
    

    Any idea what I'm doing wrong?

    Mac rbenv 
    opened by sent-hil 9
  • Example code in README leads to linking errors

    Example code in README leads to linking errors

    Following the example code in the README for calling Rust from Ruby led to the following error for me:

    alex.weisberger@hq-mbp-alexweisberger rutie_ruby_example % cargo build
       Compiling libc v0.2.80
       Compiling rutie v0.8.1
       Compiling lazy_static v1.4.0
       Compiling rutie_ruby_example v0.1.0 (/Users/alex.weisberger/code/rutie_ruby_example)
    error: linking with `cc` failed: exit code: 1
      |
      = note: "cc" "-m64" "-arch" "x86_64" "-L" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.11q727vvefaevrgc.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.12cmroqxm1v6w82i.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.13rwlaby184m84vu.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.1inmyugmpz48gsd1.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.1le1raml7q98jvdx.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.1y4acf0zfcbs193n.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.34ma6hgf2pohzwr4.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.3cltky4kxueandzf.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.3fvje93866ikqr6o.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.3ifmhzeog215p5ng.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.3sqem6ck3s4rkxfg.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.3tzohvolf7wfsroj.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.3wu9kx8o1vy55jof.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.3yhtwtbzcg5qzek0.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.442z675k1qo8low2.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.44damv685dvi8uo6.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4dtvikikt94104vo.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4eqi3u60emg32hnp.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4hqid910kt6voa39.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4jicv1x3i5o4al25.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4q8gysy1ka9xuw3d.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4vpxglhiqgzykwxq.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4y18zc35i7o069rs.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.50m2zi5k0c0ch31d.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.52etfccwdi2wjkz8.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.54v3bj03n3nz389k.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.57evdjplmp36t4dy.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.5baxxzbe43evixiw.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.5dup4iu6xeglpp8t.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.8fbg87d4431ni44.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.dv749jpiy2zqbg0.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.jhx1fqu7uhg6yh0.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.jvje28rhvoyghqp.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.s83947a79u7r8f6.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.sfmslqr8z0ax1qs.rcgu.o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.z2lm3cwj17cwxp6.rcgu.o" "-o" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/librutie_ruby_example.dylib" "-Wl,-exported_symbols_list,/var/folders/_j/lj_s009n4bn2q2x3y3k5ntpm0000gp/T/rustcdXmJbY/list" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.55by2lg2xogu0bs.rcgu.o" "-Wl,-dead_strip" "-dynamiclib" "-Wl,-dylib" "-nodefaultlibs" "-L" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps" "-L" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/librutie-fcf5b68285cb8bee.rlib" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/liblibc-67370c729c9509e9.rlib" "/Users/alex.weisberger/code/rutie_ruby_example/target/debug/deps/liblazy_static-b4401f02f4fbcaf3.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libstd-688c1376a25c049d.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libpanic_unwind-078f89c2cdb6d46b.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libobject-fec020208bc1ad3c.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libaddr2line-38540dcacc9fd218.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libgimli-6f613179f618c598.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/librustc_demangle-4d1a5d7118aaeaf2.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libhashbrown-d88fab3b1b9d8356.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/librustc_std_workspace_alloc-a21754532a052f2f.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libunwind-2e9ebc4127641a96.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcfg_if-82d0f961232a05ca.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/liblibc-370b1b71f08bac3c.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/liballoc-816106c1f35f5421.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/librustc_std_workspace_core-20f3a030f1a56a86.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcore-60333aa00936c5ce.rlib" "/Users/alex.weisberger/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcompiler_builtins-116aaeaea873ef94.rlib" "-lSystem" "-lresolv" "-lc" "-lm"
      = note: Undefined symbols for architecture x86_64:
                "_rb_define_class", referenced from:
                    rutie::binding::class::define_class::h7b8247193a3fa385 in librutie-fcf5b68285cb8bee.rlib(rutie-fcf5b68285cb8bee.rutie.cpab5xen-cgu.10.rcgu.o)
                "_rb_funcallv", referenced from:
                    rutie::binding::vm::call_method::hbd76d6098d2488cf in librutie-fcf5b68285cb8bee.rlib(rutie-fcf5b68285cb8bee.rutie.cpab5xen-cgu.14.rcgu.o)
                "_rb_string_value_cstr", referenced from:
                    rutie::binding::string::value_to_string::h2f04d887b782c46e in librutie-fcf5b68285cb8bee.rlib(rutie-fcf5b68285cb8bee.rutie.cpab5xen-cgu.13.rcgu.o)
                "_rb_utf8_str_new", referenced from:
                    rutie::binding::string::new_utf8::he32cd2db6829b590 in librutie-fcf5b68285cb8bee.rlib(rutie-fcf5b68285cb8bee.rutie.cpab5xen-cgu.13.rcgu.o)
                "_rb_intern2", referenced from:
                    rutie::binding::symbol::internal_id::h4f486e6fa3135f71 in librutie-fcf5b68285cb8bee.rlib(rutie-fcf5b68285cb8bee.rutie.cpab5xen-cgu.6.rcgu.o)
                "_rb_cObject", referenced from:
                    rutie::class::class::Class::superclass_to_value::hfcbfcf1309bdc603 in librutie-fcf5b68285cb8bee.rlib(rutie-fcf5b68285cb8bee.rutie.cpab5xen-cgu.9.rcgu.o)
                    rutie::util::inmost_rb_object::h9f13d555f3b3b34b in librutie-fcf5b68285cb8bee.rlib(rutie-fcf5b68285cb8bee.rutie.cpab5xen-cgu.15.rcgu.o)
                "_rb_const_get", referenced from:
                    rutie::binding::class::const_get::h75c9cdd8fbebeb9b in librutie-fcf5b68285cb8bee.rlib(rutie-fcf5b68285cb8bee.rutie.cpab5xen-cgu.10.rcgu.o)
                "_rb_exc_raise", referenced from:
                    rutie::binding::vm::raise_ex::h621857d0bff6ffb1 in librutie-fcf5b68285cb8bee.rlib(rutie-fcf5b68285cb8bee.rutie.cpab5xen-cgu.14.rcgu.o)
                "_rb_define_singleton_method", referenced from:
                    rutie::binding::class::define_singleton_method::hc64422c5f9698d77 in rutie_ruby_example.4q8gysy1ka9xuw3d.rcgu.o
              ld: symbol(s) not found for architecture x86_64
              clang: error: linker command failed with exit code 1 (use -v to see invocation)
              
    
    error: aborting due to previous error
    
    error: could not compile `rutie_ruby_example`
    

    MacOS version 10.15.7 Rutie version 0.8.1 Ruby version 2.7.2 (compiled with --enable-shared). rustc version 1.48.0

    This error means that the Rust --> Ruby bindings have not linked (i.e. here) the Ruby C library.

    I noticed that the example app in the repo does not specify the no-link cargo feature, and removing that feature from my example app allowed rutie to compile.

    opened by amw-zero 8
  • Add faster versions of `equals`, `is_eql` and `is_equal`

    Add faster versions of `equals`, `is_eql` and `is_equal`

    Hi there,

    I'm just getting my feet wet with Rust/Rutie, so its entirely possible that this patch is nonsensical. Also, I'm not sure if I have put things in the right place, etc. Happy to make any changes you consider necessary!

    The changes are:

    • Object::equals is now a wrapper around the rb_equal C function;
    • Object::is_eql is now a wrapper around the rb_eql C function;
    • Object::is_equal simply performs an == comparison on the underlying values, which is the same behaviour as the rb_obj_equal C function.
    opened by asppsa 7
  • Fix segfaults caused by closures passed to `Thread` methods

    Fix segfaults caused by closures passed to `Thread` methods

    I sadly still don't really understand how the changes work, but did my best explaining my though process, which I hope makes sense 😄


    Fix segfaults when calling Thread::call_without_gvl and call_with_gvl

    I can't really explain why requiring FnMut over FnOnce fixes the problems described in #69. I only discovered that all examples for passing closure to C callbacks were using FnMut and not FnOnce. Based on the stacktraces I saw I am assuming that the compiler captures and returns the variables differently which somehow extends(?) their lifetime.

    Moving the func into the wrap_return seems to be required to ensure the return value lives long enough.

    Due to the additional requirements of FnMut the 'static lifetime of the closures are not required anymore. They have been introduced to fix this issue. The original example now also does not compile and requires str to be cloned. Done that it compiles and runs without a segfault.


    Fix creating Thread::new when passing a closure capturing variables

    Without requiring FnMut closures creating a ruby thread using a closure capturing variables segfaulted.

    Fixes #69

    opened by dsander 7
  • Unable to build

    Unable to build "Call Rust from Ruby" example on Mac

    Hi!

    I've been trying to build the example of calling Rust from Ruby from the readme and have hit some issues.

    The first snag I hit was that the feature in the readme wasn't detected:

    error: failed to select a version for `rutie`.
        ... required by package `rutie_ruby_example v0.1.0 (/Users/me/code/rutie_ruby_example)`
    versions that meet the requirements `= 0.7.0` are: 0.7.0
    
    the package `rutie_ruby_example` depends on `rutie`, with features: `no-link` but `rutie` does not have these features.
    

    If I remove the feature from the toml file, I get an error about not being able to find the static libruby, which is correct as I built ruby dynamically as requested by the readme:

      = note: ld: library not found for -lruby-static
    

    If I set the feature using enviroment variables NO_LINK_RUTIE, I get complaints at the link stage that certain symbols cannot be found.

    ...
      = note: Undefined symbols for architecture x86_64:
                "_rb_funcallv", referenced from:
                    rutie::binding::vm::call_method::h4f58f42a73be3784 in librutie-d43da9d278d1d079.rlib(rutie-d43da9d278d1d079.rutie.83fl08uz-cgu.15.rcgu.o)
                "_rb_intern2", referenced from:
                    rutie::binding::symbol::internal_id::h53c0d0a300c24aed in librutie-d43da9d278d1d079.rlib(rutie-d43da9d278d1d079.rutie.83fl08uz-cgu.8.rcgu.o)
                "_rb_cObject", referenced from:
                    rutie::util::inmost_rb_object::h58fc3e7371a9bd30 in librutie-d43da9d278d1d079.rlib(rutie-d43da9d278d1d079.rutie.83fl08uz-cgu.5.rcgu.o)
                    rutie::class::class::Class::superclass_to_value::h623835c60d0cf15e in librutie-d43da9d278d1d079.rlib(rutie-d43da9d278d1d079.rutie.83fl08uz-cgu.8.rcgu.o)
                "_rb_string_value_cstr", referenced from:
                    rutie::binding::string::value_to_string::h31a08fe870ac65fa in librutie-d43da9d278d1d079.rlib(rutie-d43da9d278d1d079.rutie.83fl08uz-cgu.14.rcgu.o)
    ...
    

    The linker command itself doesn't actually seem to have libruby in it:

    "cc" "-m64" "-L" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.13gzxphx1qkh09zh.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.13ohqgh1e9065748.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.176ggxngm7z90af0.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.19905pc63lyfea4z.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.1sqrydyuz8kxg43z.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.1tf1904qivzwgynr.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.1ujbqjz2queip6ud.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.1zlj8q95ije0uldn.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.28ij0jl8wx7v4dlu.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.2pll6j6yd9e1px0r.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.2qp6kmprupu21ngf.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.2w54erubrjse8vbk.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.33b3mnyngfhtsb0l.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.3dpzfxpvnrwk7suk.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.3njal17w5pffbvwh.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.3o52on0z8tomm3zt.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.3shfgz0k9oan8kx.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.3xjqdc41yoxkrjac.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4knkv9rrmqqlxs71.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4lm03l44oubherxf.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4o6b8l2818e0y5uk.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4qbt5kzv3r5cu9au.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4yxyva8ajkrg5lj6.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.551s5p1koaimc597.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.5d7940jh37m9hg9v.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.5diqvg2jjyqhpnew.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.622gamq7rq49gcz.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.d0fe6qr8d5rqwu2.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.eepjz2ustpmdm6y.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.imntb66b3x452wh.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.nxzdpzkjoi0fsp8.rcgu.o" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.wt0do9sj9kmt9nv.rcgu.o" "-o" "/Users/me/code/rutie_ruby_example/target/debug/deps/librutie_ruby_example.dylib" "-Wl,-exported_symbols_list,/var/folders/g1/p9stlry52vg5syw1zjzsd5dr0000gn/T/rustcxeo8Vw/list" "/Users/me/code/rutie_ruby_example/target/debug/deps/rutie_ruby_example.4hd42g73j2fxvw4s.rcgu.o" "-Wl,-dead_strip" "-nodefaultlibs" "-L" "/Users/me/code/rutie_ruby_example/target/debug/deps" "-L" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib" "/Users/me/code/rutie_ruby_example/target/debug/deps/librutie-d43da9d278d1d079.rlib" "/Users/me/code/rutie_ruby_example/target/debug/deps/liblibc-2f697bcb367999fc.rlib" "/Users/me/code/rutie_ruby_example/target/debug/deps/liblazy_static-a489a9dd01075252.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libstd-ce17fe05fa88fff7.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libpanic_unwind-88250736fdfd488b.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libhashbrown-b4c23b5d831b61ea.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/librustc_std_workspace_alloc-52678edf67c3cbfc.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libbacktrace-aa90723925b767c3.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libbacktrace_sys-1ad31f0e1f5330bc.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/librustc_demangle-572bf915a75bf178.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libunwind-709b6ef89ca6e6af.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcfg_if-174360cf12ee1390.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/liblibc-45e1eff5d23696f7.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/liballoc-d67c1d4ca132d737.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/librustc_std_workspace_core-41d0f9161f0005e8.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcore-f090ec23084537ee.rlib" "/Users/me/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcompiler_builtins-7c4cbb62cd53c96a.rlib" "-lSystem" "-lresolv" "-lc" "-lm" "-dynamiclib" "-Wl,-dylib"
    

    I have made sure that the DYLD_LIBRARY_PATH variable is set to the correct location as well accoring to the readme, but that has not helped.

    Please let me know if I'm doing something wrong! 🙂

    opened by Eosis 6
  • Rutie Float type requires an exact Float when called from Ruby

    Rutie Float type requires an exact Float when called from Ruby

    Hi 👋. Thanks for building Rutie, I am glad to see that there's another option for Ruby/Rust integration that is actively developed.

    I'm experimenting with offloading some of our high density math to Rust. I made a repository for benchmarking and API experimentation with the various ways to integrate Rust and Ruby. I'm currently adding rutie to the benchmark, mostly for API comparison.

    I noticed that Rutie inherited the same problematic ruby Float behavior from ruru that the other APIs (rust/helix, rust/ffi, c, etc.) don't share.

    Issue

    // This will cause a panic if passed a non float like `2123`
    fn double_me(input: Float) -> Float {
        Float::new(input.unwrap().to_f64() * 2.0)
    }
    

    rutie and ruru require Ruby to pass in an exact Float value 0.0, rather than allowing integers passed as floats 0 like Ruby itself. If a non-exact float is passed, this will panic.

    # works fine when called with an exact float
    def call_double_me
      RutieExample.double_me(100.0)
    end
    
    # Rutie PANIC when called with a non-exact float
    # Other libraries work fine
    def call_double_me
      RutieExample.double_me(100)
    end
    
    thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: #<TypeError: Error converting to Float>', src/libcore/result.rs:999:5
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
    fatal runtime error: failed to initiate panic, error 5
    

    Expectation

    Given that a valid ruby Integer is always a valid ruby Float, and a valid rust iX is always a valid fX, this seems like it would be optimal for rutie to handle this easily without a panic attack.

    The Ruby C API (using rb_num2dbl/NUM2DBL) correctly handles this cast. It looks like the rutie source code is calling extern rb_num2dbl, so I'm assuming the issue is happening Rust-side. Is it missing traits?

    I'm happy to PR with a bit of guidance on how to approach it. I'm guessing it's something like this integer PR.

    opened by bbugh 6
  • Fix build.rs to use RbConfig::CONFIG['ruby_pc']

    Fix build.rs to use RbConfig::CONFIG['ruby_pc']

    I modified build.rs to use pkg-config. A test is done only on my Mac, but backward compatibility is not destroyed and I think that there is no problem.


    There are 6 Ruby installed on my Mac.

    • Initially installed
    • Installed using homebrew (brew install ruby)
    • Installed using rbenv
      • CONFIGURE_OPTS="--enable-shared" rbenv install 2.3.6
      • rbenv install 2.3.7
      • CONFIGURE_OPTS="--enable-shared" rbenv install 2.5.0
      • rbenv install 2.5.1

    I ran the following script.

    #!/bin/bash
    
    build_test() {
      printf "** %s **\n" "$1"
      cargo clean
      which "${RUBY:-ruby}"
      ${RUBY:-ruby} -v
      ${RUBY:-ruby} -e 'puts "ENABLE_SHARED = " + RbConfig::CONFIG["ENABLE_SHARED"] '
      cargo run --quiet --example eval 'puts "Success to build"'
      if cat target/debug/build/rutie-*/output | grep 'use ruby_pc' > /dev/null; then
          echo "build with pkg-config"
      else
          echo "build without pkg-config"
      fi
      sleep 1
      echo
    }
    
    RUBY=/usr/bin/ruby build_test "Build-in"
    RUBY=/usr/local/bin/ruby build_test "Homebrew"
    RBENV_VERSION=2.3.6 build_test "rbenv 2.3.6"
    RBENV_VERSION=2.3.7 build_test "rbenv 2.3.7"
    RBENV_VERSION=2.5.0 build_test "rbenv 2.5.0"
    RBENV_VERSION=2.5.1 build_test "rbenv 2.5.1"
    

    And I got the following result.

    $ bash build-test.bash
    ** Build-in **
    /usr/bin/ruby
    ruby 2.3.3p222 (2016-11-21 revision 56859) [universal.x86_64-darwin17]
    ENABLE_SHARED = yes
    Success to build
    build with pkg-config
    
    ** Homebrew **
    /usr/local/bin/ruby
    ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]
    ENABLE_SHARED = yes
    Success to build
    build with pkg-config
    
    ** rbenv 2.3.6 **
    /Users/user/.rbenv/shims/ruby
    ruby 2.3.6p384 (2017-12-14 revision 61254) [x86_64-darwin17]
    ENABLE_SHARED = yes
    Success to build
    build with pkg-config
    
    ** rbenv 2.3.7 **
    /Users/user/.rbenv/shims/ruby
    ruby 2.3.7p456 (2018-03-28 revision 63024) [x86_64-darwin17]
    ENABLE_SHARED = no
    Success to build
    build with pkg-config
    
    ** rbenv 2.5.0 **
    /Users/user/.rbenv/shims/ruby
    ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin17]
    ENABLE_SHARED = yes
    Success to build
    build with pkg-config
    
    ** rbenv 2.5.1 **
    /Users/user/.rbenv/shims/ruby
    ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]
    ENABLE_SHARED = no
    Success to build
    build with pkg-config
    
    opened by irxground 6
  • Ruby 2.7

    Ruby 2.7

    Hello,

    I tried to use rutie with Ruby 2.7 and it seems to fail. See the logs, https://github.com/wasmerio/ruby-ext-wasm/runs/481967739?check_suite_focus=true.

    /home/runner/.rbenv/versions/2.7.0/lib/ruby/2.7.0/fiddle.rb:47:in `initialize': libruby.so.2.6: cannot open shared object file: No such file or directory (Fiddle::DLError)
    	from /home/runner/.rbenv/versions/2.7.0/lib/ruby/2.7.0/fiddle.rb:47:in `new'
    	from /home/runner/.rbenv/versions/2.7.0/lib/ruby/2.7.0/fiddle.rb:47:in `dlopen'
    	from /home/runner/.gem/gems/rutie-0.0.4/lib/rutie.rb:21:in `init'
    	from /home/runner/work/ruby-ext-wasm/ruby-ext-wasm/lib/wasmer.rb:5:in `<module:Wasmer>'
    	from /home/runner/work/ruby-ext-wasm/ruby-ext-wasm/lib/wasmer.rb:4:in `<top (required)>'
    	from /home/runner/.rbenv/versions/2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:72:in `require'
    	from /home/runner/.rbenv/versions/2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:72:in `require'
    	from /home/runner/work/ruby-ext-wasm/ruby-ext-wasm/tests/prelude.rb:2:in `<top (required)>'
    	from /home/runner/.rbenv/versions/2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:72:in `require'
    	from /home/runner/.rbenv/versions/2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:72:in `require'
    	from /home/runner/work/ruby-ext-wasm/ruby-ext-wasm/tests/global_test.rb:2:in `<top (required)>'
    	from /home/runner/.rbenv/versions/2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
    	from /home/runner/.rbenv/versions/2.7.0/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
    	from /home/runner/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:17:in `block in <main>'
    	from /home/runner/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:5:in `select'
    	from /home/runner/.rbenv/versions/2.7.0/lib/ruby/gems/2.7.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:5:in `<main>'
    rake aborted!
    Command failed with status (1)
    

    Is Rutie tested against Ruby 2.7 already, or is it something I've to check on my side?

    Thanks!

    opened by Hywan 5
  • Integer::new(std::i64::MIN) panics

    Integer::new(std::i64::MIN) panics

    I feel like I must be overlooking something, but I ran across this while writing some tests. I tried whittling it down to find the breaking point; some of these panic (signal: 11, SIGSEGV: invalid memory reference); some don't:

    // Panic
    let i = std::i64::MIN;  // -9223372036854775808
    let _ = Integer::new(i);
    
    // Panic
    let i = std::i64::MIN + std::u32::MAX as i64; // -9223372032559808513
    let _ = Integer::new(i);
    
    // Panic
    let i = std::i64::MAX;  // 9223372036854775807
    let _ = Integer::new(i);
    
    // Panic
    let i = std::i64::MAX - 1;
    let _ = Integer::new(i);
    
    // Ok
    let i = (std::i32::MAX as i64) + 1; // 2147483648
    let _ = Integer::new(i);
    
    // Panic
    let i = (std::i32::MIN as i64).pow(2); // 4611686018427387904
    let _ = Integer::new(i);
    
    // Ok! Looks like this is a threshold on the positive end.
    let i = (std::i32::MIN as i64).pow(2) -  1;
    let _ = Integer::new(i);
    
    // Ok!
    let i = (std::i32::MIN as i64).pow(2) * -1; // -4611686018427387904
    let _ = Integer::new(i);
    
    // Panic; looks like the -1 here is where it fails, at least on the negative end
    let i = (std::i32::MIN as i64).pow(2) * -1 - 1;  // -4611686018427387905
    let _ = Integer::new(i);
    

    Ruby version: ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-darwin18] Rust version: rustc 1.39.0 (4560ea788 2019-11-04)

    If this is a Ruby limitation (only handling values in between 32- and 64-bit int types), I'm not sure what a reasonable solution would be, but it at least seems worth documenting.

    question Mac 
    opened by turboladen 5
  • Expose `Fiber::SchedulerInterface` in Rust

    Expose `Fiber::SchedulerInterface` in Rust

    Hey @danielpclark,

    First of all, thank you for creating Rutie, I've been successfully using it in a project and the experience has been very positive.

    I have a feature in mind that I'd love to see in Rutie. Since Ruby 3 we now have a Fiber::SchedulerInterface that exposes a way to write Fiber-based concurrency without manual scheduling of the fiber execution. It's based on hinting the optional Fiber scheduler that the current operation is blocking and it can go and do something else and then again when the operation is complete and we can unblock. It's kinda like releasing the GVL allowing other Threads to be scheduled, but for Fibers.

    From what I can tell we only need to expose 2 methods to be able to tell Ruby that we're blocked/unblocked.

    Putting this out there for anyone to pick before I find some time to put together a PR.

    opened by antstorm 0
  • Add support for function parameter trailing commas in 'methods' macro

    Add support for function parameter trailing commas in 'methods' macro

    Fixes #164.

    I ran the existing tests and everything passed and I reran my example with these changes and it compiled. That said, I have no experience with Rust macros so please let me know if anything needs improvement. I am happy to change or add anything if necessary. :)

    opened by andrewtbiehl 0
  • 'methods' macro doesn't support function parameter trailing commas

    'methods' macro doesn't support function parameter trailing commas

    It appears that the methods (and also unsafe_methods) macro doesn't currently support having a trailing comma at the end of its declared methods' parameters. For me this causes issues when using Rutie alongside Rustfmt. This is a very minor issue for me, but I thought I might as well raise it.

    For example, running cargo check on the following Rutie example (adapted from the docs) is successful:

    #[macro_use]
    extern crate rutie;
    
    use rutie::{Class, Object, RString};
    
    class!(RutieExample);
    
    methods!(
        RutieExample,
        _rtself,
        fn pub_greet(raw_first_name: RString, raw_last_name: RString, raw_hometown: RString) -> RString {
            let first_name = raw_first_name.unwrap().to_string();
            let last_name = raw_last_name.unwrap().to_string();
            let hometown = raw_hometown.unwrap().to_string();
    
            let greeting = format!("Hello {first_name} {last_name} from {hometown}!");
    
            RString::new_utf8(&greeting)
        }
    );
    
    #[allow(non_snake_case)]
    #[no_mangle]
    pub extern "C" fn Init_rutie_ruby_example() {
        Class::new("RutieExample", None).define(|klass| {
            klass.def_self("greet", pub_greet);
        });
    }
    

    However, running cargo fmt on this code (using the default Rustfmt configuration) results in the following formatting change:

    @@ -8,7 +8,11 @@ class!(RutieExample);
     methods!(
         RutieExample,
         _rtself,
    -    fn pub_greet(raw_first_name: RString, raw_last_name: RString, raw_hometown: RString) -> RString {
    +    fn pub_greet(
    +        raw_first_name: RString,
    +        raw_last_name: RString,
    +        raw_hometown: RString,
    +    ) -> RString {
             let first_name = raw_first_name.unwrap().to_string();
             let last_name = raw_last_name.unwrap().to_string();
             let hometown = raw_hometown.unwrap().to_string();
    

    With this change, now running cargo check returns the following errors:

        Checking rutie_ruby_example v0.1.0 (~/Code/rutie_ruby_example)
    error: no rules expected the token `)`
      --> src/lib.rs:15:5
       |
    15 |     ) -> RString {
       |     ^ no rules expected this token in macro call
    
    error[E0425]: cannot find value `pub_greet` in this scope
      --> src/lib.rs:30:33
       |
    30 |         klass.def_self("greet", pub_greet);
       |                                 ^^^^^^^^^ not found in this scope
    
    warning: unused import: `RString`
     --> src/lib.rs:4:28
      |
    4 | use rutie::{Class, Object, RString};
      |                            ^^^^^^^
      |
      = note: `#[warn(unused_imports)]` on by default
    
    For more information about this error, try `rustc --explain E0425`.
    warning: `rutie_ruby_example` (lib) generated 1 warning
    error: could not compile `rutie_ruby_example` due to 2 previous errors; 1 warning emitted
    

    Finally, removing the newly added trailing comma from the parameter list in the pub_greet function signature results in a successful build, so it looks as though this trailing comma is the root issue.

    The unsafe_methods macro also appears to have this issue.

    I originally encountered this while working in the following environment:

    • Rutie: 0.8.4
    • Rust: rustc 1.65.0 (897e37553 2022-11-02)
    • Ruby: ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-darwin21]
    • OS: MacOS Ventura 13.0.1 on an Intel MacBook

    P.S. Thanks for such a great library! It's been amazing to use overall. :smile: :gem: :gear:

    opened by andrewtbiehl 0
  • Integration with `rb-sys`

    Integration with `rb-sys`

    Hi there!

    I’ve been working on rb-sys. The main goal of the project is to make building native extensions in Rust easier than C.

    Traditionally, most Ruby/Rust gems have packaged their own Ruby bindings. As you know, there are many edge cases and supporting these bindings across multiple platforms can be a total pain. With rb-sys, the goal is remove that burden. Some features are:

    • Rust bindings for the Ruby C API
    • Support for Ruby 2.4+
    • Cross compilation of gems
    • Integration with rake-compiler
    • Support for the Rubygems official cargo builder
    • Production battle tested at shopify

    I would love to add support for rb-sys to Rutie if you are interested. I recently made the switch this for magnus and things went smoothly. For Rutie, I imagine it will solve a lot of build issues (particularly with libruby-static, and upcoming changes with Ruby 3.2). On top of this, it will make it easier for Rutie users to cross compile gems.

    Let me know if this sounds like something you would accept. Happy to start working on it!

    opened by ianks 3
  • Implement bindings to ruby_sysinit and ruby_init_stack (Segmentation fault in Windows on VM#init)

    Implement bindings to ruby_sysinit and ruby_init_stack (Segmentation fault in Windows on VM#init)

    Hello all,

    Description of issue

    Rutie is missing bindings to Virtual Machine Initialization methods such as ruby_sysinit and ruby_init_stack which are vital on Windows New Technology Operating Systems. If one does not use them, they will get STATUS_ACCESS_VIOLATION (Segmentation Fault) on Ruby 3.1 (and on previous versions, perhaps?).

    Host information

    OS Version: Windows 10 21H2 (19044.1889) Rust Version: 1.65.0-nightly Linked with Ruby Version: 3.1

    Steps to reproduce STATUS_ACCESS_VIOLATION

    1. Install dependencies
    1. Clone rcxp
    2. Run in shell cargo run
    3. error: process didn't exit successfully: 'target\debug\rcxp.exe' (exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)

    Method signatures and their descriptions:

    // ruby/interpreter.h
    
    
    /**
     * Initializes the process for libruby.
     *
     * This function assumes this process is `ruby(1)` and it has just started.
     * Usually programs that embed CRuby interpreter may not call this function,
     * and may do their own initialization.
     *
     * @param[in]  argc  Pointer to process main's `argc`.
     * @param[in]  argv  Pointer to process main's `argv`.
     * @warning    `argc` and `argv` cannot be `NULL`.
     *
     * @internal
     *
     * AFAIK Ruby does write to argv, especially `argv[0][0]`, via setproctitle(3).
     * It is intentional that the argument is not const-qualified.
     */
    void ruby_sysinit(int *argc, char ***argv);
    
    /**
     * Set stack bottom of Ruby implementation.
     *
     * You  must   call  this   function  before  any   heap  allocation   by  Ruby
     * implementation.  Or GC will break living objects.
     *
     * @param[in]  addr  A pointer somewhere on the stack, near its bottom.
     */
    void ruby_init_stack(volatile VALUE *addr);
    

    And I'm pretty sure they're needed, since I also tried initializing Ruby Virtual Machine from Pure C and it didn't work without at least ruby_sysinit.

    So, there are two options.

    1. Implement VM#init_sys - ruby_sysinit and VM#init_stack - ruby_init_stack, requiring Rutie Dev to use them before VM Initialization.
    2. Instead of implementing two new methods, we can modfy VM#init to use these functions internally, freeing the developer from additional code.

    What's the better way to go around this?

    opened by somedevfox 0
  • Ruby 3.0.4 SegFault when running `Fiddle::Function#call`

    Ruby 3.0.4 SegFault when running `Fiddle::Function#call`

    Dear @danielpclark,

    First of all thank you for an amazing library!

    I've ran into a problem that turned out to be a proper head scratcher. Basically I took the example from this repo and was able to successfully run it on my machine (I'm using an M1 chip, just in case). I then replicated the setup in my own project and caught a Segmentation Fault when trying to initialize Rust bindings (it points to calling the Fiddle::Function#call method) — https://gist.github.com/antstorm/1d01c783e4c0b514c869b04a1c362144.

    I was able to narrow the difference down to how I run the cargo rustc command — using the provided Rakefile vs just copying the same exact command to the terminal (it's cargo rustc --release -- -C link-args=-Wl,-undefined,dynamic_lookup in my case). Now here's the crazy part — running this command from an empty irb shell (just wrapping it in backticks) produces a dylib that works, while running the same command directly in the terminal shell doesn't.

    I stumbled upon this issue and did a cargo clean to get a fresh start. This unfortunately (as far as I can tell) did not affect the behaviour at all.

    I can replicate this behaviour consistently in Ruby 3.0.4 and 3.1.2. However both approaches work just fine in Ruby 3.0.3.

    I also ran the diff on the target directories produced by the 2 approaches and this is what I got (as far as I can tell the only difference is the order of the keys inside the "outputs" map, the keys themselves and their values are identical):

    diff target/.rustc_info.json target2/.rustc_info.json
    1c1
    < {"rustc_fingerprint":9631749218497856628,"outputs":{"931469667778813386":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/opt/homebrew/Cellar/rust/1.59.0\ndebug_assertions\nproc_macro\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""},"5309432699494263626":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n","stderr":""},"17598535894874457435":{"success":true,"status":"","code":0,"stdout":"rustc 1.59.0\nbinary: rustc\ncommit-hash: unknown\ncommit-date: unknown\nhost: aarch64-apple-darwin\nrelease: 1.59.0\nLLVM version: 13.0.0\n","stderr":""},"2797684049618456168":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n","stderr":""}},"successes":{}}
    \ No newline at end of file
    ---
    > {"rustc_fingerprint":9631749218497856628,"outputs":{"931469667778813386":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/opt/homebrew/Cellar/rust/1.59.0\ndebug_assertions\nproc_macro\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""},"2797684049618456168":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n","stderr":""},"5309432699494263626":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n","stderr":""},"17598535894874457435":{"success":true,"status":"","code":0,"stdout":"rustc 1.59.0\nbinary: rustc\ncommit-hash: unknown\ncommit-date: unknown\nhost: aarch64-apple-darwin\nrelease: 1.59.0\nLLVM version: 13.0.0\n","stderr":""}},"successes":{}}
    \ No newline at end of file
    Common subdirectories: target/release and target2/release
    

    Am I going completely mad? What am I missing? Any help greatly appreciated.

    UPDATES:

    • There's probably something in the ENV variables
    • Putting the cargo rustc ... in a Makefile didn't work
    • Also initializing an IRB session from a different directory and running cd example && cargo rustc ... didn't work either
    bug Ruby C compatibility Mac 
    opened by antstorm 3
Owner
Daniel P. Clark
I really enjoy Ruby, Rust, and Linux. Blogger and educator on all things technical and personal development. I code for charity, fun, and income.
Daniel P. Clark
Native Ruby extensions written in Rust

Ruru (Rust + Ruby) Native Ruby extensions in Rust Documentation Website Have you ever considered rewriting some parts of your slow Ruby application? J

Dmitry Gritsay 812 Dec 26, 2022
Native Ruby extensions without fear

Helix ⚠️ Deprecated ⚠️ Sadly, we have made the decision to deprecate this project. While we had hoped to bootstrap the project to a point where it cou

Tilde 2k Jan 1, 2023
Fast state-of-the-art tokenizers for Ruby

Fast state-of-the-art tokenizers for Ruby

Andrew Kane 34 Dec 15, 2022
Safe interop between Rust and C++

CXX — safe FFI between Rust and C++ This library provides a safe mechanism for calling C++ code from Rust and Rust code from C++, not subject to the m

David Tolnay 4.4k Jan 7, 2023
Bridge the gap between Haskell and Rust

Curryrs Curryrs (a play on the name of Haskell Curry, rs for Rust libraries, and it's pronunciation couriers) is a library for providing easy to use b

Michael Gattozzi 296 Oct 18, 2022
Facilitating high-level interactions between Wasm modules and JavaScript

wasm-bindgen Facilitating high-level interactions between Wasm modules and JavaScript. Guide | API Docs | Contributing | Chat Built with ?? ?? by The

Rust and WebAssembly 5.9k Jan 8, 2023
Robust and Fast tokenizations alignment library for Rust and Python

Robust and Fast tokenizations alignment library for Rust and Python Demo: demo Rust document: docs.rs Blog post: How to calculate the alignment betwee

Explosion 157 Dec 28, 2022
Rust Attribute-Based Encryption library rabe's C FFI binding , support CP-ABE and KP-ABE encrypt and decrypt, submodule of Rabe.Core c# library.

Rabe-ffi Rust Attribute-Based Encryption library rabe's C FFI binding , support CP-ABE and KP-ABE encrypt and decrypt, submodule of Rabe.Core c# libra

Aya0wind 2 Oct 10, 2022
Slitter is a C- and Rust-callable slab allocator implemented primarily in Rust, with some C for performance or to avoid unstable Rust features.

Slitter is a less footgunny slab allocator Slitter is a classically structured thread-caching slab allocator that's meant to help write reliable long-

Backtrace Labs 133 Dec 5, 2022
Automatically generates Rust FFI bindings to C (and some C++) libraries.

bindgen bindgen automatically generates Rust FFI bindings to C (and some C++) libraries. For example, given the C header doggo.h: typedef struct Doggo

The Rust Programming Language 3.2k Jan 4, 2023
Rust bindings for writing safe and fast native Node.js modules.

Rust bindings for writing safe and fast native Node.js modules. Getting started Once you have the platform dependencies installed, getting started is

The Neon Project 7k Jan 4, 2023
Objective-C Runtime bindings and wrapper for Rust.

Objective-C Runtime bindings and wrapper for Rust. Documentation: http://ssheldon.github.io/rust-objc/objc/ Crate: https://crates.io/crates/objc Messa

Steven Sheldon 336 Jan 2, 2023
A minimalist and safe ECS library for rust!

The full ECS (Entity-Component-System) library. Support an Open Source Developer! ♥️ Composed of two smaller libraries: world_dispatcher: the System p

Joël Lupien 124 Dec 19, 2022
A notebook app integrated with todo lists utility. Developed with Rust, WebAssembly, Yew and Trunk.

Flow.er A notebook app integrated with todo-list utility. Project flow.er is a Rust WASM app running in browser. Taking advantage of Yew and Trunk, it

null 45 Dec 31, 2022
A JavaScript Runtime built with Mozilla's SpiderMonkey Engine and Rust

Spiderfire Spiderfire is a javascript runtime built with Mozilla's SpiderMonkey engine and Rust. Spiderfire aims to disrupt the server-side javascript

Redfire 122 Dec 15, 2022
A rust library containing typings and utility functions dealing with the Public specification of the Internet Computer.

IC Types Contributing Please follow the guidelines in the CONTRIBUTING.md document. Goal This library contains typings and utility functions dealing w

DFINITY 5 Nov 28, 2022
Modern JavaScript runtime for Sony PSP, based on rust-psp and QuickJS.

PSP.js Modern JavaScript runtime for Sony PSP, based on rust-psp and QuickJS. ⚠️ Currently in PoC state, unusable for developing JavaScript apps yet.

Yifeng Wang 15 Nov 28, 2022
Implementation of the Radon and Inverse Radon Transforms in Rust

Radon Transform A rust and python implementation of the discretized version of the radon transform that I did out of boredom. The main mathematical tr

Atman Kar 0 Nov 8, 2021
🚀 Fast and 100% API compatible postcss replacer, built in Rust

postcss-rs ?? Fast and 100% API compatible postcss replacer, built in Rust ⚠️ DO NOT USE. STILL WORK IN PROGRESS. Performance Improvement Tokenize boo

null 472 Dec 28, 2022