用Visual Studio 2017编译Ruby 2.5.0并集成在C++中

1、引言

在Windows上编译Ruby一直是一件要命的事情,虽然官方提供了Ruby Installer,但是从Ruby 1.9开始,Ruby Installer就是使用MinGW进行编译了,一般使用的话问题不大,但是如果你想要把Ruby解释器集成到自己的C/C++应用程序里面做深度开发的话,那么就意味着你必须要使用gcc作为后端(Ruby Installer只提供.a格式的lib库文件),那么也就意味着你可以和Visual Studio这个宇宙第一IDE说再见了……

我自己就有如上需求,主要是想要把Ruby嵌入游戏引擎中做脚本层(类似于其他引擎使用Lua、Python这种应用场景),所以折腾了很久。虽说Ruby一直都提供了win32的编译configure,但是在早期版本的VC的编译器下简直形同虚设,要么缺这个依赖要么缺那个依赖,总之就是完全编译不起来,令人窒息。

Visual Studio 2017之后情况开始好转,于是我尝试使用Visual Studio 2017进行Ruby的编译,虽然过程中也踩了些坑,但还是相对顺利地完成了编译,并且成功集成到了C++之中,下面就对整个过程做个总结。

2、准备

  1. 安装Visual Studio 2017,我用的是社区版。

  2. 编译Ruby最基本的自然是它的源码,可以从Ruby官网上下载,截至目前(2018年3月27日),latest stable release的Ruby版本号为2.5.0,因此我下载的就是2.5.0版本的Ruby。

    下载下来文件名为ruby-2.5.0.tar.gz,解压出来,这里假设源代码的目录为:D:\ruby,我们要安装到D:\ruby-bin中。

  3. 除了Ruby源代码之外,Ruby的编译还依赖于一些第三方扩展,比如dbmgdbmreadlineopensslzlib之类的,这些扩展你可用可不用,如果要用到的话就需要去编译,如果不用的话就不管它(如果不编译不用的扩展的话,在编译Ruby的时候就会提示你某某扩展将不会被安装,这个时候不要惊慌不要害怕,统统无视掉就行了 _(:з」∠)_)。这里我选择了opensslzlib作为依赖进行编译。

    . 首先去openssl官网上下载源码,我下载的是openssl-1.0.2n.tar.gz,,下载下来后本地解压,这里假设目录为:D:\openssl,为了编译openss,我们还需要安装Perl环境,这里简单地安装ActivePerl就行了(体积有点大);此外,还需要去nasm官网上下载nasm汇编器,我这里下载的是http://www.nasm.us/pub/nasm/releasebuilds/2.13.03/win64/nasm-2.13.03-installer-x64.exe,简单安装完即可,这里假设安装目录为D:\nasm

  4. 然后去zlib官网上下载源码,我下载的是zlib-1.2.11.tar.gz,同样地,下载下来后本地解压,这里假设目录为:D:\zlib

  5. 继续新建一个文件夹如D:\Dependency,然后在里面新建三个文件夹:D:\Dependency\binD:\Dependency\includeD:\Dependency\lib,之后我们编译好的依赖相关文件会分别放进这3个文件夹里面。

  6. 最后,在控制面板中打开系统和安全 -> 高级设置 -> 环境变量,然后在Path中添加D:\Dependency\bin以及D:\nasm,再新建一个INCLUDE,设定为D:\Dependency\include,最后再新建一个LIB然后设定为D:\Dependency\lib,这样一来,-上面2个依赖编译好的相关文件,在Ruby编译的时候就能够被找到了。

以上就是编译Ruby前所有准备工作。

3、编译过程

  1. 在开始菜单中打开Visual Studio 2017 -> 适用于 VS 2017 的 x64 本机命令提示,需要注意的是,这里我要编译的是64位的Ruby,所以选择的是64位的本机命令提示,如果你要编译32位的,则选择适用于 VS 2017 的 x86 本机命令提示,这个时候打开了一个命令行。

  2. 先编译openssl

    D:
    cd openssl
    perl Configure VC-WIN64A --prefix="D:/Dependency"
    nmake
    nmake test
    nmake install
    

    完成后,所需的文件就已经在D:\Dependency里面了。

  3. 然后编译zlib

    cd ..
    cd zlib
    nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF -I." OBJA="inffasx64.obj gvmat64.obj inffas8664.obj"
    

    编译完成后,还需要进一步把源代码目录下生成的以下文件分别拷贝到对应的文件夹里面:

    • zdll.exp/zdll.lib/zlib.lib/zlib.pdb/zlib1.pdb -> D:\Dependency\lib
    • zlib1.dll -> D:\Dependency\bin
    • zconf.h/zlib.h -> D:\Dependency\include
  4. 最后编译Ruby

    cd ..
    cd ruby
    win32\configure.bat --prefix=/ruby-bin --target=x64-mswin64
    nmake
    nmake test
    nmake install
    

    然后你就可以在D:\ruby-bin下面找到编译好的Ruby啦~ (〃'▽'〃)

