使用SWIG實現C/C++與其他語言間的互相呼叫
阿新 • • 發佈:2019-02-05
為了執行速度,java, C#, ruby等語言可能會呼叫C/C++寫的函式或者類,但直接寫很麻煩,必須遵循各種語言訂立的規範,以jni為例要匯出一個函式給java用,你必須在函式定義前寫上JNIEXPORT,對於那些早已存在的程式碼,這樣就麻煩了,而且相同的程式碼如果要給ruby用,又得按照擴充套件Ruby的規定去重新定義這些函式。並且不能將C++定義的類直接拿來用
但SWIG能很方便,很自然的將C/C++程式碼轉換給這些語言用。
要使用swig需要到www.swig.org去下載這個工具。
以ruby為例,講講用法。
首先下載ruby, 我的是1.8.5, 執行configure.bat生成Makefile檔案,再用nmake命令生成config.h檔案和需要的靜態庫
用vs2005新建一個動態庫工程
//Test.h
class TestRuby
{
public:
TestRuby();
void print();
};
void testFun();
//Test.cpp
#include "test.h"
#include<iostream>
using namespace std;
TestRuby::TestRuby()
{
cout<<"Test::Test/n";
}
void TestRuby::print()
{
cout<<"hello swig/n";
}
void testFun()
{
cout<<"testFun/n";
}
//Test.i
%module test
%{
#include "test.h"
%}
%include "test.h"
注意include前的是%,昨天看成#,害得白忙了半天,汗
建立一個空白檔案test_wrap.cxx
設定好環境變數,執行
swig –c++ -ruby test.i
(也可以在專案屬性中的自定義生成步驟中定義這些命令,具體見MSDN)
這時會更新test_wrap.cxx檔案
自動生成ruby呼叫C函式需要的一些東東
如:
SWIGEXPORT void Init_test(void) {
size_t i;
SWIG_InitRuntime();
mTest = rb_define_module("Test" );
SWIG_InitializeModule(0);
for (i = 0; i < swig_module.size; i++) {
SWIG_define_class(swig_module.types[i]);
}
SWIG_RubyInitializeTrackings();
cTestRuby.klass = rb_define_class_under(mTest, "TestRuby", rb_cObject);
SWIG_TypeClientData(SWIGTYPE_p_TestRuby, (void *) &cTestRuby);
rb_define_alloc_func(cTestRuby.klass, _wrap_TestRuby_allocate);
rb_define_method(cTestRuby.klass, "initialize", VALUEFUNC(_wrap_new_TestRuby), -1);
rb_define_method(cTestRuby.klass, "print", VALUEFUNC(_wrap_TestRuby_print), -1);
cTestRuby.mark = 0;
cTestRuby.destroy = (void (*)(void *)) free_TestRuby;
cTestRuby.trackObjects = 0;
rb_define_module_function(mTest, "testFun", VALUEFUNC(_wrap_testFun), -1);
}
在附加包含目錄中引入ruby.h所在的那個路徑
在連結器中把需要的庫附加進去,我這裡連結的是msvcrt-ruby18.lib
編譯,生成dll
寫個ruby檔案測試
require 'test'
t = Test::TestRuby.new()
t.print
Test.testFun
正確輸出
Test::Test
Hello swig
testFun
如果要把這個程式碼給java,或C#用只要改變一下swig的命令引數,然後再編譯一次就行了,異常方便
Swig不支援C++所以特性,但常用的特性都支援,不太影響使用。
Swig支援C#, java, Lua, Ruby, Perl, Python, Tcl等多種語言