Skip to content

Instantly share code, notes, and snippets.

@Beyarz
Last active May 11, 2024 14:43
Show Gist options
  • Save Beyarz/66c879d915dc63d17295cdc025ed3cf5 to your computer and use it in GitHub Desktop.
Save Beyarz/66c879d915dc63d17295cdc025ed3cf5 to your computer and use it in GitHub Desktop.
Comprehensive guide to get working environment with MRuby

Getting started

Compile on Windows

  1. Install msys2 (because we need mingw64, gcc and libws2_32.a)
  2. Open msys2 or mingw64 and run pacman -S mingw64/mingw-w64-x86_64-mruby
  3. Get MRuby and extract the folder
  4. Run make inside the folder mruby-3.3.0, there will be a new folder called /build after the compilation, we need the file at /build/host/lib/libmruby.a
  5. Compile using the following command gcc main.c -I"mruby-3.3.0/include" "mruby-3.3.0/build/host/lib/libmruby.a" "C:\msys64\mingw64\lib\libws2_32.a" -lm -o main or substitue "C:\msys64\mingw64\lib\libws2_32.a" with -lws2_32
  6. Run the compiled binary main.exe
  7. Done

Compile to Unix from Windows

Using Docker

  1. Get MRuby and extract the folder
  2. docker run --rm -it -v .:/app -w /app appplant/mruby-cli sh in the folder
  3. Now you're in the container shell, run rake
  4. In our case, looking at the path (on Windows explorer) C:\Users\USER\Downloads\mruby-3.3.0\build\host\lib, you'll find libmruby.a. That is what you are going to need when compiling.
  5. Now when compiling (still in container shell), go to your other project where the main_rb_file.c is and run the following gcc main_rb_file.c -I"C:\Users\USER\Downloads\mruby-3.3.0\include" "C:\Users\USER\Downloads\mruby-3.3.0\build\host\lib\libmruby.a" -lm -pthread -o main (make sure to update the paths correctly)
  6. Done, you should have your main file now which can be executed on a unix machine

Bonus

  1. Extract the include/ folder and libmruby.a from mruby-3.3.0\build\host\lib and put these two into a new directory togheter with main_rb_file.c and code.rb
  2. Run docker run --rm -it -v .:/app -w /app appplant/mruby-cli sh in that folder
  3. After that you can simply run gcc main_rb_file.c -I"include/" libmruby.a -lm -pthread -o main_unix

The sweet thing here is that if you repeat the steps before the bonus but runned MRUBY_CONFIG=cross-mingw rake instead on step 3 and did the rest (including the bonus steps). You would be able to run gcc main_rb_file.c -I"include" win/lib/libmruby.a -lws2_32 -lm -o main_win to compile for windows.

To shorten the steps even further, you can simply wrap it in a empheral container: docker run --rm -it -v .:/app -w /app appplant/mruby-cli gcc main_rb_file.c -I"include" "unix/lib/libmruby.a" -lm -pthread -o main_unix

Compile to Windows from Unix

  1. Create a folder named something, in our case it is "mrubyyy"
  2. Add the files main_rb_file.c and code.rb (you can find them below) to the folder "mrubyyy"
  3. Download mruby-3.3.0 to mrubyyy and add it as subfolder, like so: mrubyyy/mruby-3.3.0
  4. Run docker run --rm -it -v .:/app -w /app appplant/mruby-cli sh in root folder (mrubyyy)
  5. In the container cd into the folder mruby-3.3.0: cd mruby-3.3.0, you should now be in the subfolder "mruby-3.3.0"
  6. Compile using windows config MRUBY_CONFIG=cross-mingw rake
  7. This is optional but run the tests make sure everything went well, rake test
  8. change directory to the root folder "mrubyyy", cd ..
  9. Run the following command to compile the project to Windows binary x86_64-w64-mingw32-gcc-posix main_rb_file.c -I"mruby-3.3.0/include" "mruby-3.3.0/build/cross-mingw/lib/libmruby.a" -lws2_32 -lm -o main_win
  10. Done, the binary "main_win.exe" should be executable on a Windows machine now

Build once run anywhere

