(一)python调用c++代码《从C++共享链接库编译到python调用指南》


该系列文章:
(一)python调用c++代码《从C++共享链接库编译到python调用指南》
(二)ndarray(Python)与Mat(C++)数据的传输
(三)C++结构体与python的传输

1、前言

对于某些时候,我们希望能在python中调用c++代码,或许是为了追求速度,或许是为了调用现成的c++代码。

网上也有很多相关方面的教程,但他们的c++代码仅仅为一个函数或者一个类,情况比较简单。

我找到了一个不错的c++项目,但是我没有能力用python重写,所以我将c++中的main函数写成一个类,并希望导出为共享链接库(.so文件),在python中调用。

我的难点在于我希望导出的这个类,使用了第三方库OpenCV,以及这个类还使用了其他的类,情况一下就复杂了。

实际上这也符合真实情况,如果我只想调用c++实现的一个函数或者单纯的类,为什么不直接用python写呢?实际情况才是如同上面我讲的那样,情况复杂。

2、介绍

{这里给出一张图}

注意:opencv.cpp是作者自己写的一个类(类似于RPPG.cpp),而OpenCV是第三方库,不要混淆了

三个类都使用了OpenCV第三方库,同时HB使用了RPPG类和opencv类,RPPG使用了opencv类,而我要导出HB类,使其可以在python中调用,依赖关系复杂了。

所以,我们使用cmake来帮助编译so文件

3、环境安装

首先我们在Ubuntu20.04中编译( (一)Ubuntu安装详细教程(从镜像制作到NVIDIA驱动安装全流程)——超详细的图文教程

3.1 gcc安装

先查看是否安装gcc:
在这里插入图片描述

如果没有安装:

# 在终端中,依次执行
sudo apt-get update
sudo apt-get install build-essential gdb

3.2 cmake安装

先查看是否安装cmake:
在这里插入图片描述
如果没有安装,请参阅 Kitware APT存储库中适用于您的平台的说明

4、编译

# .hpp 头文件,用于申明
# .cpp 实现头文件中申明的函数或类
-project
--HB.cpp
--HB.hpp
--RPPG.cpp
--RPPG.hpp
--opencv.cpp
--opencv.hpp
--......

首先我的结构目录如上,在节2中给出了之间的关系,我们的目的是导出HB.cpp为so文件

4.1 CMakeLists.txt

我们知道编译时会指定许多参数,CMakeLists.txt就是告诉cmake我们编译时的参数设定。

我们在project文件夹下新建CMakeLists.txt文件,内容如下:

cmake_minimum_required(VERSION 3.0.0)	# 最小版本
project(hbp VERSION 0.1.0)  # 项目名称

set(CMAKE_CXX_FLAGS "-std=c++11")   # 添加c++11标准

find_package(OpenCV REQUIRED) # 添加OpenCV库
include_directories(${OpenCV_INCLUDE_DIRS})

add_library(opencv SHARED opencv.cpp)	# 把opencv.cpp导出为链接库,SHARED指定为共享链接库
target_link_libraries(opencv ${OpenCV_LIBS})	#因为opencv.cpp使用了OpenCV,所以将OpenCV链接到opencv中,相当于告诉opencv去哪儿找OpenCV

add_library(RPPG SHARED RPPG.cpp)
target_link_libraries(RPPG ${OpenCV_LIBS})	# RPPG也使用了OpenCV库,也要链接

add_library(HB SHARED HB.cpp)
target_link_libraries(HB ${OpenCV_LIBS})	# HB也使用了OpenCV库

target_link_libraries(RPPG opencv)	# RPPG还使用了opencv类
target_link_libraries(HB RPPG) # HB使用了RPPG(同时RPPG链接了opencv,相当于HB间接链接了opencv)

可以看出:

  1. 第三方库是通过target_link_libraries直接链接
  2. 自定义类要先通过add_library定义为共享链接库,后面再通过target_link_libraries链接

4.2 编译

在project中新建build文件夹:

-project
--build/
--CMakeLists.txt
--HB.cpp
--HB.hpp
--RPPG.cpp
--RPPG.hpp
--opencv.cpp
--opencv.hpp
--......

再终端中进入build/,执行命令:$ cmake ..
在这里插入图片描述
再执行:$ make
在这里插入图片描述
然后就得到了想要的HB.so文件:
在这里插入图片描述
(会自动加lib-前缀,所以libHB.so就是编译好的文件)

4.3 检查

编译时成功不代表真的成功,我们需要检查一下。
执行命令$ ldd -r libHB.so
在这里插入图片描述
在这里插入图片描述
这代表成功了。

失败了是什么样的?

如果我直接按照python调用C++中的函数【最简明教程】编译so文件:$ g++ -o HB.so -shared -fPIC HB.cpp得到HB.so文件,现在检查一下这个有没有问题$ ldd -r HB.so
在这里插入图片描述
可以看到出现大量的"undefined symbol:“,从后面的_ZN2cv8fastFreeEPv可以看出是缺少OpenCV的链接,导致使用的OpenCV函数为"undefined symbol:”,同理还可以看到“RPPG”等。

如果你想查看是具体什么函数,你可以执行命令:
c++filt _ZN2cv8fastFreeEPv就可以查看到后面的一串到底代表哪个函数
在这里插入图片描述

5、python中调用

直接给代码:

import ctypes
dll=ctypes.cdll.LoadLibrary

# 加载so链接库
lib=dll("./libHB.so")

# 这里是调用HB类中的load函数
lib.load()

可以看到C++中HB.load()函数执行成功会打印字符串:
在这里插入图片描述
验证一下,运行python代码,ok!
在这里插入图片描述

6、补充:一个更简单的方法编译共享链接库

实际上我们可以使用一下命令将HB.cpp编译为共享链接库:

g++ -std=c++11 \
    -o HB.so \
    -shared \
    -fPIC HB.cpp opencv.cpp RPPG.cpp \
    `pkg-config --cflags --libs opencv`

如此便成功将HB.cpp编译并保存在HB.so文件

下面简单解释一下

g++ -std=c++11 \  # 指定了c++11标准
    -o HB.so \	# output
    -shared \	# 创建共享链接库
    #链接使用到的cpp,整个项目使用到了这三个cpp,所以全写上
    -fPIC HB.cpp opencv.cpp RPPG.cpp \ #
    # 链接使用的第三方库opencv,你可以通过pkg-config opencv --modversion看看是否正确安装了opencv,如果是则会显示版本号比如3.4.11
    `pkg-config --cflags --libs opencv` 

注意:pkg-config --cflags --libs opencv 前后的“撇”不是单引号,是左上角1旁边的按键符号

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是一个对称矩阵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值