1

I am embedding ruby version 2.1.2 into a wxWidgets application, compiling on - and targeting - Windows. Linking to msvcrt-ruby210.dll and calling

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

is enough to get me running with the basic VM and built-in classes. However, I am also packaging the standard library with my application, as I intend use facilities like FileUtils and Resolv from my application. I can require and use some of the libraries just fine, yet when I require 'resolv' I get an error reporting unitialized constant Encoding::UTF_16LE. After some googling and digging around in ruby.c, I've found I can fix this with the following initialization code...

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

Which clears the previous error, but leaves me with code converter not found (UTF-8 to UTF-16LE). This is fixed by adding an additional line rb_eval_string("require 'enc/trans/transdb'");, but, it is not my desire to replicate, piece by piece, the initialization code performed by ruby's ruby_options function, so I tried to use it directly, as in ruby's own main function...

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));

This, however, is only effective if I run my application with myapp.exe scripts/bootstrap.rb. It seems that ruby is ignoring my parameters to ruby_options and using the system supplied values of argc & argv (Apparently this has been the case for some time on Windows). This is bothersome, as I would like my application to run with a simple double-click of the executable, and not require users to supply command line arguments indicating the location of the "bootstrap" script.

So, is there a convenient API or some incantation I can use to initialize ruby in this case without requiring the command line parameters?

Note that if at all possible, I would like to avoid having to package my application as a ruby extension.

jared
  • 151
  • 2
  • 9

1 Answers1

1

I noticed this code in pepper_main.c, and suspected this was doing about what I wanted.

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

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

As far as I can figure, I don't need Init_ext() since I'm using the ruby dll, and I'm not statically compiling my extensions. So, I tried just using Init_enc. While this symbol is present in the msvcrt-ruby210.dll, it's not present in the import library (msvcrt-ruby210.dll.a) so I wasn't able to link it with my application. Searching through the symbols in the .so files under the lib\ruby\2.1.0\i386-mingw32\enc directory, I was able to find Init_encdb in encdb.so, and Init_transdb in trans/transdb.so. So, I've required these libs and my bootstrap script as shown below:

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");

This enables me to use the FileUtils and Resolv libraries without error. While I can't be sure I won't run into more issues like this (I've yet to try requiring an actual gem...) this is a solution I'm more comfortable with. If I can resolve any forthcoming issues with a simple require, as opposed to digging around to find obscure commands like rb_enc_find_index("encdb"); to sprinkle into my initialization code, then that seems reasonable.

I am still interested in any simpler alternatives, and will hold off on accepting this as the answer - for a while, at least - until I receive some confirmation that I'm going about this correctly.

jared
  • 151
  • 2
  • 9
  • This approach has indeed proved quite effective. After building ruby with the RubyInstaller recipes (which makes life much easier) I've been able to load ruby in the manner and everything just works. I'm even able to load ruby gems (after requiring "rubygems") including pg and sequel. Looks like this is good-to-go. – jared Sep 08 '14 at 23:00