diff options
author | Lamont Granquist <lamont@scriptkiddie.org> | 2015-04-06 12:22:11 -0700 |
---|---|---|
committer | Lamont Granquist <lamont@scriptkiddie.org> | 2015-04-06 12:24:04 -0700 |
commit | 9a536029c699ee501d9278577a300a5ef3d147dd (patch) | |
tree | 7e3d63890d70f72a048a64cd6f4e52c9075d99fa | |
parent | 10c7da3b6002a59e21c9c8ee202f6f713c3959f9 (diff) | |
download | ffi-yajl-9a536029c699ee501d9278577a300a5ef3d147dd.tar.gz |
add native dlopen extension code
This will get dlopen in a consistent place on all the platforms
which need it.
-rw-r--r-- | Rakefile | 7 | ||||
-rw-r--r-- | ext/ffi_yajl/ext/dlopen/dlopen.c | 38 | ||||
-rw-r--r-- | ext/ffi_yajl/ext/dlopen/extconf.rb | 15 | ||||
-rw-r--r-- | ffi-yajl.gemspec | 3 | ||||
-rw-r--r-- | lib/ffi_yajl.rb | 8 | ||||
-rw-r--r-- | lib/ffi_yajl/ext.rb | 51 |
6 files changed, 69 insertions, 53 deletions
@@ -51,6 +51,13 @@ Rake::ExtensionTask.new do |ext| ext.gem_spec = spec end +Rake::ExtensionTask.new do |ext| + ext.name = 'dlopen' + ext.lib_dir = 'lib/ffi_yajl/ext' + ext.ext_dir = 'ext/ffi_yajl/ext/dlopen' + ext.gem_spec = spec +end + # # test tasks # diff --git a/ext/ffi_yajl/ext/dlopen/dlopen.c b/ext/ffi_yajl/ext/dlopen/dlopen.c new file mode 100644 index 0000000..7330763 --- /dev/null +++ b/ext/ffi_yajl/ext/dlopen/dlopen.c @@ -0,0 +1,38 @@ +#include <ruby.h> + +#if defined(HAVE_DLFCN_H) +# include <dlfcn.h> +#ifndef RTLD_LAZY +#define RTLD_LAZY 0 +#endif +#ifndef RTLD_GLOBAL +#define RTLD_GLOBAL 0 +#endif +#ifndef RTLD_NOW +#define RTLD_NOW 0 +#endif +#else +# if defined(_WIN32) +# include <windows.h> +# define dlopen(name,flag) ((void*)LoadLibrary(name)) +# define dlerror() strerror(rb_w32_map_errno(GetLastError())) +# define dlsym(handle,name) ((void*)GetProcAddress((handle),(name))) +# define RTLD_LAZY -1 +# define RTLD_NOW -1 +# define RTLD_GLOBAL -1 +# endif +#endif + +static VALUE mFFI_Yajl, mDlopen, mExt; + +static VALUE mDlopen_dlopen(VALUE self, VALUE file) { + dlopen(RSTRING_PTR(file), RTLD_NOW|RTLD_GLOBAL); + return Qnil; +} + +void Init_dlopen() { + mFFI_Yajl = rb_define_module("FFI_Yajl"); + mExt = rb_define_module_under(mFFI_Yajl, "Ext"); + mDlopen = rb_define_module_under(mExt, "Dlopen"); + rb_define_method(mDlopen, "dlopen", mDlopen_dlopen, 1); +} diff --git a/ext/ffi_yajl/ext/dlopen/extconf.rb b/ext/ffi_yajl/ext/dlopen/extconf.rb new file mode 100644 index 0000000..7e18469 --- /dev/null +++ b/ext/ffi_yajl/ext/dlopen/extconf.rb @@ -0,0 +1,15 @@ +require 'mkmf' +require 'rubygems' + +RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC'] + +puts $CFLAGS +puts $LDFLAGS + +have_header("dlfcn.h") + +have_library("dl", "dlopen") + +dir_config 'dlopen' + +create_makefile 'ffi_yajl/ext/dlopen' diff --git a/ffi-yajl.gemspec b/ffi-yajl.gemspec index 8e6943d..2801527 100644 --- a/ffi-yajl.gemspec +++ b/ffi-yajl.gemspec @@ -1,7 +1,6 @@ gemspec = eval(IO.read(File.expand_path(File.join(File.dirname(__FILE__), "ffi-yajl.gemspec.shared")))) gemspec.platform = Gem::Platform::RUBY -gemspec.extensions = %w{ ext/ffi_yajl/ext/encoder/extconf.rb ext/ffi_yajl/ext/parser/extconf.rb } +gemspec.extensions = %w{ ext/ffi_yajl/ext/encoder/extconf.rb ext/ffi_yajl/ext/parser/extconf.rb ext/ffi_yajl/ext/dlopen/extconf.rb } gemspec - diff --git a/lib/ffi_yajl.rb b/lib/ffi_yajl.rb index 7f39189..1787766 100644 --- a/lib/ffi_yajl.rb +++ b/lib/ffi_yajl.rb @@ -19,10 +19,10 @@ elsif ENV['FORCE_FFI_YAJL'] == "ffi" require 'ffi_yajl/ffi' elsif RUBY_PLATFORM == "java" require 'ffi_yajl/ffi' -elsif defined?(Yajl) - warn "the ffi-yajl and yajl-ruby gems have incompatible C libyajl libs and should not be loaded in the same Ruby VM" - warn "falling back to ffi which might work (or might not, no promises)" - require 'ffi_yajl/ffi' +#elsif defined?(Yajl) +# warn "the ffi-yajl and yajl-ruby gems have incompatible C libyajl libs and should not be loaded in the same Ruby VM" +# warn "falling back to ffi which might work (or might not, no promises)" +# require 'ffi_yajl/ffi' else begin require 'ffi_yajl/ext' diff --git a/lib/ffi_yajl/ext.rb b/lib/ffi_yajl/ext.rb index bc4d410..12f74d9 100644 --- a/lib/ffi_yajl/ext.rb +++ b/lib/ffi_yajl/ext.rb @@ -4,60 +4,17 @@ require 'ffi_yajl/encoder' require 'ffi_yajl/parser' require 'libyajl2' require 'ffi_yajl/map_library_name' +require 'ffi_yajl/ext/dlopen' module FFI_Yajl extend FFI_Yajl::MapLibraryName + extend FFI_Yajl::Ext::Dlopen + libname = map_library_name libpath = File.expand_path(File.join(Libyajl2.opt_path, libname)) - # - # FFS, what exactly was so wrong with DL.dlopen that ruby had to get rid of it??? - # - - def self.try_fiddle_dlopen(libpath) - require 'fiddle' - if defined?(Fiddle) && Fiddle.respond_to?(:dlopen) - ::Fiddle.dlopen(libpath) - true - else - false - end - rescue LoadError - return false - end - - def self.try_dl_dlopen(libpath) - require 'dl' - if defined?(DL) && DL.respond_to?(:dlopen) - ::DL.dlopen(libpath) - true - else - false - end - rescue LoadError - return false - end - - def self.try_ffi_dlopen(libpath) - require 'ffi' - require 'rbconfig' - extend ::FFI::Library - ffi_lib 'dl' - attach_function 'dlopen', :dlopen, [:string, :int], :void - if RbConfig::CONFIG['host_os'] =~ /linux/i - dlopen libpath, 0x102 # linux: RTLD_GLOBAL | RTLD_NOW - else - dlopen libpath, 0 - end - true - rescue LoadError - return false - end - - unless try_fiddle_dlopen(libpath) || try_dl_dlopen(libpath) || try_ffi_dlopen(libpath) - raise "cannot find dlopen via Fiddle, DL or FFI, what am I supposed to do?" - end + dlopen(libpath) class Parser require 'ffi_yajl/ext/parser' |