Skip to content

Commit

Permalink
Merge pull request #2404 from herwinw/ffi_load_array
Browse files Browse the repository at this point in the history
Support array argument in ffi_lib
  • Loading branch information
herwinw committed Dec 19, 2024
2 parents dfcad8c + 33c2705 commit dbd9658
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 5 deletions.
27 changes: 23 additions & 4 deletions lib/ffi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,29 @@ Value init_ffi(Env *env, Value self) {
Value FFI_Library_ffi_lib(Env *env, Value self, Args &&args, Block *) {
args.ensure_argc_is(env, 1);
auto name = args.at(0);
name->assert_type(env, Object::Type::String, "String");
auto handle = dlopen(name->as_string()->c_str(), RTLD_LAZY);
if (!handle)
env->raise("LoadError", "Could not open library '{}': {}.", name->as_string()->c_str(), dlerror());
void *handle = nullptr;
if (name->is_array()) {
for (auto name2 : *name->as_array()) {
name2->assert_type(env, Object::Type::String, "String");
handle = dlopen(name2->as_string()->c_str(), RTLD_LAZY);
if (handle) {
name = name2;
break;
}
}
if (!handle) {
auto error = new StringObject;
for (auto name2 : *name->as_array())
error->append_sprintf("Could not open library '%s': %s.\n", name2->as_string()->string().c_str(), dlerror());
error->chomp_in_place(env, nullptr);
env->raise("LoadError", error->string());
}
} else {
name->assert_type(env, Object::Type::String, "String");
handle = dlopen(name->as_string()->c_str(), RTLD_LAZY);
if (!handle)
env->raise("LoadError", "Could not open library '{}': {}.", name->as_string()->c_str(), dlerror());
}
auto handle_ptr = new VoidPObject { handle, [](auto p) { dlclose(p->void_ptr()); } };
auto libs = self->ivar_get(env, "@ffi_libs"_s);
if (libs->is_nil())
Expand Down
35 changes: 34 additions & 1 deletion test/natalie/ffi_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ module LibRubyParser
describe 'FFI' do
it 'raises an error if the library cannot be found' do
lambda do
module Foo
Module.new do
extend FFI::Library
ffi_lib "non_existent.so"
end
Expand All @@ -44,6 +44,39 @@ module Foo
)
end

it 'supports an array of strings as library and uses the first one available' do
foo = Module.new do
extend FFI::Library
ffi_lib ['non_existent.so', STUB_LIBRARY_PATH, PRISM_LIBRARY_PATH]
end
libs = foo.instance_variable_get(:@ffi_libs)
libs.size.should == 1
lib = libs.first
lib.should be_an_instance_of FFI::DynamicLibrary
lib.name.should == STUB_LIBRARY_PATH
end

it 'raises an error if no library can be found' do
lambda do
Module.new do
extend FFI::Library
ffi_lib ["non_existent.so", "neither_existent.so"]
end
end.should raise_error(
LoadError,
/Could not open library.*non_existent\.so.*Could not open library.*neither_existent\.so/m
)
end

it 'raises an error if an empty list is provided' do
lambda do
Module.new do
extend FFI::Library
ffi_lib []
end
end.should raise_error(LoadError)
end

it 'links to a shared object' do
libs = LibRubyParser.instance_variable_get(:@ffi_libs)
libs.size.should == 1
Expand Down

0 comments on commit dbd9658

Please sign in to comment.