查看SWIG帮助
swig - -help 可以看到语言特有的选项
例如:swig -java -help
常规选项
-addextern - 添加额外的extern声明
-c ++ - 启用C ++处理
-co <file> - 检查SWIG库中的<file>
-copyctor - 尽可能自动生成复制构造函数
-cpperraswarn - 将预处理器#error语句视为#warning(默认)
-cppext <ext> - 将生成的C ++文件的文件扩展名更改为<ext>
(默认为cxx,但使用cpp的PHP除外)
-copyright - 显示版权声明
-debug-classes - 显示有关在接口中找到的类的信息
-debug-module <n> - 在1-4阶段显示模块解析树,<n>是csv阶段列表
-debug-symtabs - 显示符号表信息
-debug-symbols - 在符号表中显示目标语言符号
-debug-csymbols - 在符号表中显示C符号
-debug-lsymbols - 显示目标语言层符号
-debug-tags - 显示有关在界面中找到的标签的信息
-debug-template - 显示调试模板的信息
-debug-top <n> - 在1-4阶段显示整个解析树,<n>是csv阶段列表
-debug-typedef - 显示有关接口中类型和typedef的信息
-debug-typemap - 显示类型映射调试信息
-debug-tmsearch - 显示类型映射搜索调试信息
-debug-tmused - 显示使用调试信息的类型映射
-directors - 打开所有类的导演模式,主要用于测试
-dirprot - 打开导向器类的受保护成员包装(默认)
-D <symbol> - 定义符号<symbol>(用于条件编译)
-E - 仅预处理,不生成包装器代码
-external-runtime [file] - 导出SWIG运行时堆栈
-fakeversion <v> - 使SWIG伪造程序版本号为<v>
-fcompact - 在紧凑模式下编译
-features <list> - 设置全局功能,其中<list>是逗号分隔的列表
功能,例如-features director,autodoc = 1
如果未对该功能赋予显式值,则使用默认值1
-fastdispatch - 启用快速调度模式以生成更快的过载调度程序代码
-Fmicrosoft - 以Microsoft格式显示错误/警告消息
-Fstandard - 以常用格式显示错误/警告消息
-fvirtual - 在virtual排除模式下编译。
-help - 此输出
-I- - 不要搜索当前目录
-I <dir> - 在目录<dir>中查找SWIG文件
-ignoremissing - 忽略丢失的包含文件
-importall - 将所有#include语句作为导入
-includeall - 关注所有#include语句
-l <ifile> - 包含SWIG库文件<ifile>
-macroerrors - 报告宏内部的错误
-makedefault - 创建默认构造函数/析构函数(默认值)
-M - 列出所有依赖项
-MD - 相当于`-M -MF <file>',但不暗示`-E'
-MF <file> - 生成<file>中的依赖项并继续生成包装器
-MM - 列出依赖项,但省略SWIG库中的文件
-MMD - 与`-MD'类似,但省略SWIG库中的文件
-module <name> - 将模块名称设置为<name>
-MP - 为所有依赖项生成虚假目标
-MT <target> - 设置依赖关系生成发出的规则的目标
-nocontract - 关闭合同检查
-nocpperraswarn - 不要将预处理器#error语句视为#warning
-nodefault - 不生成默认构造函数也不生成默认析构函数
-nodefaultctor - 不生成隐式默认构造函数
-nodefaultdtor - 不生成隐式默认析构函数
-nodirprot - 不要包装director受保护的成员
-noexcept - 不要包装异常说明符
-nofastdispatch - 禁用快速调度模式(默认)
-nopreprocess - 跳过预处理器步骤
-notemplatereduce - 禁用 简化模板中的typedef
-O - 启用优化选项:
-fastdispatch -fvirtual
-o <outfile> - 将C / C ++输出文件的名称设置为<outfile>
-oh <headfile> - 将控制器的C ++输出头文件的名称设置为<headfile>
-outcurrentdir - 将默认输出目录设置为当前目录而不是输入文件的路径
-outdir <dir> - 将语言特定文件输出目录设置为<dir>
-pcreversion - 显示PCRE版本信息
-small - 在虚拟消除和紧凑模式下编译
-swiglib - 报告SWIG库的位置并退出
-templatereduce - 减少模板中的所有typedef
-v - 以详细模式运行
-version - 显示SWIG版本号
-Wall - 删除所有警告抑制,也暗示-Wextra
-Wallkw - 为所有支持的语言启用关键字警告
-Werror - 将警告视为错误
-Wextra - 添加以下附加警告:202,309,403,512,321,322
-w <list> - 抑制/添加警告消息,例如-w401,+ 321 - 请参阅Warnings.html
-xmlout <file> - 正常处理后,将解析树的XML版本写入<file>
Java选项(与-java一起提供)
-nopgcpp - 抑制过早的垃圾收集保护参数
-noproxy - 生成低级函数接口而非代理类
-oldvarnames - 变量包装器使用旧中间方法名称
-package <name> - 将Java包的名称设置为<name>
SWIG接口文件语法
- 简单例子
%module mymodule #指定生成的目标语言文件名 %{ #%{%}包含的部分,将会插入到wrapper中 #include "myheader.h" %} // Now list ANSI C/C++ declarations int foo; #swig预处理器根据这里的函数声明生成相应的包装方法 int bar(int x);
- 初始化块(
%init
指令)%init %{ #在module加载的时候调用,测试了一下,java没有用,但是python有效果 init_variables(); %}
%inline
指令
等效于%inline %{ #也就是说块中的代码既会添加到生成的接口文件(xx_wrap.cxx中)又会被swig预处理器解析从而生成相应的包装方法 /* Create a new vector */ Vector *new_Vector() { return (Vector *) malloc(sizeof(Vector)); } %}
%{ /* Create a new vector */ Vector *new_Vector() { return (Vector *) malloc(sizeof(Vector)); } %} Vector *new_Vector() { return (Vector *) malloc(sizeof(Vector)); }
- 代码插入
%begin %{ ... code in begin section ... xx_wrap.cxx 最前面,一般是放入宏,好让后面都能用到 %} %runtime %{ ... code in runtime section ... 在%header前面 %} %header %{ ... code in header section ... 等效 %{%} %} %wrapper %{ ... code in wrapper section ... 放在SWIG生成接口代码的地方 %} %init %{ ... code in init section ... 放在模块加载的地方,目标语言是java就会生成在xx_wrap.cxx文件最后面, python的话在SWIG_INIT方法内最后一行 %}
- SWIG预处理器是C/C++预处理器的增强版本。除了#include之外,其它的C/C++语法都会被SWIG解析并生成相应的包装代码。
基于这个原因,SWIG直接解析头文件来生成包装代码 swig -java -module example example.h%module base_module %{ #include "base.h" %} %include "base.h"//SWIG默认不解析#include,所以当需要让SWIG预处理解析#include需要通过%include指令来达到 #define STATUS 50//这些C语言语法会被解析,生成相应的包装(get/set)方法 #define VERSION "1.1"
- 使用宏在C/C++头文件中添加SWIG指令。因为SWIG指令语法不是标准的C语法所以需要通过宏来隔离,避免编译时语法错误
#ifdef SWIG //swig解析时会定义这个宏 %module foo #endif
%import
指令
SWIG使用%import 指令提供另一个文件包含指令。例如:
%import“foo.i”
%import
的目的是从另一个SWIG接口文件或头文件中收集某些信息,而不实际生成任何包装器代码。
此类信息通常包括类型声明(例如,typedef)以及可能用作接口中类声明的基类的C ++类。当SWIG用于生成扩展作为相关模块的集合时,
使用%import也很重要。这是一个高级主题,稍后将在使用模块章节中进行介绍。
该-importall指令告诉SWIG将#include作为%import。如果要从系统头文件中提取类型定义而不生成任何包装器,这可能很有用。%immutable
指令
将变量标记为不可修改,这样就只会在生成的接口文件生成只读方法get而已,不会生成set方法// File : interface.i int a; // Can read/write %immutable; int b, c, d; // Read only variables %mutable; double x, y; // read/write
- 链接char* 全局变量
当出现char *类型的全局变量时,SWIG使用malloc()或 new为新值分配内存。具体来说,如果你有这样的变量
如果这不是您想要的行为,请考虑使用%immutable指令将变量设置为只读 。或者,您可以编写一个简短的辅助函数来完全按照您的意愿设置值。例如:char * foo; //SWIG生成以下代码: / * C模式* / void foo_set(char * value){ if(foo)free(foo); foo =(char *)malloc(strlen(value)+1); strcpy(foo,value); } / * C ++模式。使用-c++选项时* / void foo_set(char * value){ if(foo)delete [] foo; foo = new char [strlen(value)+1]; strcpy(foo,value); }
注意:如果你编写这样的辅助函数,你将不得不从目标脚本语言中将其称为函数(它不像变量那样工作)。例如,在Python中你必须写:%inline %{ void set_foo(char * value){ strncpy(foo,value,50); } %}
char *变量的 常见错误是链接到声明如下的变量:>>> set_foo(“Hello World”)
char * VERSION =“1.0”;
在这种情况下,变量将是可读的,但任何更改值的尝试都会导致段错误或一般保护错误。这是因为当使用malloc()或new分配给变量的字符串文字值时,SWIG尝试使用free或delete释放旧值 。要解决此问题,您可以将变量标记为只读,编写类型映射,或者编写一个特殊的set函数。另一种方法是将变量声明为数组:
char VERSION [64] =“1.0”;
当声明类型为const char *的变量时,SWIG仍会生成用于设置和获取值的函数。但是,默认行为并没有释放以前的内容(从而可能导致内存泄漏)。实际上,在包装这样的变量时,您可能会收到一条警告消息:example.i:20。类型图警告。设置const char *变量可能会泄漏内存。这种行为的原因是const char *变量通常用于指向字符串文字。例如:const char * foo =“Hello World \ n”;
因此,在这样的指针上调用free()是一个非常糟糕的主意。另一方面,将指针更改为指向其他值是合法的。设置此类型的变量时,SWIG会分配一个新字符串(使用malloc或new)并将指针更改为指向新值。但是,重复修改该值将导致内存泄漏,因为旧值未释放。 %constant
、%callback/%nocallback
回调函数指针
在这种情况下,add,sub和mul成为目标脚本语言中的函数指针常量。这允许您按如下方式使用它们:/ *带回调函数* / int binary_op(int a,int b,int(* op)(int,int)); / *一些回调函数* / %constant int add(int,int); %constant int sub(int,int); %constant int mul(int,int);
不幸的是,通过将回调函数声明为常量,它们不再可以作为函数访问。如果要将函数作为回调函数和函数使用,可以使用%callback和%nocallback指令,如下所示:>>> binary_op(3,4,add) 7 >>> binary_op(3,4,mul) 12 >>>
%callback 的参数是一个printf样式的格式字符串,它指定回调常量的命名约定(%s被函数名替换)。回调模式保持有效,直到使用%nocallback显式禁用它。执行此操作时,界面现在的工作方式如下:/ *带回调函数* / int binary_op(int a,int b,int(* op)(int,int)); / *一些回调函数* / %callback( “%s_cb”); int add(int,int); int sub(int,int); int mul(int,int); %nocallback;
全部转为大写来作为回调指针>>> binary_op(3,4,add_cb) 7 >>> binary_op(3,4,mul_cb) 12 >>> add(3,4) 7 >>> mul(3,4) 12
/* Some callback functions */ %callback("%(uppercase)s"); int add(int, int); int sub(int, int); int mul(int, int); %nocallback;
- 使用
%extend
扩展c语言struct结构体,将方法绑定到结构体上。这样可以实现类似C++的类的效果/* file : vector.h */ ... typedef struct Vector { double x, y, z; } Vector // file : vector.i %module mymodule %{ #include "vector.h" %} %include "vector.h" // Just grab original C header file %extend Vector { // Attach these functions to struct Vector Vector(double x, double y, double z) { Vector *v; v = (Vector *) malloc(sizeof(Vector)); v->x = x; v->y = y; v->z = z; return v; } ~Vector() { free($self); } double magnitude() { return sqrt($self->x*$self->x+$self->y*$self->y+$self->z*$self->z); } void print() { printf("Vector [%g, %g, %g]\n", $self->x, $self->y, $self->z); } };
%ignore
忽略指定的名字,使得SWIG不会解析指定名字和生成代码%ignore foo(double); //Ignore all foo(double) %ignore Spam::foo; //Ignore foo in class Spam %ignore Spam::foo(double);//Ignore foo(double) in class Spam %ignore *::foo(double);//Ignore foo(double) in all classes
%rename
重命名
所有类的成员函数重命名
指定的类的成员函数重命名%rename(foo_i) *::foo(int);
全局函数重命名%rename(foo_i) Spam::foo(int); %rename(foo_d) Spam::foo(double);//子类中的也会被重命名
重命名所有的函数(类成员和非类成员)%rename(foo_i) ::foo(int);
%rename(foo_i) foo;
%template
实例化模板
批量实例化%template(intList) vector<int>; typedef int Integer; ... void foo(vector<Integer> *x); // 实例化 traits<double, double>, but don't 生成包装代码 %template() traits<double, double>;
强制模板实例生成默认构造函数%define TEMPLATE_WRAP(prefix, T...) //这里使用...,是因为不这样做的话, //std::pair<string, int>中的逗号就不能使用了。在宏这里变量是以逗号作为每个单位的分隔符。 %template(prefix ## Foo) Foo<T >; %template(prefix ## Bar) Bar<T >; ... %enddef TEMPLATE_WRAP(int, int) TEMPLATE_WRAP(double, double) TEMPLATE_WRAP(String, char *) TEMPLATE_WRAP(PairStringInt, std::pair<string, int>) ...
template<class T1, class T2> struct pair { T1 first; T2 second; pair() : first(T1()), second(T2()) { } pair(const T1 &x, const T2 &y) : first(x), second(y) { } template<class U1, class U2> pair(const pair<U1, U2> &x) : first(x.first), second(x.second) { } }; %extend pair { %template(pair) pair<T1, T2>; // 生成默认拷贝构造函数 }; // Instantiate a few versions %template(pairii) pair<int, int>; %template(pairdd) pair<double, double>; // Create a default constructor only %extend pair<int, int> { %template(paird) pair<int, int>; // Default constructor }; // Create default and conversion constructors %extend pair<double, double> { %template(paird) pair<double, dobule>;// Default constructor %template(pairc) pair<int, int>;// Conversion constructor }
%feature ref unref
生成引用计数类的包装代码class RCObj { // implement the ref counting mechanism int add_ref(); int del_ref(); int ref_count(); public: virtual ~RCObj() = 0; int ref() const { return add_ref(); } int unref() const { if (ref_count() == 0 || del_ref() == 0 ) { delete this; return 0; } return ref_count(); } }; class A : RCObj { public: A(); int foo(); }; class B { A *_a; public: B(A *a) : _a(a) { a->ref(); } ~B() { a->unref(); } }; %module example ... %feature("ref") RCObj "$this->ref();" %feature("unref") RCObj "$this->unref();" %include "rcobj.h" %include "A.h" ...
- 使用
%newobject
%newobject
功能旨在表明它应当采取返回对象的所有权的目标语言。当与具有与之关联的“ref”特性的类型一起使用时,它还将“ref”特征中的代码发送到C ++包装器中。除上述内容外,请考虑包装以下工厂方法:
%newobject 标识那些返回堆对象的方法。%newobject AFactory; A *AFactory() { return new A(); }
这样返回的C/C++堆对象生命周期就完全由目标语言来管理%newobject derived::bar; %inline %{ class derived : public base { public: derived * bar(){ return new derived(); } }; %}
- typemap
编写格式编写格式
typemap作用域%typemap(method [, modifiers]) typelist code ; typelist : typepattern [, typepattern, typepattern, ... ] ; typepattern : type [ (parms) ] int/*声明匹配的类型*/ (int temp/*声明在wrapper中使用的临时变量*/) | type name [ (parms) ] int len/*声明匹配的类型*/ (int temp/*声明在wrapper中使用的临时变量*/) | ( typelist ) [ (parms) ] (char *str, int len)/*声明匹配的类型*/ (int temp/*声明在wrapper中使用的临时变量*/) code : { ... } //生成 {} | " ... " //不生成 {} | %{ ... %}//不生成 {}
typemap_example.inamespace Foo { class string; %typemap(in) string { /* Foo::string */ ... } }
%module TypemapExample //控制java类名 //argxx都是针对wrapper局部变量做操作 //针对重载方法参数检查,只有在目标语言不支持重载的情况下有用。 //因为在不支持重载的目标语言中,是通过调用同一个函数,然后参数被包装成对象数组来实现调用C/C++重载的(当然也可以通过%rename来生成函数各不相同的函数来避免重载)。这个时候就需要根据数组的元素个数,以及检查数组参数类型来得知具体是调用哪个重载函数 %typemap(typecheck , precedence=SWIG_TYPECHECK_INTEGER) int { $1 = Custom_Check_Int($input) ? 1 : 0;//检查是否是int类型 } //另一种写法 /* Required for C++ method overloading */ /*%typecheck(SWIG_TYPECHECK_STRING_ARRAY) (int argc, char *argv[]) { $1 = PyList_Check($input) ? 1 : 0; }*/ //处理局部变量(传给C/C++方法参数) %typemap(arginit) int flags { //arginit,初始化wrapper方法局部变量 $1 = NULL; } %typemap(default) int flags { //default,设置wrapper方法局部变量初始值 $1 = DEFAULT_FLAGS; } %typemap(in) int flags { //in,将java对象转换成c/c++的int $1 = JavaObj_to_int($input); } %typemap(check) int flags { //check,检查参数合法性 if ($1 <= 0) { SWIG_exception(SWIG_ValueError, "Expected positive value."); } } %typemap(out) int foo { //out,C/C++函数返回值进行处理——转换成目标语言的结果类型 //\$\1,C/C++函数返回值 $result = To_Java_Int($1); } %typemap(argout) int flags { //argout,将参数添加到返回值 $result += $1 } %typemap(freearg) int flags { //freearg free($1); } %typemap(newfree) int { //newfree, 释放C/C++函数返回的堆对象。需要配合(%newobject)一起使用 delete $1; } %typemap(varin) int { //varin,全局变量赋值。目前只在python中看见有效 $1 = PythonInt_To_C($input); } %typemap(varout) int { //varout,获取全局变量。目前只在python中看见有效 $1 = C_To_PythonInt($result); } int ALL_TIMES; %typemap(ret) stringheap_t %{ //ret,针对C/C++函数返回值进行操作 free($1); %} typedef char * string_t; typedef char * stringheap_t; string_t MakeString1(); stringheap_t MakeString2(); //numinputs只能取 0 或 1 //0表示wrapper方法不会声明这个参数,也就是不要求目标语言传递这个参数,$input也就无效 //1表示wrapper方法会声明这个参数,也就是要求目标语言需要传递这个参数,$input有效 /* %typemap(in, numinputs=0) int flags (int temp) { $1 = &temp; }*/ %newobject foo; int foo(int x, int y, int flags); /*%typemap(memberin) int x[20] { //memberin, memmove($1, $input, 4*sizeof(int)); }*/ %typemap(memberin) int x[ANY] { //memberin,结构体或者类中的成员set函数中将目标语言传入的参数转换成C/C++类成员变量 memmove($1, $input, $1_dim0*sizeof(int)); } struct A { int x[4]; }; %fragment("AsMyClassFragment", "header") { //%fragment("AsMyClassFragment", "header") MyClass *AsMyClassA(PyObject *obj) { MyClass *value = 0; return value; } } %typemap(in, fragment="AsMyClassFragment") MyClass * { //in,当需要将目标语言参数转换成MyClass *对象时,会在wrapper的header那里插入fragment代码 $result = AsMyClassA($input); } %typemap(varin, fragment="AsMyClassFragment") MyClass * { //varin $result = AsMyClassA($input); } void foo(MyClass *a, MyClass *b); %fragment("<limits.h>", "header") { %#include <limits.h> } %fragment("AsMyClass", "header", fragment="<limits.h>") {//fragment依赖fragment MyClass *AsMyClass(PyObject *obj) { MyClass *value = 0; ... some marshalling code ... if (ival < CHAR_MIN /*defined in <limits.h>*/) { ... } else { ... } ... return value; } } //%fragment("bigfragment", "header", fragment="frag1", fragment="frag2", fragment="frag3") "";//依赖多个fragment //typemap依赖多个fragment //%typemap(in, fragment="frag1, frag2, frag3") {...} //等于 //%typemap(in, fragment="bigfragment") {...} //强制插入fragment代码片段 //%fragment("bigfragment"); //目标语言一个参数对应C/C++函数中的两个参数 //jstring jarg1 -> char *str, int len %typemap(in) (char *str, int len) { $1 = PyString_AsString($input); /* char *str */ $2 = PyString_Size($input); /* int len */ } int foo(char *str, int len); %typemap(in) const int* bar{ $symname $argnum $1_name $1_type $*1_type $&1_type $1_ltype $*1_ltype $&1_ltype $1_basetype $1_descriptor $*1_descriptor $&1_descriptor $1_mangle $*1_mangle $&1_mangle $descriptor(std :: vector <int> *) } int barf( const int *bar); %typemap(in) (int argc, char *argv[]) { int i; if (!PyList_Check($input)) { PyErr_SetString(PyExc_ValueError, "Expecting a list"); SWIG_fail; } $1 = PyList_Size($input); $2 = (char **) malloc(($1+1)*sizeof(char *)); for (i = 0; i < $1; i++) { PyObject *s = PyList_GetItem($input, i); if (!PyString_Check(s)) { free($2); PyErr_SetString(PyExc_ValueError, "List items must be strings"); SWIG_fail; } $2[i] = PyString_AsString(s); } $2[i] = 0; } %typemap(freearg) (int argc, char *argv[]) { if ($2) free($2); } %fragment("incode"{float}, "header") { float in_method_float(PyObject *obj) { } } %fragment("incode"{long}, "header") { float in_method_long(PyObject *obj) { } } // %my_typemaps macro definition %define %my_typemaps(Type) %typemap(in, fragment="incode"{Type}) Type { value = in_method_##Type(obj); } %enddef %my_typemaps(float); %my_typemaps(long); int foo(int argc, char *argv[]); int agoda(long argc, char *argv[]);