程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

(一)python調用c++代碼《從C++共享鏈接庫編譯到python調用指南》

編輯:Python

  • 1、前言
  • 2、介紹
  • 3、環境安裝
    • 3.1 gcc安裝
    • 3.2 cmake安裝
  • 4、編譯
    • 4.1 CMakeLists.txt
    • 4.2 編譯
    • 4.3 檢查
  • 5、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!


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved