ruby: dlopen libruby -- currently segfaults with rb1.9 ...

develop
jj 2012-06-02 23:44:52 +02:00
parent b612532348
commit 2aace670ea
2 changed files with 125 additions and 19 deletions

@ -1,15 +1,9 @@
find_package(Ruby)
if(RUBY_FOUND)
ADD_CUSTOM_COMMAND(
ADD_CUSTOM_COMMAND(
OUTPUT ruby-autogen.rb
COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/codegen.pl ${dfhack_SOURCE_DIR}/library/include/df/codegen.out.xml ${CMAKE_CURRENT_SOURCE_DIR}/ruby-autogen.rb
DEPENDS ${dfhack_SOURCE_DIR}/library/include/df/codegen.out.xml codegen.pl
)
ADD_CUSTOM_TARGET(ruby-autogen-rb ALL DEPENDS ruby-autogen.rb)
include_directories("${dfhack_SOURCE_DIR}/depends/tthread" ${RUBY_INCLUDE_PATH})
DFHACK_PLUGIN(ruby ruby.cpp LINK_LIBRARIES dfhack-tinythread)
target_link_libraries(ruby ${RUBY_LIBRARY})
install(FILES ruby.rb ruby-autogen.rb DESTINATION ${DFHACK_LIBRARY_DESTINATION})
else(RUBY_FOUND)
MESSAGE(STATUS "Required library (ruby) not found - ruby plugin can't be built.")
endif(RUBY_FOUND)
)
ADD_CUSTOM_TARGET(ruby-autogen-rb ALL DEPENDS ruby-autogen.rb)
include_directories("${dfhack_SOURCE_DIR}/depends/tthread")
DFHACK_PLUGIN(ruby ruby.cpp LINK_LIBRARIES dfhack-tinythread)
install(FILES ruby.rb ruby-autogen.rb DESTINATION ${DFHACK_LIBRARY_DESTINATION})

