如何在C ++应用程序中完全初始化嵌入式ruby VM?

时间:2014-08-22 14:13:21

标签: ruby embedded-ruby ruby-c-extension

我将ruby版本2.1.2嵌入到wxWidgets应用程序中,在Windows上编译和定位。链接到msvcrt-ruby210.dll并调用

ruby_sysinit(&argc, &argv);
RUBY_INIT_STACK;
ruby_init();
ruby_init_loadpath();

足以让我运行基本的VM和内置类。但是,我也在使用我的应用程序打包标准库,因为我打算使用我的应用程序中的FileUtils和Resolv等工具。我可以require并使用一些库,但是当我require 'resolv'时,我收到错误报告unitialized constant Encoding::UTF_16LE。在ruby.c中进行了一些谷歌搜索和挖掘后,我发现我可以通过以下初始化代码解决这个问题......

ruby_sysinit(&argc, &argv);
RUBY_INIT_STACK;
ruby_init();
ruby_init_loadpath();
rb_enc_find_index("encdb");

这会清除之前的错误,但会留下code converter not found (UTF-8 to UTF-16LE)。这是通过添加额外的行rb_eval_string("require 'enc/trans/transdb'");来解决的,但是,我不希望逐个复制由ruby的ruby_options函数执行的初始化代码,因此我尝试直接使用它,如在ruby自己的main函数中......

int my_argc = 2;
char* arg1 = "myapp.exe";
char* arg2 = "scripts/bootstrap.rb";
char** my_argv = new char*[2]{arg1, arg2};

ruby_sysinit(&my_argc, &my_argv);
RUBY_INIT_STACK;
ruby_init();
ruby_run_node(ruby_options(my_argc, my_argv));

但是,只有在我使用myapp.exe scripts/bootstrap.rb运行我的应用程序时,这才有效。似乎ruby忽略了我ruby_options的参数并使用系统提供的argc&值。 argv(Apparently this has been the case for some time on Windows)。这很麻烦,因为我希望我的应用程序只需双击可执行文件就可以运行,而不需要用户提供指示“bootstrap”脚本位置的命令行参数。

那么,在这种情况下我是否可以使用方便的API或一些咒语来初始化ruby而不需要命令行参数?

请注意,如果可能的话,我希望避免将我的应用程序打包为ruby扩展。

1 个答案:

答案 0 :(得分:0)

我在pepper_main.c中注意到了这段代码,并怀疑这是关于我想要的。

static VALUE
init_libraries_internal(VALUE unused)
{
  extern void Init_enc();
  extern void Init_ext();

  init_loadpath();
  Init_enc();
  Init_ext();
  return Qnil;
}

据我所知,我不需要Init_ext(),因为我正在使用ruby dll,而且我不是静态编译我的扩展。所以,我尝试使用Init_enc。虽然msvcrt-ruby210.dll中存在此符号,但它在导入库(msvcrt-ruby210.dll.a)中不存在,因此我无法将其与我的应用程序链接。搜索lib \ ruby​​ \ 2.1.0 \ i386-mingw32 \ enc目录下的.so文件中的符号,我能够在encdb.so中找到Init_encdb,并在trans /中找到Init_transdb transdb.so。所以,我需要这些libs和我的bootstrap脚本,如下所示:

ruby_sysinit(&argc, &argv);
RUBY_INIT_STACK;
ruby_init();
ruby_init_loadpath();
rb_require("enc/encdb");
rb_require("enc/trans/transdb");
rb_require("./scripts/bootstrap");

这使我可以无错误地使用FileUtils和Resolv库。虽然我不能确定我不会遇到更多像这样的问题(我还没有尝试要求一个真正的宝石......)这是一个我更熟悉的解决方案。如果我可以通过一个简单的需求来解决任何即将出现的问题,而不是四处寻找像rb_enc_find_index("encdb");这样的模糊命令来填充我的初始化代码,那么这似乎是合理的。

我仍然对任何更简单的替代方案感兴趣,并且会暂时接受这个作为答案 - 至少一段时间 - 直到我收到一些确认我正确认识到这一点。