查看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[]);