如何在C++应用程序中完全初始化嵌入式Ruby VM?
我正在将ruby版本2.1.2嵌入到wxWidgets应用程序中,在Windows上编译并瞄准Windows。链接到msvcrt-ruby210.dll并调用如何在C++应用程序中完全初始化嵌入式Ruby VM?,ruby,embedded-ruby,ruby-c-extension,Ruby,Embedded Ruby,Ruby C Extension,我正在将ruby版本2.1.2嵌入到wxWidgets应用程序中,在Windows上编译并瞄准Windows。链接到msvcrt-ruby210.dll并调用 ruby_sysinit(&argc, &argv); RUBY_INIT_STACK; ruby_init(); ruby_init_loadpath(); 足够让我运行基本的VM和内置类了。但是,我也将标准库与我的应用程序打包在一起,因为我打算从我的应用程序中使用FileUtils和Resolv等工具。我可以要求并使
ruby_sysinit(&argc, &argv);
RUBY_INIT_STACK;
ruby_init();
ruby_init_loadpath();
足够让我运行基本的VM和内置类了。但是,我也将标准库与我的应用程序打包在一起,因为我打算从我的应用程序中使用FileUtils和Resolv等工具。我可以要求并使用一些库,但当我需要“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");
这清除了前面的错误,但留给我的是未找到UTF-8到UTF-16LE的代码转换器。通过添加额外的行rb_eval_stringrequire'enc/trans/transdb';,可以解决此问题;,但是,我并不想一块一块地复制ruby的ruby_options函数执行的初始化代码,所以我尝试直接使用它,就像在ruby自己的主函数中一样
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脚本/bootstrap.rb运行应用程序时才有效。ruby似乎忽略了我对ruby_选项的参数,并使用了系统提供的argc和argv值。这很麻烦,因为我希望我的应用程序只需双击可执行文件即可运行,而不需要用户提供指示引导脚本位置的命令行参数
那么,在这种情况下,是否有一个方便的API或一些咒语可以用来初始化ruby而不需要命令行参数
请注意,如果可能的话,我希望避免将我的应用程序打包为ruby扩展。我在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/transdb.so中找到Init_transdb。因此,我需要这些LIB和引导脚本,如下所示:
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_indexencdb之类的晦涩命令;在我的初始化代码中加入,这似乎是合理的
我仍然对任何更简单的替代方案感兴趣,并将暂缓接受这一答案——至少在一段时间内——直到我得到一些确认,证明我的做法是正确的。事实证明,这种方法确实相当有效。在使用RubyInstaller配方构建ruby之后,我能够以这种方式加载ruby,并且一切正常。我甚至可以在需要rubygems(包括pg和sequel)后加载rubygems。看起来这很好。