【问题标题】:How do you fully initialize an embedded ruby VM in a C++ application?如何在 C++ 应用程序中完全初始化嵌入式 ruby​​ VM?
【发布时间】:2014-08-22 14:13:20
【问题描述】:

我正在将 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 等工具。我可以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​​ 自己的 @ 987654330@函数...

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) 值。这很麻烦,因为我希望我的应用程序只需双击可执行文件即可运行,并且不需要用户提供指示“引导”脚本位置的命令行参数。

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

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

【问题讨论】:

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


    【解决方案1】:

    我在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。所以,我需要这些库和我的引导脚本,如下所示:

    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 库。虽然我不能确定我不会遇到更多这样的问题(我还没有尝试过需要一个真正的宝石......)这是一个我更舒服的解决方案。如果我可以通过简单的 require 解决任何即将出现的问题,而不是四处寻找像 rb_enc_find_index("encdb"); 这样的晦涩命令来散布到我的初始化代码中,那么这似乎是合理的。

    我仍然对任何更简单的替代方案感兴趣,并且会推迟接受这个作为答案 - 至少有一段时间 - 直到我收到一些确认我正在正确地解决这个问题。

    【讨论】:

    • 这种方法确实被证明非常有效。在使用 RubyInstaller 配方构建 ruby​​ 之后(这让生活变得更轻松),我已经能够以这种方式加载 ruby​​ 并且一切正常。我什至可以加载红宝石宝石(在需要“红宝石”之后),包括 pg 和续集。看起来这很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-10
    • 2020-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多