4、集成

接下来说说怎么在VC++中调用Ruby解释器。

想要在VC++中调用Ruby解释器需要这么几个文件:

  • 所有的头文件:D:\ruby-bin\include

  • 动态运行库文件:D:\ruby-bin\x64-vcruntime140-ruby250.dll

  • 静态链接库文件:D:\ruby-bin\lib\x64-vcruntime140-ruby250.lib

如果你不想要动态运行库的话,那么可以使用静态运行库:D:\ruby-bin\x64-vcruntime140-ruby250-static.lib.dll文件。

首先,新建一个Visual Studio的C++工程,这个我就不细讲了(这个如果还要细讲的话,估计你上面那一坨都没搞定),然后把上面的文件复制到工程目录下。

接下来是配置Visual Studio工程的头文件搜索路径,把下面3个路径添加到属性 -> VC++ 目录 -> 包含目录中就行了:

  • include\ruby-2.5.0\x64-mswin64_140
  • include\ruby-2.5.0
  • include

新建一个main.cpp,编写如下代码,代码的功能在注释里面已经写好了。

#include <string>

// 把Ruby的头文件包含进来,里面包含了所有集成Ruby所需的函数声明
#include "include\ruby-2.5.0\ruby.h"

// 把静态链接库link进来
#pragma comment(lib, "x64-vcruntime140-ruby250.lib")

int main(int argc, char* argv[]) {

    // 初始化Ruby环境和堆栈。注意,从某个Ruby版本之后,这两行就绝对不能少
    ruby_sysinit(&argc, &argv);
    RUBY_INIT_STACK

    // 初始化Ruby解释器
    ruby_init();
    
    // 初始化Ruby加载路径
    ruby_init_loadpath();
    
    // 为$0命名
    ruby_script("embeedded");

    // 在Ruby中创建一个字符串
    auto str = std::string("Hello! I'm Ruby from Visual Studio!");
    auto rbStr = rb_str_new(str.c_str(), str.length());

    // 调用p方法显示字符串
    rb_p(rbStr);

    // 关闭Ruby解释器
    ruby_finalize();

    return 0;
}

需要注意的是,生成目标一定要选择x64,不然会编译不过,原因是ruby.h的第108行是这么写的:

typedef char ruby_check_sizeof_voidp[SIZEOF_VOIDP == sizeof(void*) ? 1 : -1];

而对于SIZEOF_VOIDP的定义为:

#define SIZEOF_VOIDP 8

也就是说如果你编译的是64位版本的Ruby的话,那么头文件中会把VOIDP默认为64位长度,如果你还是32位的编译目标的话,sizeof(void*)就是4,这里就编译不通过了(数组的索引为负数,使得编译器强行报错,算是一种trick)。

如果你编译的Ruby是32位的话,同理。

运行结果:

运行结果

5、总结

关于Ruby编译集成的相关内容就这么多了,更多相关的可以关注Ruby的github项目:https://github.com/ruby/ruby

Ruby相关的C API在这里:https://github.com/ruby/ruby/blob/trunk/doc/extension.rdoc

希望本文能够帮到你,不用像多年以前的我那样无头苍蝇一般地满世界乱搜 (*╹▽╹*)

顺便吐槽一下,真希望Windows下也能有apt-get这样的神物啊 _(:з」∠)_

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容

  • 图片发自简书App 问题分类 - 简单问题 - 复杂问题 - 不确定的极端负责问题 清单解决方案 - 简单问题:执...
    艾莉娅的缝衣针阅读 203评论 0 0
  • 还记得前面几年,产品经理这词刚在国内兴起,大家对这一职业还没有清晰认识的时候,就被各媒体以零门槛高回报的宣传口号拿...
    小声讲故事阅读 389评论 0 1
  • 在工作中,我们难免遇到“小白”,其实有时候,我们也是从“小白”做起。要在最短时间内把关键内容交代给一个非本领域...
    嘟鼓鼓阅读 86评论 0 1
  • 学会拒绝 铁骨柔情铸警魂文/铁骨柔情人生在世,要有一份热心。帮助他人是快乐的,有热心才能助人。但很多时候,还要学会...
    铁骨柔情青岛阅读 297评论 0 0
  • 今天要上学了会儿德语,然后妈妈就急急忙忙地回来,说姥姥病倒了,然后我们两个赶紧打的去姥姥家看看。 出租车里有司机的...
    虾肉云吞阅读 150评论 0 0