summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Kanis <lars@greiz-reinsdorf.de>2023-05-08 13:25:45 +0200
committerGitHub <noreply@github.com>2023-05-08 13:25:45 +0200
commit73c36d77d76ef681cade4c4024abfe73af8a38b6 (patch)
tree1aa0e209aaaec9668be5d040627b9529a419c6df
parentc6b7139d0394638ef51b451b81dcd2ffefb94160 (diff)
parentc95b8f3664299ff60fa06073ab0ad77f4d5ed3d0 (diff)
downloadffi-master.tar.gz
Merge pull request #963 from ioquatix/library-pathHEADmaster
Add support for passing ABI version to `FFI.map_library_name`.
-rw-r--r--lib/ffi/library.rb59
-rw-r--r--spec/ffi/ffi_spec.rb9
2 files changed, 58 insertions, 10 deletions
diff --git a/lib/ffi/library.rb b/lib/ffi/library.rb
index c23112b..2556975 100644
--- a/lib/ffi/library.rb
+++ b/lib/ffi/library.rb
@@ -33,6 +33,53 @@ require 'ffi/dynamic_library'
module FFI
CURRENT_PROCESS = USE_THIS_PROCESS_AS_LIBRARY = FFI.make_shareable(Object.new)
+ class LibraryPath < ::Struct.new(:name, :abi_number, :root)
+ PATTERN = /(#{Platform::LIBPREFIX})?(?<name>.*?)(\.|\z)/
+
+ def self.wrap(value)
+ # We allow instances of LibraryPath to pass through transparently:
+ return value if value.is_a?(self)
+
+ # We special case a library named 'c' to be the standard C library:
+ return Library::LIBC if value == 'c'
+
+ # If provided a relative file name we convert it into a library path:
+ if value && File.basename(value) == value
+ if match = PATTERN.match(value)
+ return self.new(match[:name])
+ end
+ end
+
+ # Otherwise, we assume it's a full path to a library:
+ return value
+ end
+
+ def full_name
+ # If the abi_number is given, we format it specifically according to platform rules:
+ if abi_number
+ if Platform.windows?
+ "#{Platform::LIBPREFIX}#{name}-#{abi_number}.#{Platform::LIBSUFFIX}"
+ elsif Platform.mac?
+ "#{Platform::LIBPREFIX}#{name}.#{abi_number}.#{Platform::LIBSUFFIX}"
+ else # Linux? BSD? etc.
+ "#{Platform::LIBPREFIX}#{name}.#{Platform::LIBSUFFIX}.#{abi_number}"
+ end
+ else
+ # Otherwise we just use a generic format:
+ "#{Platform::LIBPREFIX}#{name}.#{Platform::LIBSUFFIX}"
+ end
+ end
+
+ def to_s
+ if root
+ # If the root path is given, we generate the full path:
+ File.join(root, full_name)
+ else
+ full_name
+ end
+ end
+ end
+
# @param [#to_s] lib library name
# @return [String] library name formatted for current platform
# Transform a generic library name to a platform library name
@@ -43,17 +90,9 @@ module FFI
# # Windows
# FFI.map_library_name 'c' # -> "msvcrt.dll"
# FFI.map_library_name 'jpeg' # -> "jpeg.dll"
- def self.map_library_name(lib)
+ def self.map_library_name(value)
# Mangle the library name to reflect the native library naming conventions
- lib = Library::LIBC if lib == 'c'
-
- if lib && File.basename(lib) == lib
- lib = Platform::LIBPREFIX + lib unless lib =~ /^#{Platform::LIBPREFIX}/
- r = Platform::IS_WINDOWS || Platform::IS_MAC ? "\\.#{Platform::LIBSUFFIX}$" : "\\.so($|\\.[1234567890]+)"
- lib += ".#{Platform::LIBSUFFIX}" unless lib =~ /#{r}/
- end
-
- lib
+ LibraryPath.wrap(value).to_s
end
# Exception raised when a function is not found in libraries
diff --git a/spec/ffi/ffi_spec.rb b/spec/ffi/ffi_spec.rb
index 4de5310..608cd99 100644
--- a/spec/ffi/ffi_spec.rb
+++ b/spec/ffi/ffi_spec.rb
@@ -24,6 +24,15 @@ describe "FFI" do
expect(FFI.map_library_name('c')).to eq(FFI::Library::LIBC)
end
+ it "should return library path with abi version" do
+ expect(FFI.map_library_name(FFI::LibraryPath.new('vips', 42))).to be =~ /#{prefix}vips.*42/
+ end
+
+ it "should return library path with root" do
+ root = "/non/existant/root"
+
+ expect(FFI.map_library_name(FFI::LibraryPath.new('vips', 42, root))).to be =~ /#{root}/#{prefix}vips.*42/
+ end
end
describe "VERSION" do