天天看點

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腳本系統
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腳本系統
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腳本系統
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腳本系統
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腳本系統
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腳本系統
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腳本系統
C++程式中嵌入Ruby腳本系統

    RubyInterpreter* mRubyInterpreter;

C++程式中嵌入Ruby腳本系統

繼續閱讀