Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 49 additions & 10 deletions lib/ffi/library.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,53 @@
module FFI
CURRENT_PROCESS = USE_THIS_PROCESS_AS_LIBRARY = 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}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to preserve the LIBSUFFIX-addition like so

      lib = "#{Platform::LIBPREFIX}#{name}"
      r = Platform::IS_WINDOWS || Platform::IS_MAC ? "\\.#{Platform::LIBSUFFIX}$" : "\\.so($|\\.[1234567890]+)"
      lib += ".#{Platform::LIBSUFFIX}" unless lib =~ /#{r}/
      lib

end
end

def to_s
if root
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see much value to pass root through LibraryPath. It can be equally prepended externally.

Copy link
Contributor Author

@ioquatix ioquatix Apr 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a more convenient interface:

e.g.

lib_path = __dir__ # or something
ffi_lib LibraryPath.new('vips', 42, lib_path)

It's easier to understand the intention of the user (a library in a given path) and easier to print out/debug later on.

A lot of native libraries follow this pattern, i.e. compile a shared library into a known path.

In theory, if someone provides a value of "/foo/bar/mylib.so", that would be split into a root and a name. However, in that case, the string is just returned since there is no point to manipulate it further. Without root we couldn't represent such values.

# 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 @@ -41,17 +88,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