Check out mruby-cli, it setups a project structure where you add your code and then it compiles your ruby code down to multiple platforms.

I also suggest adding the --static flag here https://github.com/hone/mruby-cli/blob/master/build_config.rb#L20 like so:

  [conf.cc, conf.cxx, conf.linker].each do |cc|
    cc.flags << "--static"
  end
// Compiled using:
// mrbc -B code code.rb
#include <stdint.h>
#ifdef __cplusplus
extern
#endif
const uint8_t code[] = {
0x52,0x49,0x54,0x45,0x30,0x33,0x30,0x30,0x00,0x00,0x00,0xab,0x4d,0x41,0x54,0x5a,
0x30,0x30,0x30,0x30,0x49,0x52,0x45,0x50,0x00,0x00,0x00,0x78,0x30,0x33,0x30,0x30,
0x00,0x00,0x00,0x2a,0x00,0x01,0x00,0x04,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x0f,
0x06,0x01,0x03,0x02,0x0c,0x57,0x03,0x00,0x30,0x01,0x00,0x01,0x38,0x01,0x69,0x00,
0x00,0x00,0x01,0x00,0x04,0x75,0x70,0x74,0x6f,0x00,0x00,0x00,0x00,0x42,0x00,0x03,
0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x34,0x04,0x00,0x00,0x51,0x04,
0x00,0x06,0x05,0x01,0x06,0x01,0x59,0x05,0x23,0x04,0x2d,0x03,0x00,0x01,0x38,0x03,
0x00,0x01,0x00,0x00,0x0d,0x48,0x65,0x6c,0x6c,0x6f,0x2c,0x20,0x77,0x6f,0x72,0x6c,
0x64,0x21,0x00,0x00,0x01,0x00,0x04,0x70,0x75,0x74,0x73,0x00,0x4c,0x56,0x41,0x52,
0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x01,0x00,0x05,0x69,0x6e,0x64,0x65,0x78,0x00,
0x00,0xff,0xff,0x45,0x4e,0x44,0x00,0x00,0x00,0x00,0x08,
};
0.upto(12) do |index|
puts "Hello, world!"[0..index]
end
# This file comes shipped with MRuby folder
# Ubuntu 20.04 requires at least `gcc-mingw-w64-x86-64` package as a
# cross compiler.
MRuby::CrossBuild.new("cross-mingw") do |conf|
conf.toolchain :gcc
conf.host_target = "x86_64-w64-mingw32" # required for `for_windows?` used by `mruby-socket` gem
conf.cc.command = "#{conf.host_target}-gcc-posix"
conf.linker.command = conf.cc.command
conf.archiver.command = "#{conf.host_target}-gcc-ar"
conf.exts.executable = ".exe"
conf.gembox "default"
end
// Compile from Ruby bytecode (code.c)
#include <mruby.h>
#include <mruby/irep.h>
#include <stdio.h>
#include <stdlib.h>
#include "code.c"
int main()
{
mrb_state *mrb = mrb_open();
if (!mrb)
puts("There was some error");
mrb_load_irep(mrb, code);
mrb_close(mrb);
return EXIT_SUCCESS;
}
// Compile from Ruby file (code.rb)
#include <mruby.h>
#include <mruby/compile.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
mrb_state *mrb = mrb_open();
if (!mrb)
puts("There was some error");
FILE *fp = fopen("code.rb", "r");
mrb_load_file(mrb, fp);
mrb_close(mrb);
fclose(fp);
return EXIT_SUCCESS;
}
# From https://hub.docker.com/r/appplant/mruby-cli
MRuby::CrossBuild.new('x86_64-w64-mingw32') do |conf|
toolchain :gcc
[conf.cc, conf.linker].each do |cc|
cc.command = 'x86_64-w64-mingw32-gcc'
cc.flags += %w[-Os -DPCRE_STATIC]
end
conf.cxx.command = 'x86_64-w64-mingw32-cpp'
conf.archiver.command = 'x86_64-w64-mingw32-gcc-ar'
conf.exts.executable = '.exe'
conf.build_target = 'x86_64-pc-linux-gnu'
conf.host_target = 'x86_64-w64-mingw32'
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment