以前写过一个博客介绍用SIP来做C++的Python绑定。这几天看了看SWIG,挺不错的工具,支持把C/C++绑定成多种语言(Perl, PHP, Python, Tcl, Ruby, PHP, C#, Java等等)。最重要的是SWIG文档非常全,想想Shiboken,哎。。。
我的环境如下
- Windows XP
- Python 2.7.2
- Qt SDK 4.8.4
- MinGW (gcc 4.4.0)
- SWIG 2.0.9
下载SWIG
- 下载网址 https://sourceforge.net/projects/swig/files/swigwin/
- 直接下载它的zip包: swigwin-2.0.9.zip, 解压之后就可以用了
目标
- 使现有的Qt C++动态链接库能被Python调用。而且
- 不能重新编译该动态链接库
问题和方法
既然我们不能修改bar.dll库的代码,那么我们只能写一个C++ Wrapper 类来包装bar.dll,SWIG可以把这个Wrapper类绑定成Python库。生成动态链接库bar.dll
首先我们来生成下面要用到的动态库bar.dll. 我们会用到文件bar.h, bar.cpp, bar.pro- bar.h
#ifndef BAR_H
#define BAR_H
#if defined(BAR_LIBRARY)
#define BARSHARED_EXPORT __declspec(dllexport)
#else
#define BARSHARED_EXPORT __declspec(dllimport)
#endif
#include <string>
using namespace std;
class QString;
class BARSHARED_EXPORT Bar {
public:
Bar();
~Bar();
int len(const QString &str);
};
#endif // BAR_H
- bar.cpp
#include <QString>
#include "bar.h"
Bar::Bar()
{
}
Bar::~Bar()
{
}
int Bar::len(const QString &str)
{
return str.size();
}
- bar.pro
TEMPLATE = lib
QT -= gui
DEFINES += BAR_LIBRARY
HEADERS += bar.h
SOURCES += bar.cpp
现在建一个bar目录,把上面三个文件拷到目录里,编译成动态库(libbar.a, bar.dll)。
D:\GitHub\exercise\swig>cd bar生成的库文件应该在bar\release目录下了。
D:\GitHub\exercise\swig\bar>qmake
D:\GitHub\exercise\swig\bar>make release
D:\GITHUB\EXERCISE\SWIG\BAR
│ bar.cpp
│ bar.h
│ bar.pro
│ bar.pro.user
│ Makefile
│ Makefile.Debug
│ Makefile.Release
│ test.cpp
│
├─debug
└─release
bar.dll
bar.o
libbar.a
test.o
用SWIG生成Python绑定
现在我们写一个Wrapper类BarBinding来调用Bar.//barbinding.h这里注意barbinding.h头文件里没有用任何Qt相关的类。SWIG目前没有提供对Qt类的直接支持,所以,我们用C++标准类string来代替QString.
#ifndef BARBINDING_H
#define BARBINDING_H
#include<string>
using namespace std;
class Bar;
class BarBinding
{
public:
BarBinding();
~BarBinding();
int len(const string &str);
private:
Bar *p;
};
#endif // BARBINDING_H
//barbinding.cpp接着写一个SWIG的接口文件bar.i来描述我们需要绑定到Python的那些类和方法。基本上bar.i就是对barbinding.h头文件的一个详细描述。
#include <QString>
#include "barbinding.h"
#include "bar.h"
BarBinding::BarBinding()
{
p = new Bar();
}
BarBinding::~BarBinding()
{
if (p) {
delete p;
p = NULL;
}
}
int BarBinding::len(const string &str)
{
if (p) {
QString s(str.c_str());
return p->len(s);
} else {
return -1;
}
}
/* File : bar.i */运行SWIG来生成绑定用的C++和python文件
%module bar
%include "std_string.i"
using namespace std;
%{
#include "barbinding.h"
%}
/* Let's just grab the original header file here */
%include "barbinding.h"
D:\GitHub\exercise\swig\bar>D:\swigwin-2.0.9\swig.exe -python -c++ bar.i现在bar目录下多了如下两个文件
接着运行如下的.pro文件生成最后的绑定
TEMPLATE = lib
QT -= gui
TARGET = _bar
INCLUDEPATH += $$PWD \
D:/Python27/include
HEADERS += barbinding.h
SOURCES += barbinding.cpp \
bar_wrap.cxx
LIBS += -L$$PWD/release -lbar -LD:/Python27/libs -lpython27
D:\GitHub\exercise\swig\bar>qmake barbinding.pro现在bar\release目录下就生成了我们需要的python绑定"_bar.dll".
D:\GitHub\exercise\swig\bar>make release
我们需要把“_bar.dll"改名成Python能认识的后缀名"_bar.pyd".此外还要把bar\bar.py拷贝到bar\release\bar.py。
D:\GitHub\exercise\swig\bar>copy bar.py release\bar.py到此我们就完成了对bar.dll库的绑定。release目录下的三个文件(调用关系:bar.py->_bar.pyd->bar.dll)就是用python来调用bar.dll需要的全部东西了。
1 file(s) copied.
D:\GitHub\exercise\swig\bar>rename release\_bar.dll _bar.pyd