From 418bd89a5f81cf757a7581b8df96af0237e3a8ad Mon Sep 17 00:00:00 2001 From: Sutou Kouhei Date: Mon, 7 Oct 2024 16:33:03 +0900 Subject: [PATCH] Use JRuby implementation for TruffleRuby Fix GH-145 lib/fiddle/truffleruby.rb uses lib/fiddle/jruby.rb. lib/fiddle/jruby.rb uses FFI API. So we can use it for TruffleRuby too. --- .github/workflows/ci.yml | 2 ++ ext/fiddle/extconf.rb | 2 +- fiddle.gemspec | 1 + lib/fiddle/jruby.rb | 11 +++++++++++ lib/fiddle/truffleruby.rb | 1 + test/fiddle/test_closure.rb | 6 ++++++ test/fiddle/test_fiddle.rb | 11 +++++++++++ test/fiddle/test_func.rb | 4 ++++ test/fiddle/test_function.rb | 13 +++++++++++++ test/fiddle/test_handle.rb | 15 +++++++++++++++ test/fiddle/test_import.rb | 3 +++ test/fiddle/test_pointer.rb | 15 +++++++++++++++ 12 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 lib/fiddle/truffleruby.rb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fe0d68bf..972bcce5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,7 @@ jobs: - '3.2' - debug - jruby + - truffleruby include: - { os: windows-latest , ruby: mingw } - { os: windows-latest , ruby: mswin } @@ -33,6 +34,7 @@ jobs: - { os: macos-14 , ruby: '2.5' } - { os: windows-latest , ruby: '3.0' } - { os: windows-latest , ruby: debug } + - { os: windows-latest , ruby: truffleruby } steps: - uses: actions/checkout@v4 diff --git a/ext/fiddle/extconf.rb b/ext/fiddle/extconf.rb index 6b0ea753..a4a7e7e1 100644 --- a/ext/fiddle/extconf.rb +++ b/ext/fiddle/extconf.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'mkmf' -if RUBY_ENGINE == "jruby" +unless RUBY_ENGINE == "ruby" File.write('Makefile', dummy_makefile("").join) return end diff --git a/fiddle.gemspec b/fiddle.gemspec index 65de7a30..89c2c851 100644 --- a/fiddle.gemspec +++ b/fiddle.gemspec @@ -44,6 +44,7 @@ Gem::Specification.new do |spec| "lib/fiddle/pack.rb", "lib/fiddle/ruby.rb", "lib/fiddle/struct.rb", + "lib/fiddle/truffleruby.rb", "lib/fiddle/types.rb", "lib/fiddle/value.rb", "lib/fiddle/version.rb", diff --git a/lib/fiddle/jruby.rb b/lib/fiddle/jruby.rb index 9ad61d4d..2f1648ca 100644 --- a/lib/fiddle/jruby.rb +++ b/lib/fiddle/jruby.rb @@ -158,6 +158,17 @@ def call(*args, &block); end args[i] = Fiddle::JRuby.__ffi_type__(args[i]) end + else + args.size.times do |i| + arg = args[i] + next unless arg.respond_to?(:to_ptr) + loop do + arg = arg.to_ptr + break if arg.is_a?(FFI::Pointer) + break unless arg.respond_to?(:to_ptr) + end + args[i] = arg + end end result = @function.call(*args, &block) result = Pointer.new(result) if result.is_a?(FFI::Pointer) diff --git a/lib/fiddle/truffleruby.rb b/lib/fiddle/truffleruby.rb new file mode 100644 index 00000000..d2be1474 --- /dev/null +++ b/lib/fiddle/truffleruby.rb @@ -0,0 +1 @@ +require_relative 'jruby' diff --git a/test/fiddle/test_closure.rb b/test/fiddle/test_closure.rb index 787a9b63..8f927b7d 100644 --- a/test/fiddle/test_closure.rb +++ b/test/fiddle/test_closure.rb @@ -6,6 +6,12 @@ module Fiddle class TestClosure < Fiddle::TestCase + def setup + if RUBY_ENGINE == "truffleruby" + omit("FFI::Function don't accept #call-able object with TruffleRuby") + end + end + def teardown super # We can't use ObjectSpace with JRuby. diff --git a/test/fiddle/test_fiddle.rb b/test/fiddle/test_fiddle.rb index b247ae15..e1ed1b5e 100644 --- a/test/fiddle/test_fiddle.rb +++ b/test/fiddle/test_fiddle.rb @@ -9,6 +9,9 @@ def test_nil_true_etc if RUBY_ENGINE == "jruby" omit("Fiddle::Q* aren't supported with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Q* aren't supported with TruffleRuby") + end assert_equal Fiddle::Qtrue, Fiddle.dlwrap(true) assert_equal Fiddle::Qfalse, Fiddle.dlwrap(false) @@ -30,6 +33,10 @@ def test_dlopen_linker_script_input_linux if Dir.glob("/usr/lib/*/libncurses.so").empty? omit("libncurses.so is needed") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#file_name doesn't exist in TruffleRuby") + end + # libncurses.so uses INPUT() on Debian GNU/Linux # $ cat /usr/lib/x86_64-linux-gnu/libncurses.so # INPUT(libncurses.so.6 -ltinfo) @@ -44,6 +51,10 @@ def test_dlopen_linker_script_input_linux def test_dlopen_linker_script_group_linux omit("This is only for Linux") unless RUBY_PLATFORM.match?("linux") + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#file_name doesn't exist in TruffleRuby") + end + # libc.so uses GROUP() on Debian GNU/Linux # $ cat /usr/lib/x86_64-linux-gnu/libc.so # /* GNU ld script diff --git a/test/fiddle/test_func.rb b/test/fiddle/test_func.rb index 5d69cc5f..7ed88a45 100644 --- a/test/fiddle/test_func.rb +++ b/test/fiddle/test_func.rb @@ -64,6 +64,10 @@ def test_strtod end def test_qsort1 + if RUBY_ENGINE == "truffleruby" + omit("TruffleRuby's FFI::Function don't accept #call-able object") + end + closure_class = Class.new(Closure) do def call(x, y) Pointer.new(x)[0] <=> Pointer.new(y)[0] diff --git a/test/fiddle/test_function.rb b/test/fiddle/test_function.rb index b6ae8c14..61b786d3 100644 --- a/test/fiddle/test_function.rb +++ b/test/fiddle/test_function.rb @@ -41,6 +41,9 @@ def test_need_gvl? if RUBY_ENGINE == "jruby" omit("rb_str_dup() doesn't exist in JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("rb_str_dup() doesn't work with TruffleRuby") + end libruby = Fiddle.dlopen(nil) rb_str_dup = Function.new(libruby['rb_str_dup'], @@ -91,6 +94,10 @@ def test_call end def test_argument_count + if RUBY_ENGINE == "truffleruby" + omit("TruffleRuby's FFI::Function don't accept #call-able object") + end + closure_class = Class.new(Closure) do def call one 10 + one @@ -112,6 +119,9 @@ def test_last_error if RUBY_ENGINE == "jruby" omit("Fiddle.last_error doesn't work with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle.last_error doesn't work with TruffleRuby") + end func = Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP) @@ -219,6 +229,9 @@ def test_no_memory_leak if RUBY_ENGINE == "jruby" omit("rb_obj_frozen_p() doesn't exist in JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("memory leak detection is fragile with TruffleRuby") + end if respond_to?(:assert_nothing_leaked_memory) rb_obj_frozen_p_symbol = Fiddle.dlopen(nil)["rb_obj_frozen_p"] diff --git a/test/fiddle/test_handle.rb b/test/fiddle/test_handle.rb index c952a7ef..bdef9e8f 100644 --- a/test/fiddle/test_handle.rb +++ b/test/fiddle/test_handle.rb @@ -12,6 +12,9 @@ def test_to_i if RUBY_ENGINE == "jruby" omit("Fiddle::Handle#to_i is unavailable with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#to_i is unavailable with TruffleRuby") + end handle = Fiddle::Handle.new(LIBC_SO) assert_kind_of Integer, handle.to_i @@ -21,6 +24,9 @@ def test_to_ptr if RUBY_ENGINE == "jruby" omit("Fiddle::Handle#to_i is unavailable with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#to_i is unavailable with TruffleRuby") + end handle = Fiddle::Handle.new(LIBC_SO) ptr = handle.to_ptr @@ -37,6 +43,9 @@ def test_static_sym if RUBY_ENGINE == "jruby" omit("We can't assume static symbols with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("We can't assume static symbols with TruffleRuby") + end begin # Linux / Darwin / FreeBSD @@ -136,6 +145,9 @@ def test_file_name if RUBY_ENGINE == "jruby" omit("Fiddle::Handle#file_name doesn't exist in JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle#file_name doesn't exist in TruffleRuby") + end file_name = Handle.new(LIBC_SO).file_name if file_name @@ -158,6 +170,9 @@ def test_NEXT if RUBY_ENGINE == "jruby" omit("Fiddle::Handle::NEXT doesn't exist in JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Handle::NEXT doesn't exist in TruffleRuby") + end begin # Linux / Darwin diff --git a/test/fiddle/test_import.rb b/test/fiddle/test_import.rb index 26190325..2ef3edd7 100644 --- a/test/fiddle/test_import.rb +++ b/test/fiddle/test_import.rb @@ -157,6 +157,9 @@ def test_io() if RUBY_ENGINE == "jruby" omit("BUILD_RUBY_PLATFORM doesn't exist in JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("BUILD_RUBY_PLATFORM doesn't exist in TruffleRuby") + end if( RUBY_PLATFORM != BUILD_RUBY_PLATFORM ) || !defined?(LIBC.fprintf) return diff --git a/test/fiddle/test_pointer.rb b/test/fiddle/test_pointer.rb index f17c8338..56c2f4ea 100644 --- a/test/fiddle/test_pointer.rb +++ b/test/fiddle/test_pointer.rb @@ -14,6 +14,9 @@ def test_can_read_write_memory if RUBY_ENGINE == "jruby" omit("Fiddle::Pointer.{read,write} don't exist in JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Pointer.{read,write} don't exist in TruffleRuby") + end # Allocate some memory Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Fiddle::RUBY_FREE) do |pointer| @@ -116,6 +119,9 @@ def test_inspect if RUBY_ENGINE == "jruby" omit("Fiddle::Pointer#inspect is incompatible on JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Pointer#inspect is incompatible on TruffleRuby") + end ptr = Pointer.new(0) inspect = ptr.inspect @@ -135,6 +141,9 @@ def test_to_ptr_io if RUBY_ENGINE == "jruby" omit("Fiddle::Pointer.to_ptr(IO) isn't supported with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle::Pointer.to_ptr(IO) isn't supported with TruffleRuby") + end Pointer.malloc(10, Fiddle::RUBY_FREE) do |buf| File.open(__FILE__, 'r') do |f| @@ -186,6 +195,9 @@ def test_ref_ptr if RUBY_ENGINE == "jruby" omit("Fiddle.dlwrap([]) isn't supported with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle.dlwrap([]) isn't supported with TruffleRuby") + end ary = [0,1,2,4,5] addr = Pointer.new(dlwrap(ary)) @@ -198,6 +210,9 @@ def test_to_value if RUBY_ENGINE == "jruby" omit("Fiddle.dlwrap([]) isn't supported with JRuby") end + if RUBY_ENGINE == "truffleruby" + omit("Fiddle.dlwrap([]) isn't supported with TruffleRuby") + end ary = [0,1,2,4,5] addr = Pointer.new(dlwrap(ary))