Skip to content

Commit

Permalink
Merge pull request #963 from ioquatix/library-path
Browse files Browse the repository at this point in the history
Add support for passing ABI version to `FFI.map_library_name`.
  • Loading branch information
larskanis committed May 8, 2023
2 parents c6b7139 + c95b8f3 commit 73c36d7
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 10 deletions.
59 changes: 49 additions & 10 deletions lib/ffi/library.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,53 @@
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
Expand All @@ -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
Expand Down
9 changes: 9 additions & 0 deletions spec/ffi/ffi_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@
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
Expand Down

0 comments on commit 73c36d7

Please sign in to comment.