C++程序中嵌入Ruby脚本系统

什么是Ruby?
    Ruby,一种为简单快捷面向对象编程(面向对象程序设计)而创的脚本语言,由日本人*(まつもとゆきひろ,英译:Yukihiro Matsumoto,外号matz)开发,遵守GPL协议和Ruby License。Ruby的作者认为Ruby > (Smalltalk + Perl) / 2,表示Ruby是一个语法像Smalltalk一样完全面向对象、脚本执行、又有Perl强大的文字处理功能的编程语言。

什么是SWIG?
    SWIG(Simplified Wrapper and Interface Generator)是个帮助使用C或者C++编写的软件能与其它各种高级编程语言进行嵌入联接的开发工具。SWIG能应用于各种不同类型的语言包括常用脚本编译语言例如Perl, PHP, Python, Tcl, Ruby and PHP。
  简单来说,主要用于导出C/C++程序库给脚本语言使用的一个自动化工具.导出的工作是非常机械化,而且繁复的.

编译环境设置
    Ruby在Windows下:
    头文件在$RUBY_HOME/lib/ruby/1.8/i386-mswin32;
    lib在$RUBY_HOME/lib,为msvcrt-ruby18.lib;
    dll在RUBY_HOME/bin,其实只有一个dll,就是:msvcrt-ruby18.dll.
    在这里需要注意到的是,$RUBY_HOME/lib/ruby/1.8/i386-mswin32/config.h这个文件对VC的版本做了限制:

C++程序中嵌入Ruby脚本系统#if _MSC_VER != 1200
C++程序中嵌入Ruby脚本系统#error MSC version unmatch
C++程序中嵌入Ruby脚本系统#endif
    所以,如果VC不是这个版本的话,编译是通不过的,对此问题,最简单的办法就是:将这三行代码注释掉,就可以了.

C++解释器包裹代码
头文件
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统#ifndef __RubyInterpreter_H__
C++程序中嵌入Ruby脚本系统#define __RubyInterpreter_H__
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统#include <string>
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统typedef unsigned long    VALUE;
C++程序中嵌入Ruby脚本系统typedef std::string        String;
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统typedef VALUE(*staticValueMethod)(C++程序中嵌入Ruby脚本系统);
C++程序中嵌入Ruby脚本系统typedef VALUE(*ProtectedMethod)(VALUE);
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统class RubyInterpreter
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统public:
C++程序中嵌入Ruby脚本系统    RubyInterpreter();
C++程序中嵌入Ruby脚本系统    virtual ~RubyInterpreter();
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统public:
C++程序中嵌入Ruby脚本系统    /// 初始化解释器
C++程序中嵌入Ruby脚本系统    void initializeInterpreter();
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    /// 终止解释器
C++程序中嵌入Ruby脚本系统    void finalizeInterpreter();
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    /// 设置
C++程序中嵌入Ruby脚本系统    void setOutputFunction(staticValueMethod func);
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    /// 加入引用库的搜索路径
C++程序中嵌入Ruby脚本系统    void addSearchPath(const String& path);
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统public:
C++程序中嵌入Ruby脚本系统    /// 执行语句
C++程序中嵌入Ruby脚本系统    bool execute(const String& command);
C++程序中嵌入Ruby脚本系统    
C++程序中嵌入Ruby脚本系统    /// 执行文件
C++程序中嵌入Ruby脚本系统    bool executeFile(String rubyfile);
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统private:
C++程序中嵌入Ruby脚本系统    /// 记录错误日志
C++程序中嵌入Ruby脚本系统    void logRubyErrors(const std::string& intro, int errorcode);
C++程序中嵌入Ruby脚本系统    
C++程序中嵌入Ruby脚本系统    /// 
C++程序中嵌入Ruby脚本系统    void loadProtected(ProtectedMethod func, VALUE args,
C++程序中嵌入Ruby脚本系统        const std::string& msg, bool exitOnFail = false);
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    /// 
C++程序中嵌入Ruby脚本系统    static VALUE loadDlls(VALUE);
C++程序中嵌入Ruby脚本系统}
;
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统#endif
C++程序中嵌入Ruby脚本系统
源文件
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统#include "StdAfx.h"
C++程序中嵌入Ruby脚本系统#include "RubyInterpreter.h"
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统#include "FixRubyHeaders.h"
C++程序中嵌入Ruby脚本系统#include <ruby.h>
C++程序中嵌入Ruby脚本系统#include "FixRubyHeaders.h"
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统RubyInterpreter::RubyInterpreter()
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统}

