在一个程序里使用多种语言进行开发,出发点有若干种:
- 为了性能,嵌入低级语言的代码进行优化。
- 为了开发效率,嵌入高级语言减少代码行数。
- 重用一些成熟的工具和库文件。
- DSL简化配置,降低维护成本。
最近因为要重用一段C++代码,遇到了原来代码逻辑比较复杂的问题。新项目是一段测试程序,首选是一种解释语言。想在脚本中重用这些功能,完全重写的代价比较高,需要花费精力理清原来程序的逻辑。好在输入和输出的内容都很简单,而Ruby提供了可以方便利用的接口,写一个功能扩展来调用旧的C++代码似乎是一个说得过去的选择。
C++的接口为:
std::string PrivateUtil::getInfo(std::string);
首先创建一个文件private_util.cc,包含头文件ruby.h
#include <ruby.h>
#include "album_util.h"
然后声明所有要实现的功能,与ruby脚本通讯:
VALUE getInfo(VALUE input_str);
下一步,开始进入模块功能注册,也是这个文件的核心。定义一个Ruby的Module,名字为PrivateUtil;另外定义一个getInfo的方法,并且用刚才声明的getInfo与之对应。
extern "C" void Init_foo()
{
VALUE private_util = rb_define_module("PrivateUtil");
rb_define_module_function(private_util, "getInfo", RUBY_METHOD_FUNC(getInfo), 2);
}
现在可以去实现getInfo的具体逻辑了。getInfo的实现也很简单,调用了旧代码的接口,返回一个ruby_str即可。这个返回值需要是ruby的数据类型,以便在脚本中直接使用。
VALUE getInfo(VALUE input_str)
{
return ruby_str_new2(PrivateUtil::getInfo(input_str));
}
到此步骤,c++文件基本完成。
下面开始,建立extconf.rb
require 'mkmf'
$libs = '-lstdc++'
create_makefile 'private_util'
执行
ruby extconf.rb && make
自动生成一个Makefile文件。make后生成了可供ruby脚本调用的so文件:private_util.so。
直接在ruby中调用private_util:
irb > require 'private_util'
true
irb > PrivateUtils::getInfo("abc")
"abc"
如果想在系统全局使用,可以执行make install,这样就能在其它脚本里方面调用。
欢迎交流使用心得。http://www.liulantao.com/