写作目的:结合工作需要——封装C++模块在Python下调用。对SWIG官方文档相关部分做了翻译和归纳。
官方文档:http://www.swig.org/Doc4.0/index.html
使用环境:window、python3.6、swigwin-4.0.1
不足之处欢迎斧正。
使用SWIG
swig [ options ] filename
SWIG接口描述文件xxx.i or xxx.swg
SWIG接口描述文件用来告诉SWIG接口的导出内容、信息和规则等;
eg:
%module mymodule %{ #include "myheader.h" %} // Now list ISO C/C++ declarations int foo; int bar(int x); ...
通过 %module 命令声明模块名称
%{ ... %}中的所有内容将会拷贝到SWIG生成的wrapper文件,该部分被用来包含头文件、声明。SWIG不会解析里面的内容,用户需要确保内容的正确性。
SWIG输出
SWIG输出的是模块所用到的C/C++包裹文件。SWIG会根据使用的语言生成附加文件.默认情况下,输入file.i文件会生成file_wrap.cxx文件。输出的C/C++文件名可通过 -o 参数指定。
eg:
swig -c++ -python -o example_wrap.cpp example.i
SWIG指令
绝大多数SWIG指令是以‘%’前缀开头,用来和C声明做区分。SWIG指令用于提示或改变SWIG的解析行为。
解析局限
尽管SWIG能够解析大多数C/C++声明,但是它没有提供全C/C++解析的支持,这些限制大多数都与C++高级功能有关。
不支持的功能如下:
- 非常规类型声明。 例如,SWIG不支持以下声明(即使这是合法的C):
/* Non-conventional placement of storage specifier (extern) */
const int extern Number;
/* Extra declarator grouping */
Matrix (foo); // A global variable
/* Extra declarator grouping in parameters */
void bar(Spam (Grok)(Doh));
- 不建议直接拿C ++源文件(.C,.cpp或.cxx文件中的代码)运行SWIG生成包裹文件。 通常的方法是提供SWIG头文件以解析C ++定义和声明。 主要原因是,如果SWIG解析作用域定义或声明(对于C ++源文件是正常的),则将其忽略,除非先前已解析符号的声明。 例如:
/* bar not wrapped unless foo has been defined and
the declaration of bar within foo has already been parsed */
int foo::bar(int) {
... whatever ...
}
- 尚未完全支持C ++的某些高级功能,例如嵌套类。
打包简单的C声明
SWIG通过创建一个与C程序中使用声明的方式紧密匹配的接口来包装简单的C声明。 例如,考虑以下接口文件:
%module example
%inline %{
extern double sin(double x);
extern int strcmp(const char *, const char *);
extern int Foo;
%}
#define STATUS 50
#define VERSION "1.1"
该文件中有两个函数,sin()和strcmp(),全局变量Foo,两个常量STATUS和VERSION,SWIG创建扩展模块时,这些声明分别可以作为脚本语言函数,变量和常量进行访问。
>>> example.sin(3)
5.2335956
>>> example.strcmp('Dave', 'Mike')
-1
>>> print example.cvar.Foo
42
>>> print example.STATUS
50
>>> print example.VERSION
1.1
SWIG会尽可能创建一个与基础C / C ++代码紧密匹配的接口。 但是,由于语言,运行时环境和语义之间的细微差异,因此并非总是可能做到这一点。
基本类型处理
为了构建接口,SWIG必须将C / C ++数据类型转换为目标语言中的等效类型。 转换过程涉及一定数量的类型强制。
大多数脚本语言提供使用C中的int或long数据类型实现的单个整数类型。以下列表显示了SWIG将在目标语言中与整数进行相互转换的所有C数据类型:
int short long unsigned signed unsigned short unsigned long unsigned char signed char bool
注意:
C中的16位短可以被提升为32位整数。 当整数朝另一个方向转换时,该值将转换回原始的C类型。 如果该值太大而无法容纳,它将被无声地截断。
unsigned char和signed char是特殊情况,它们被当作小的8位整数处理。 通常,char数据类型映射为一个单字符ASCII字符串。
布尔数据类型强制转换为0和1的整数值,除非目标语言提供特殊的布尔类型。
使用大整数值时需要格外小心。32位无符号整数(可能显示为较大的负数)可能会出现类似的问题。
根据经验,可以安全使用int数据类型以及char和short数据类型的所有变体。 对于无符号的int和long数据类型,在用SWIG包装程序之后,需要仔细检查程序的正确操作。
SWIG可识别以下浮点类型:
float double
char数据类型被映射到以单个字符结尾的NULL终止ASCII字符串。
char *数据类型以NULL终止的ASCII字符串处理。
目前,SWIG对Unicode和宽字符字符串(C wchar_t类型)提供了有限的支持。
全局变量
%module example double foo;
在Python中,必须通过称为cvar的特殊变量对象访问所有全局变量。
# Python cvar.foo = 3.5 # Set foo to 3.5 print cvar.foo # Print value of foo
常量
常量可以使用#define,枚举或特殊的%constant指令创建常量。下面列出了一些有效的常量声明:
#define I_CONST 5 // An integer constant #define PI 3.14159 // A Floating point constant #define S_CONST "hello world" // A string constant #define NEWLINE '\n' // Character constant enum boolean {NO=0, YES=1}; enum months {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC}; %constant double BLAH = 42.37; #define PI_4 PI/4 #define FLAGS 0x04 | 0x08 | 0x40
未完待续...