为了运行速度,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等多种语言
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1714946