C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统RubyInterpreter::~RubyInterpreter()
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统}

C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统void RubyInterpreter::initializeInterpreter()
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统#if defined(NT)
C++程序中嵌入Ruby脚本系统    static int dummyargc(0);
C++程序中嵌入Ruby脚本系统    static char** vec;
C++程序中嵌入Ruby脚本系统    NtInitialize(&dummyargc, &vec);
C++程序中嵌入Ruby脚本系统#endif
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    // 初始化Ruby
C++程序中嵌入Ruby脚本系统
    ruby_init();
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    // 使用UTF8编码
C++程序中嵌入Ruby脚本系统
    execute( "$KCODE = 'u'" );
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    // addSearchPath();
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    
// 初始化脚本加载路径
C++程序中嵌入Ruby脚本系统
    ruby_init_loadpath();
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    // 设置安全级别
C++程序中嵌入Ruby脚本系统
    rb_set_safe_level(0);
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    // 
C++程序中嵌入Ruby脚本系统
    ruby_script("ruby");
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    //loadProtected(&RubyInterpreter::loadDlls, 0, "Ruby error while loading dlls");
C++程序中嵌入Ruby脚本系统
}

C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统void RubyInterpreter::finalizeInterpreter()
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统    ruby_finalize();
C++程序中嵌入Ruby脚本系统}

C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统void RubyInterpreter::setOutputFunction(staticValueMethod func)
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统    rb_defout = rb_str_new("", 0);
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    // 定义一个虚拟类的方法
C++程序中嵌入Ruby脚本系统
    rb_define_singleton_method(rb_defout, "write", func, 1);
C++程序中嵌入Ruby脚本系统}

C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统void RubyInterpreter::addSearchPath(const String& path)
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统    ruby_incpush(path.c_str());
C++程序中嵌入Ruby脚本系统}

C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统VALUE RubyInterpreter::loadDlls(VALUE val)
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统    String lib;
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    // 
C++程序中嵌入Ruby脚本系统
    return rb_require(lib.c_str());
C++程序中嵌入Ruby脚本系统}

C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统void RubyInterpreter::loadProtected(ProtectedMethod func,
C++程序中嵌入Ruby脚本系统                                    VALUE val, 
C++程序中嵌入Ruby脚本系统                                    const std::string& msg, 
C++程序中嵌入Ruby脚本系统                                    bool exitOnFail)
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统    int error = 0;
C++程序中嵌入Ruby脚本系统    rb_protect(func, val, &error);
C++程序中嵌入Ruby脚本系统    logRubyErrors("Ruby error while initializing", error);
C++程序中嵌入Ruby脚本系统}

C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统void RubyInterpreter::logRubyErrors(const std::string& intro, int errorcode)
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统    if (errorcode != 0)
C++程序中嵌入Ruby脚本系统    {
C++程序中嵌入Ruby脚本系统        VALUE info = rb_inspect(ruby_errinfo);
C++程序中嵌入Ruby脚本系统        rb_backtrace();
C++程序中嵌入Ruby脚本系统        if (intro.length() > 0)
C++程序中嵌入Ruby脚本系统        {
C++程序中嵌入Ruby脚本系统        }

C++程序中嵌入Ruby脚本系统    }

C++程序中嵌入Ruby脚本系统}

C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统bool RubyInterpreter::execute(const String& command)
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统    int status = -1;
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    rb_eval_string_protect(command.c_str(), &status);
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    logRubyErrors("", status);
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    if ( status )
C++程序中嵌入Ruby脚本系统    {
C++程序中嵌入Ruby脚本系统        rb_eval_string_protect("print $!", &status);
C++程序中嵌入Ruby脚本系统        return false;
C++程序中嵌入Ruby脚本系统    }

C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    return true;
C++程序中嵌入Ruby脚本系统}

