您的位置:首页 > 编程语言 > C语言/C++

Python调用C/C++(使用SWIG)

2017-09-13 15:59 1051 查看
这里选用SWIG的一个重要原因是,它不仅可以用于Python,也可以用于其他语言。如今SWIG已经支持C/C++的好基友Java,主流脚本语言Python、Perl、Ruby、PHP、JavaScript、tcl、Lua,还有Go、C#,以及R。

一、SWIG环境搭建

1、 下载Swig for Windows:http://www.swig.org/download.html

2、 解压 .zip 文件到目录,比如:C:\

3、 添加环境变量到path, 比如: C:\swigwin

4、 简单测试安装是否成功:

打开Dos,在命令行执行: swig –help, 显示 Target Language Options即表明安装成功。

二、以c++为例

1、编写c++源文件

//example.h
#include <iostream>
using namespace std;
class Example{
public:
void say_hello();
};

//example.cpp

#include "example.h"

void Example::say_hello()
{
printf("hello");
}


2、再写一个swig模块定义文件如下

%module example
%{
#include "example.h"
%}
%include "example.h"


3、通过命令行运行:

$ swig -python -c++ example.i


如果是使用C源码,则选项:

$ swig -Python example.i


这样会创建两个不同的文件:example_wrap.cxx(如果用c源码是example_wrap.c),和python文件example.py。

4、使用python.distutils生成模块动态库

python自带一个distutils工具,可以用它来创建python的扩展模块。使用它也很简单,只需要先定义一个配置文件,通常是命名为setup.py,如下:

#!/usr/bin/env python

"""
setup.py file for SWIG C\+\+/Python example
"""

from distutils.core import setup, Extension

example_module = Extension('_example',
sources=['example.cpp', 'example_wrap.cxx',])
setup (name = 'example',
version = '0.1',
author = "www",
description = """Simple swig C\+\+/Python example""",
ext_modules = [example_module],
py_modules = ["example"],
)


注:swig生成的扩展模块对象名必须使用python模块名并在前面加上下划线_,刚才我们通过swig生成的python文件是example.py,所以这里的模块对象名必须是’_example’,否则无法顺利编译。

为setup.py添加c/c++ 头文件或者库的搜索路径

通过上网查询,得知,setup.py的ext_modules参数的详细解释,所以,只用在Extension中加上两个参数,如下:

example_module = Extension('_example',
sources=['example.cpp', 'example_wrap.cxx',],
include_dirs = ['C:\Progra~1\API','C:\Progra~1\include'],
library_dirs = ['C:\Progra~1\API\x64','C:\Progra~1\lib\Win32_i86']
)


include_dirs指定了搜索的头文件路径,library_dirs指定了搜索的动态库或者静态库的路径

注意如果路径中包含空格如Program Files,要用简写形式去除空格如Progra~1

5、编译

命令行中将当前工作目录切换到文件example.cpp,example_wrap.cxx,example.py,setup.py所在的目录,然后输入以下命令:

python setup.py build_ext --inplace


会在本目录下生成_example.pyd模块。

问题1:检测到“_MSC_VER”的不匹配项问题



打开GCLinkage.h定位问题如下:



_MSC_VER这个相当于做了宏的检测 _MSC_VER 定义编译器的版本。下面是一些编译器版本的_MSC_VER值:

MS VC++ 14.0 _MSC_VER = 1900 vs2015

MS VC++ 12.0 _MSC_VER = 1800 vs2013的编译器他的平台是v120

MS VC++ 11.0 _MSC_VER = 1700 vs2012的编译器他的平台是v110

MS VC++ 10.0 _MSC_VER = 1600 Visual C++ 2010

MS VC++ 9.0 _MSC_VER = 1500 Visual C++ 2008

MS VC++ 8.0 _MSC_VER = 1400 Visual C++ 2005

MS VC++ 7.1 _MSC_VER = 1310

MS VC++ 7.0 _MSC_VER = 1300

MS VC++ 6.0 _MSC_VER = 1200

MS VC++ 5.0 _MSC_VER = 1100

检测到“_MSC_VER”的不匹配项: 值“1900”不匹配最高值“1700”

原因:由于使用了vs2015,而源文件中只支持到vs2012

怎么看python使用的是哪个版本的vs?

cmd中执行python,输出:



python输出版本信息中就有

MSC v.1900 64 bit (AMD64)


解决方法

编辑Python安装目录/Lib/distutils/_msvccompiler.py(我这里是C:\Users\username\AppData\Local\Programs\Python\Python35\Lib\distutils),搜索这一行:

if version >= 14 and version > best_version:


修改为:

if version == 11 and version > best_version:


保存,再次运行python setup.py build,成功启动编译,最后在链接阶段报错,提示找不到库文件ucrt.lib

这个ucrt.lib是Visual C++ 2015对C语言运行库进行重构后的产物,对应以前版本Visual C++中的msvcrt.lib,解决的办法也很简单,打开VC安装目录/lib,找到msvcrt.lib,复制一份并更名为ucrt.lib,再次运行python setup.py build,编译成功。

问题2:LIBCMT.lib(memcpy.obj) : error LNK2005: memmove 已经在 ucrt.lib(MSVCR110D.dll)中定义

error LNK2005得知:

You are mixing code that was compiled with /MD (use DLL version of CRT) with code that was compiled with /MT (use static CRT library). That cannot work, all source code files must be compiled with the same setting. Given that you use libraries that were pre-compiled with /MD, almost always the correct setting, you must compile your own code with this setting as well.

在VS中可以用以下方法设置:



但是python的解决方法找了很久没有找到,只好还是在_msvccompiler.py中修改。可以看到,执行编译的命令行中部分信息如下:

>python example_setup.py build_ext --inplace
running build_ext
building '_example' extension
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\BIN\x86_amd64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MT
......


这里默认是/MT模式的。

在_msvccompiler.py找到这一行:

self.compile_options.append('/MD' if self._vcruntime_redist else '/MT')


修改为:

self.compile_options.append('/MD')


保存后,终于编译成功!

6、测试

import examlpe
example.Example().say_hello()


注:如果导入模块失败,需要将模块所在路径添加到sys.path中,在次导入就会成功

参考:

SWIG实现python对c++封装

SWIG官方说明文档

python的setup.py文件

python官方说明Packaging and Distributing Projects
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python swig C++