Windows下C++扩展模块的制作与Python调用


前言

需求:

  1. 珞石机械臂的C++SDK库只能在windows下运行
  2. 视觉感知生成抓取部分的代码使用PointnetGPD,python语言
  3. 需要用Python调用C++代码,即Python与C++通信

一、扩展模块

参考https://www.zhihu.com/question/23003213最高赞回答,第二点Python官方提供的实现方式(其基于Python2,Python3会有不同),后面有个答主给了Python3下的示例https://www.zhihu.com/question/23003213/answer/105223038。

扩展模块格式

下面每部分的作用都有给注释

#include <Python.h>
#include <iostream>
#include <Windows.h>
#include <vector>
#include "RobotAPI.h"

#pragma comment(lib, "RobotAPI.lib")
using namespace std;

int robot_function(double a){

	char ip[32] = "192.168.0.160";
	int port= 50502;
	int ret = 1;
	cout << "正在执行API_Init()···" << endl;
	ret = API_Init(ip, port);
	cout << "成功执行API_Init()···" << endl;
	return a;
}

static PyObject * _robot_function(PyObject *self, PyObject *args){ 
	// 包裹函数,负责将python的参数转化为C的参数(PyArg_ParseTuple)
	// 调用实际的great_function,并处理great_function的返回值,最终返回给Python
	double _a;
	int res;

	if(!PyArg_ParseTuple(args, "i", &_a))
		return NULL;
	res = robot_function(_a);
	return PyLong_FromLong(res);
}

static PyMethodDef GreateModuleMethods[]={
	// 导出表,负责告诉Python这个模块中有哪些函数可以被Python调用
	// 名字可以随便起
	// 每一项有4个参数:python环境的函数名、包裹函数、参数变长
	{
		"robot_function",
		_robot_function,
		METH_VARARGS,
		""
	},
	{NULL, NULL, 0, NULL} // 总是以这个结尾
};

static struct PyModuleDef robot_module = {
	PyModuleDef_HEAD_INIT,
	"robot_module",
	NULL,
	-1,
	GreateModuleMethods
};


PyMODINIT_FUNC PyInit_robot_module(void){
	// 导出函数,名字不是任取的,是module名称添加前缀Py_Init
	// 将模块名称和导出表进行连接
	PyObject *m;
	m = PyModule_Create(&robot_module);

	if(m == NULL)
		return NULL;
	cout << "init robot_module module" << endl;
	return m;
}

python setup.py build

可以在visual studio命令行下编译该.cpp文件,更方便的是使用python setuptools。在同级目录下创建setup.py,内容如下:

from setuptools import setup, Extension
robot_module = Extension('robot_module', sources=["robot_module.cpp"])
setup(ext_modules=[robot_module])

然后进行python setup.py build。值得注意的事,该命令是在编译该module,并生成build文件夹,其中就有当前python环境下的库.pyc。
而我们常用的python setup.py install,实际分为两步:第一步执行python setup.py build,第二步将生成的库文件复制到对应环境目录下的Lib中。

二、静态库与动态库

比历程复杂一些的是,我需要使用相当于自己的链接库。珞石提供了.lib,.dll,.h,在C++扩展模块中应该如何调用呢(这里因为我只是将C++作为扩展模块,觉得不方便使用VS,用VS的话比较简单)。

这里就先总结一下静态库lib和动态库dll吧——


        首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用。什么时候我们会用到库呢?一种情况是某些代码需要给别人使用,但是我们不希望别人看到源码,就需要以库的形式进行封装,只暴露出头文件。另外一种情况是,对于某些不会进行大的改动的代码,我们想减少编译的时间,就可以把它打包成库,因为库是已经编译好的二进制了,编译的时候只需要 Link 一下,不会浪费编译时间。

        上面提到库在使用的时候需要 Link,Link 的方式有两种,静态和动态,于是便产生了静态库和动态库。静态库即静态链接库(Windows 下的 .lib,Linux 和 Mac 下的 .a)。之所以叫做静态,是因为静态库在编译的时候会被直接拷贝一份,复制到目标程序里,这段代码在目标程序里就不会再改变了;动态库即动态链接库(Windows 下的 .dll,Linux 下的 .so,Mac 下的 .dylib)。与静态库相反,动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向动态库的引用。等到程序运行时,动态库才会被真正加载进来

        比如使用VS编译,在工程文件夹下找到.exe所在目录,只需要将.dll文件放在该目录下,.exe文件就能顺利运行。

        而我这里既用到了lib又用到了dll,我分析可能是因为在lib并没有实现代码,而是指向了dll。
        具体在程序中,只需要添加这一行:#pragma comment(lib, “RobotAPI.lib”),预处理,显示调用该lib。


总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值