@ -11,8 +11,6 @@
#include "tinythread.h"
#include <ruby.h>
using namespace DFHack;
@ -20,6 +18,8 @@ using namespace DFHack;
// DFHack stuff
static int df_loadruby(void);
static void df_unloadruby(void);
static void df_rubythread(void*);
static command_result df_rubyload(color_ostream &out, std::vector <std::string> & parameters);
static command_result df_rubyeval(color_ostream &out, std::vector <std::string> & parameters);
@ -45,6 +45,11 @@ DFHACK_PLUGIN("ruby")
DFhackCExport command_result plugin_init ( color_ostream &out, std::vector <PluginCommand> &commands)
{
if (!df_loadruby()) {
Core::printerr("failed to load libruby\n");
return CR_FAILURE;
}
m_irun = new tthread::mutex();
m_mutex = new tthread::mutex();
r_type = RB_INIT;
@ -90,6 +95,8 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
m_mutex->unlock();
delete m_mutex;
df_unloadruby();
return CR_OK;
}
@ -191,6 +198,111 @@ static command_result df_rubyeval(color_ostream &out, std::vector <std::string>
// ruby stuff
// ruby-dev on windows is messy
// ruby.h on linux 64 is broken
// so we dynamically load libruby instead of linking it at compile time
// lib path can be set in dfhack.ini to use the system libruby, but by
// default we'll embed our own (downloaded by cmake)
// these ruby definitions are invalid for windows 64bit
typedef unsigned long VALUE;
typedef unsigned long ID;
#define Qfalse ((VALUE)0)
#define Qtrue ((VALUE)2)
#define Qnil ((VALUE)4)
#define INT2FIX(i) ((VALUE)((((long)i) << 1) | 1))
#define FIX2INT(i) (((long)i) >> 1)
#define RUBY_METHOD_FUNC(func) ((VALUE(*)(...))func)
VALUE *rb_eRuntimeError;
void (*ruby_sysinit)(int *, const char ***);
void (*ruby_init)(void);
void (*ruby_init_loadpath)(void);
void (*ruby_script)(const char*);
void (*ruby_finalize)(void);
ID (*rb_intern)(const char*);
VALUE (*rb_raise)(VALUE, const char*, ...);
VALUE (*rb_funcall)(VALUE, ID, int, ...);
VALUE (*rb_define_module)(const char*);
void (*rb_define_singleton_method)(VALUE, const char*, VALUE(*)(...), int);
void (*rb_define_const)(VALUE, const char*, VALUE);
void (*rb_load_protect)(VALUE, int, int*);
VALUE (*rb_gv_get)(const char*);
VALUE (*rb_str_new)(const char*, long);
VALUE (*rb_str_new2)(const char*);
char* (*rb_string_value_ptr)(VALUE*);
VALUE (*rb_eval_string_protect)(const char*, int*);
VALUE (*rb_ary_shift)(VALUE);
VALUE (*rb_float_new)(double);
double (*rb_num2dbl)(VALUE);
VALUE (*rb_int2inum)(long);
VALUE (*rb_uint2inum)(unsigned long);
unsigned long (*rb_num2ulong)(VALUE);
// end of rip(ruby.h)
DFHack::DFLibrary *libruby_handle;
// load the ruby library, initialize function pointers
static int df_loadruby(void)
{
const char *libpath =
#ifdef WIN32
"msvcrt-ruby191.dll";
#else
"libruby1.9.so.1.9.0";
#endif
libruby_handle = OpenPlugin(libpath);
if (!libruby_handle)
return 0;
if (!(rb_eRuntimeError = (VALUE*)LookupPlugin(libruby_handle, "rb_eRuntimeError")))
return 0;
// XXX does msvc support decltype ? might need a #define decltype typeof
// or just assign to *(void**)(&s) = ...
// ruby_sysinit is optional (ruby1.9 only)
ruby_sysinit = (decltype(ruby_sysinit))LookupPlugin(libruby_handle, "ruby_sysinit");
#define rbloadsym(s) if (!(s = (decltype(s))LookupPlugin(libruby_handle, #s))) return 0
rbloadsym(ruby_init);
rbloadsym(ruby_init_loadpath);
rbloadsym(ruby_script);
rbloadsym(ruby_finalize);
rbloadsym(rb_intern);
rbloadsym(rb_raise);
rbloadsym(rb_funcall);
rbloadsym(rb_define_module);
rbloadsym(rb_define_singleton_method);
rbloadsym(rb_define_const);
rbloadsym(rb_load_protect);
rbloadsym(rb_gv_get);
rbloadsym(rb_str_new);
rbloadsym(rb_str_new2);
rbloadsym(rb_string_value_ptr);
rbloadsym(rb_eval_string_protect);
rbloadsym(rb_ary_shift);
rbloadsym(rb_float_new);
rbloadsym(rb_num2dbl);
rbloadsym(rb_int2inum);
rbloadsym(rb_uint2inum);
rbloadsym(rb_num2ulong);
#undef rbloadsym
return 1;
}
static void df_unloadruby(void)
{
if (libruby_handle) {
ClosePlugin(libruby_handle);
libruby_handle = 0;
}
}
// ruby thread code
static void dump_rb_error(void)
{
@ -353,7 +465,7 @@ static VALUE rb_dfregister(VALUE self, VALUE name, VALUE descr)
*/
static VALUE rb_dfregister(VALUE self, VALUE name, VALUE descr)
{
rb_raise(rb_eRuntimeError, "not implemented");
rb_raise(*rb_eRuntimeError, "not implemented");
}
static VALUE rb_dfget_global_address(VALUE self, VALUE name)
@ -402,7 +514,7 @@ static VALUE rb_dfmalloc(VALUE self, VALUE len)
{
char *ptr = (char*)malloc(FIX2INT(len));
if (!ptr)
rb_raise(rb_eRuntimeError, "no memory");
rb_raise(*rb_eRuntimeError, "no memory");
memset(ptr, 0, FIX2INT(len));
return rb_uint2inum((long)ptr);
}