Class: FFI::DynamicLibrary

Inherits:
Object
  • Object
show all
Defined in:
lib/ffi/dynamic_library.rb,
ext/ffi_c/DynamicLibrary.c

Defined Under Namespace

Classes: Symbol

Constant Summary collapse

SEARCH_PATH =
%w[/usr/lib /usr/local/lib /opt/local/lib]
SEARCH_PATH_MESSAGE =
"Searched in <system library path>, #{SEARCH_PATH.join(', ')}".freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(libname, libflags) ⇒ FFI::DynamicLibrary

A new DynamicLibrary instance.

Parameters:

  • libname (String)

    name of library to open

  • libflags (Fixnum)

    flags for library to open

Raises:

  • (LoadError)

    if libname cannot be opened



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'ext/ffi_c/DynamicLibrary.c', line 136

static VALUE
library_initialize(VALUE self, VALUE libname, VALUE libflags)
{
    Library* library;
    int flags;

    Check_Type(libflags, T_FIXNUM);

    TypedData_Get_Struct(self, Library, &rbffi_library_data_type, library);
    flags = libflags != Qnil ? NUM2UINT(libflags) : 0;

    library->handle = dl_open(libname != Qnil ? StringValueCStr(libname) : NULL, flags);
    if (library->handle == NULL) {
        char errmsg[1024];
        dl_error(errmsg, sizeof(errmsg));
        rb_raise(rb_eLoadError, "Could not open library '%s': %s",
                libname != Qnil ? StringValueCStr(libname) : "[current process]",
                errmsg);
    }
#ifdef __CYGWIN__
    // On Cygwin 1.7.17 "dlsym(dlopen(0,0), 'getpid')" fails. (dlerror: "No such process")
    // As a workaround we can use "dlsym(RTLD_DEFAULT, 'getpid')" instead.
    // Since 0 == RTLD_DEFAULT we won't call dl_close later.
    if (libname == Qnil) {
        dl_close(library->handle);
        library->handle = RTLD_DEFAULT;
    }
#endif
    rb_iv_set(self, "@name", libname != Qnil ? rb_str_new_frozen(libname) : rb_str_new2("[current process]"));

    rb_obj_freeze(self);
    return self;
}

Instance Attribute Details

#nameObject (readonly)

Class Method Details

.last_errorString

Returns library’s last error string.

Returns:

  • (String)

    library’s last error string



187
188
189
190
191
192
193
# File 'ext/ffi_c/DynamicLibrary.c', line 187

static VALUE
library_dlerror(VALUE self)
{
    char errmsg[1024];
    dl_error(errmsg, sizeof(errmsg));
    return rb_str_new2(errmsg);
}

.load_library(name, flags) ⇒ Object (private)



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/ffi/dynamic_library.rb', line 40

def self.load_library(name, flags)
  if name == FFI::CURRENT_PROCESS
    FFI::DynamicLibrary.open(nil, RTLD_LAZY | RTLD_LOCAL)
  else
    flags ||= RTLD_LAZY | RTLD_LOCAL

    libnames = (name.is_a?(::Array) ? name : [name])
    libnames = libnames.map(&:to_s).map { |n| [n, FFI.map_library_name(n)].uniq }.flatten.compact
    errors = []

    libnames.each do |libname|
      lib = try_load(libname, flags, errors)
      return lib if lib

      unless libname.start_with?("/") || FFI::Platform.windows?
        SEARCH_PATH.each do |prefix|
          path = "#{prefix}/#{libname}"
          if File.exist?(path)
            lib = try_load(path, flags, errors)
            return lib if lib
          end
        end
      end
    end

    raise LoadError, [*errors, SEARCH_PATH_MESSAGE].join(".\n")
  end
end

.open(libname, libflags) ⇒ FFI::DynamicLibrary

Open a library.

Parameters:

  • libname (String)

    name of library to open

  • libflags (Fixnum)

    flags for library to open

Returns:

Raises:

  • (LoadError)

    if libname cannot be opened



122
123
124
125
126
# File 'ext/ffi_c/DynamicLibrary.c', line 122

static VALUE
library_open(VALUE klass, VALUE libname, VALUE libflags)
{
    return library_initialize(library_allocate(klass), libname, libflags);
}

.try_load(libname, flags, errors) ⇒ Object (private)



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/ffi/dynamic_library.rb', line 70

def self.try_load(libname, flags, errors)
  begin
    lib = FFI::DynamicLibrary.open(libname, flags)
    return lib if lib

  # LoadError for C ext & JRuby, RuntimeError for TruffleRuby
  rescue LoadError, RuntimeError => ex
    if ex.message =~ /(([^ \t()])+\.so([^ \t:()])*):([ \t])*(invalid ELF header|file too short|invalid file format)/
      if File.binread($1) =~ /(?:GROUP|INPUT) *\( *([^ \)]+)/
        return try_load($1, flags, errors)
      end
    end

    errors << ex
    nil
  end
end

Instance Method Details

#find_function(name) ⇒ FFI::DynamicLibrary::Symbol

Returns library function symbol.

Parameters:

  • name (String)

    library function’s name

Returns:



170
171
172
173
174
175
176
177
178
179
180
181
# File 'ext/ffi_c/DynamicLibrary.c', line 170

static VALUE
library_dlsym(VALUE self, VALUE name)
{
    Library* library;
    void* address = NULL;
    Check_Type(name, T_STRING);

    TypedData_Get_Struct(self, Library, &rbffi_library_data_type, library);
    address = dl_sym(library->handle, StringValueCStr(name));

    return address != NULL ? symbol_new(self, address, name) : Qnil;
}

#find_symbol(name) ⇒ FFI::DynamicLibrary::Symbol

Returns library symbol.

Parameters:

  • name (String)

    library symbol’s name

Returns:



170
171
172
173
174
175
176
177
178
179
180
181
# File 'ext/ffi_c/DynamicLibrary.c', line 170

static VALUE
library_dlsym(VALUE self, VALUE name)
{
    Library* library;
    void* address = NULL;
    Check_Type(name, T_STRING);

    TypedData_Get_Struct(self, Library, &rbffi_library_data_type, library);
    address = dl_sym(library->handle, StringValueCStr(name));

    return address != NULL ? symbol_new(self, address, name) : Qnil;
}

#find_variable(name) ⇒ FFI::DynamicLibrary::Symbol

Returns library variable symbol.

Parameters:

  • name (String)

    library variable’s name

Returns:



170
171
172
173
174
175
176
177
178
179
180
181
# File 'ext/ffi_c/DynamicLibrary.c', line 170

static VALUE
library_dlsym(VALUE self, VALUE name)
{
    Library* library;
    void* address = NULL;
    Check_Type(name, T_STRING);

    TypedData_Get_Struct(self, Library, &rbffi_library_data_type, library);
    address = dl_sym(library->handle, StringValueCStr(name));

    return address != NULL ? symbol_new(self, address, name) : Qnil;
}

#last_errorString

Returns library’s last error string.

Returns:

  • (String)

    library’s last error string



187
188
189
190
191
192
193
# File 'ext/ffi_c/DynamicLibrary.c', line 187

static VALUE
library_dlerror(VALUE self)
{
    char errmsg[1024];
    dl_error(errmsg, sizeof(errmsg));
    return rb_str_new2(errmsg);
}