Sip使用步骤

第一步: 编写个C文件,功能是将两个数字相加并输出,命名为add.c,这个将成为在Python中的模块名,如下:

1
2
3
4
5
6
7
/* File : add.c */
int add(int x, int y)
{
int g;
g = x + y;
return g;
}

第二步: 手工编写SIP文件,在使用SIP的过程中,一个C/C++的源码文件尽量对应一个同名的sip文件,这里命名为add.sip,如下:

1
2
3
/* Define the SIP wrapper to the add library. */
%Module(name=add, language="C")
int add(int x, int y);

如果是源程序是用C++写的,那么这里的(name=add, language=”C”)就可以省去。
这里的C源码文件没有头文件,所以对应的sip文件很简单。
如果C/C++的源码是实现部分,在实现部分还包括接口部分,即头文件。那么在相应的sip文件中需要用下面的代码来包含相应的头文件.

1
2
3
%TypeHeaderCode
#include <word.h>
%End

sip文件与正式的C/C++头文件相似,但与之不同的是:sip文件不包含相应的头文件的私有成员变量(private或protected)。
更详细的sip文件编写规范,请参考riverbank官方网站上的说明文档SIP Reference Guide。

第三步:编译C文件。按照官网的说法,是编写configure.py,但先做一些必不可少的工作。
在命令行将add.c编译成add.o文件:输入gcc -c add.c, 将这一步生成的add.o文件
生产库文件:ar -r libadd.a add.o,这两步在这里是为一个单独的C模块测试的,
如果是大量的C模块,可以用一个makefile一并批量完成。
记住,需要将libadd.a文件复制到Python文件夹下的libs文件夹中。也可以将源代码直接编译成dll

第四步:手工编写configure.py文件,同样,这个configure文件的编写也不难,看下规范就会了。这里,我们模仿官网的模版写一个自己的configure.py。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import os
import sipconfig
# The name of the SIP build file generated by SIP and used by the build system.
build_file = "add.sbf"
# Get the SIP configuration information.
config = sipconfig.Configuration()
# Run SIP to generate the code.
os.system(" ".join([config.sip_bin, "-c", ".", "-b", build_file, "add.sip"]))
# Create the Makefile.
makefile = sipconfig.SIPModuleMakefile(config, build_file)
# Add the library we are wrapping. The name doesn't include any platform
# specific prefixes or extensions (e.g. the "lib" prefix on UNIX, or the
# ".dll" extension on Windows).
makefile.extra_libs = ["add"]
# Generate the Makefile itself.
makefile.generate()

第五步:运行configure.py,会生成一个makefile文件(直接用IDLE打开configure.py,按F5运行;或者命令行用python configure.py运行都可以)。
这里有个诡异的地方,有的人会在这一步会报错,说找不到add.sbf文件,而add.sbf文件应该是configure.py运行时调用相关函数自动产生的。
若出现这个问题,请重新编译SIP。如果是Windows下,最好是在另一台机器上拷贝一个完整的包含能正常的SIP的Python文件夹,到有问题的机器上,将问题Python文件夹覆盖掉。

第六步: 在命令行输入make(这里会生成一个关于函数的警告,不用管它,若有问题请检查前面的步骤),生成add.pyd文件。
然后再输入make install(将add.pyd文件装入到Python的Lib文件夹下的sit-packages文件夹中)。

第七步: 打开Python 的命令行,进行测试:

1
2
3
4
>>>import add
>>>add.add(4, 7)
11
>>>

提示:
(1)这些文件可以放到Python的文件夹下新建的文件夹中(所有的操作在这个目录下的命令行窗口中使用)。
注意,Python的父文件夹名不能有空格,否则会无法读取库文件。
(2)使用MinGW,需要把~\MinGW\bin添加的环境变量中(Linux下则不必),这样才能使用gcc、make和ar等工具。

C++中的sip写法

具体的实现办法和上面介绍的相似,所不同的就是根据相应的C++头文件来写对应的sip文件。详细过程如下。

首先,写好C++类的实现和接口部分(以Geometry类中的方法,输入半径,显示周长或面积为例):

1
2
3
4
5
6
7
8
9
10
11
12
13
//Geometry.h
class Geometry
{
public:
Geometry(double r); //构造函数
double calPerimeter(double radius); //参数半径,返回圆周长
double calArea(double radius); //参数半径,返回原面积
private:
double perimeter;
double radius;
double area;
};

接着,是C++的实现部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Geometry.cpp
#include <iostream>
#include "Geometry.h"
#define PI 3.141592
Geometry::Geometry(double r) //构造函数
{
radius = r;
}
double Geometry::calPerimeter(double radius) //参数半径,返回圆周长
{
perimeter = radius * 2* PI;
return perimeter;
}
double Geometry::calArea(double radius) //参数半径,返回原面积
{
area = radius * radius * PI;
return perimeter;
}

第三步:如同上文中介绍的,在命令行中用g++ -c Geometry.cpp和ar -r libGeometry.a Geometry.o来编译出库文件,并把库文件添加到Python文件夹下的libs文件夹中。

第四步:编写C++文件对应的sip文件,再次提示,sip文件是基于C++的头文件的。本例中的sip文件内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
//Geometry.sip
%Module Geometry
class Geometry {
%TypeHeaderCode
#include <Geometry.h>
%End
public:
Geometry(double r);
double calPerimeter(double radius);
double calArea(double radius);
};

第五步:在命令行中使用Python configure.py命令,注意,configure.py文件是自己写的,configure的模板在上文中有,只需将上文中的模板中的add改为对应的Geometry,也就是类名就可以了。

第六步:在命令行中依次使用mingw32-make和ming32-make install将编译出的Geometry.pyd复制到Python文件夹下的Libs/site-packages文件夹中。

若不出意外,上述步骤可以执行成功。注:这里所有的命令都是在Geometry类的文件所在目录下完成的。

参考