1. 背景
最近公司在某券商募集了一笔资金,需要对接其提供的程序化接口方便以后进行交易,对方只提供了c++版本程序,我们系统是python开发的,所以需要用python调用c++,大致了解下了python调用c++的几种方式,下面根据网上的资料介绍下几种方式优缺点,最后给个mac环境下python调用c++的例子。
2. Python调用C/C++程序方法
-
ctypes
- 如果是 C 函数库,则直接 load 这个库,然后调用即可;
- 如果是 C++ 函数库,则需要用extern关键字封装一个供 C 使用的函数,即把类隐藏到一些 C 风格的函数里,然后用 extern 标明这些函数,以方便外部调用。
-
SWIG
SWIG完整支持ANSI C,支持除嵌套类外的所有C++特性。SWIG是一个接口编译器,旨在为C/C++方便地提供脚本语言接口。SWIG不仅可以为C/C++程序生成 Python接口,目前可以生成CLISP,Java,Lua,PHP,Ruby,Tcl等19种语言的接口。SWIG被Subversion, wxPython, Xapian等项目使用。值得一提的是,Google也使用SWIG。
-
SIP
SIP是一种Python工具,用于自动生成Python与C、C++库的绑定。SIP最初是在1998年用PyQt开发的,用于Python与Qt GUI toolkit的绑定,但适用于生成任何C或C++库的绑定。
-
Cython
Cython是让Python脚本支持C语言扩展的编译器,Cython能够将Python+C混合编码的.pyx脚本转换为C代码,主要用于优化Python脚本性能或Python调用C函数库。由于Python固有的性能差的问题,用C扩展Python成为提高Python性能常用方法,Cython算是较为常见的一种扩展方式。
-
Boost.Python
Boost.Python是Boost提供的一个C++的模板库,用以支持Python和C++的无缝互操作。相对SWIG来说,这个库的优势是功能通过C++ API完成,不用学习写新的接口文件。对C++的支持更自然、完整。
ctypes | SWIG | SIP | Cython | Boost.Python | |
---|---|---|---|---|---|
是否支持Python3 | 支持 | 支持 | 支持 | 支持 | 支持 |
对接难易程度 | 简单 | 中等 | 中等 | 困难 | 困难 |
是否需开发封装代码 | c++需要,c不需要 | 需要 | 需要 | 需要 | 需要 |
3. 使用ctypes调用C/C++ 例子
3.1 安装 GNU 的 C/C++ 编译器
- UNIX/Linux: http://gcc.gnu.org/install/
- Mac OS X: 安装 Xcode就能使用编译器
- Windows: www.mingw.org
以mac为例,安装之后命令行输入 g++ -v 查看是否安装成功
~/ g++ -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin18.2.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
3.2 开发c++例子程序:
#include <iostream>
class Test{
public:
void print(){
std::cout << "Hello world!" << std::endl;
}
};
extern "C" {
Test* Test_new(){
return new Test();
}
void Test_print(Test* test){
test->print();
}
}
保存文件未test.cpp,编译代码生成动态链接库:
g++ -o test.so -shared -fPIC test.cpp
执行完成后会在当前目录下生辰test.so 文件
3.3 Python中调用so
from ctypes import cdll
lib = cdll.LoadLibrary('./test.so')
class Test(object):
def __init__(self):
self.obj = lib.Test_new()
def print(self):
lib.Test_print(self.obj)
test = Test()
test.print()
执行Python代码会输出 Hello world!,说明执行成功
参考
https://stackoverflow.com/questions/145270/calling-c-c-from-python
关于python对接c/c++各种方案的优缺点,这篇文章说的比较清楚: https://www.jb51.net/article/63623.htm
我的微信公众号:pyquant