C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统bool RubyInterpreter::executeFile(String rubyfile)
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统    bool error = execute("load '" + rubyfile + "'");
C++程序中嵌入Ruby脚本系统    return error;
C++程序中嵌入Ruby脚本系统}

C++程序中嵌入Ruby脚本系统


SWIG的使用
步骤大致为:
1. 编写后缀为.i的脚本;
2. 使用swig生成导出代码,假如脚本名为:sample.i,那么生成的源码文件名规则就为:sample_wrap.cpp/.c.
3. 将生成的cpp加入动态链接库,然后编译.

最简单的.i脚本为:
C++程序中嵌入Ruby脚本系统%module Export4ScriptLib
C++程序中嵌入Ruby脚本系统
%{
C++程序中嵌入Ruby脚本系统#include 
"Player.h"
C++程序中嵌入Ruby脚本系统
%}

C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统
%include "stl.i"
C++程序中嵌入Ruby脚本系统
%include "Player.h"
Edit:如果想要使用STL的导出类,那就需要添加%include "stl.i"
假如说,头文件里面定义的所有的类,类所有的方法,你都要将之导出,那么以上就足够了.但是,假如你只需要导出部分的类,部分的类的方法.那么你就需要自己手动写入到.i脚本里面去了.

生成代码的命令为:
C++程序中嵌入Ruby脚本系统swig.exe -c++ -ruby Exports.i
这样写的前提是你已经吧swig的路径加入到环境变量里面去了,其中第一个参数表示的是导出的代码为c++,第二个参数表示的目标脚本语言是谁,第三个参数是.i脚本的路径名.我写了一个批处理:invoke_swig.bat,做这件事情.不过更完美的做法是在VC项目里面的"预生成事件"加入此语句.

剩下的事情就是把生成的代码和要导出的代码编译一边,就可以开始使用导出的C++库了.


测试
在实例代码里面:Export4ScriptLib工程是动态链接库工程,testRubyInterpreter是测试用的可执行程序工程.
测试用的Ruby代码test.rb如下:
C++程序中嵌入Ruby脚本系统require 'Export4ScriptLib'
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统print "hello 你好!\n"
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统ply = Export4ScriptLib::Player.new
C++程序中嵌入Ruby脚本系统ply.Jump();
C++程序中嵌入Ruby脚本系统ply.Move(100, 2000);
测试用C++代码如下:
C++程序中嵌入Ruby脚本系统class testClient
C++程序中嵌入Ruby脚本系统{
C++程序中嵌入Ruby脚本系统public:
C++程序中嵌入Ruby脚本系统    testClient()
C++程序中嵌入Ruby脚本系统    {
C++程序中嵌入Ruby脚本系统        mRubyInterpreter = new RubyInterpreter();
C++程序中嵌入Ruby脚本系统        mRubyInterpreter->initializeInterpreter();
C++程序中嵌入Ruby脚本系统    }
C++程序中嵌入Ruby脚本系统    
C++程序中嵌入Ruby脚本系统    ~testClient()
C++程序中嵌入Ruby脚本系统    {
C++程序中嵌入Ruby脚本系统        delete mRubyInterpreter;
C++程序中嵌入Ruby脚本系统    }
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统    void exec()
C++程序中嵌入Ruby脚本系统    {
C++程序中嵌入Ruby脚本系统        // 执行语句
C++程序中嵌入Ruby脚本系统        mRubyInterpreter->execute("print \"This is C++ call Ruby print funtion!\n\"");
C++程序中嵌入Ruby脚本系统        
C++程序中嵌入Ruby脚本系统        // 执行文件
C++程序中嵌入Ruby脚本系统        mRubyInterpreter->executeFile("test.rb");
C++程序中嵌入Ruby脚本系统    }
C++程序中嵌入Ruby脚本系统
C++程序中嵌入Ruby脚本系统private:
C++程序中嵌入Ruby脚本系统    RubyInterpreter* mRubyInterpreter;
C++程序中嵌入Ruby脚本系统};
上一篇:mysql中的日期格式问题


下一篇:【直播回顾】阿里云技术系列直播:异构计算、函数计算、自研数据库…