C++如何调用Python自定义模块?
安装Python pybind11模块
pip3 install pybind11 -i https://pypi.tuna.tsinghua.edu.cn/simple
Python基础代码示例
这里使用一位兄弟博客的代码:
https://blog.csdn.net/sunny23666/article/details/109479950
cat >> c_test.py << EOF
class Dog():
def __init__(self, name, action):
self.name=name
self.action=action
def get_name(self):
return self._name
def get_action(self):
return self.action
def add(self,i,j):
print ("Hi")
return i+j
def type_test(self,a):
n=list()
if a==1:
n={1, 2, 3}
else:
n={5, 5, 5}
print("type test")
return n
def dict_test(self,b):
d=dict()
if b==1:
d={"wo":2, "ni":3}
else:
d={"hei" :3, "ha":5}
return d
def set_test(self,c):
e=set()
if c==1:
e={1,2,3,3}
else:
e={2,3,3,3}
return e
def tuple_test(self,d):
f=tuple()
if d==1:
f=(5, 6, 7)
else:
f=(7,8,9)
return f
EOF
C++代码示例
这里使用一位兄弟博客的代码:
https://blog.csdn.net/sunny23666/article/details/109479950
cat >> main.cpp <<
#include <pybind11/embed.h>
#include<iostream>
#include<pybind11/stl.h>
namespace py=pybind11;
int main() {
py::scoped_interpreter python;
py::print("hello world");
//用py::object导入python类模块并进行类的初始化
py::object Dog=py::module::import("c_test").attr("Dog");
py::object obj=Dog("miao", "sit");
// function_test
py::object add=obj.attr("add");
py::object result2=add(2,4);
//注:python返回值到c++中需要类型转换,用cast<数据类型>()来进行转换
int n=result2.cast<int>();
std::cout<<n<<std::endl;
//list_test 集合类型
py::object type_test=obj.attr("type_test");
py::object result3=type_test(2);
py::list v=result3.cast<py::list>();
std::cout<<v<<std::endl;
//dict_test 字典类型
py::object dict_test=obj.attr("dict_test");
py::object result4=dict_test(1);
py::dict dd=result4.cast<py::dict>();
std::cout<<dd<<std::endl;
//set_ test 列表类型
py::object set_test=obj.attr("set_test");
py::object result5=set_test(3);
py::set ss=result5.cast<py::set>();
std::cout<<ss<<std::endl;
//tuple_ test 元组类型测试
py::object tuple_test=obj.attr("tuple_test");
py::object result6=tuple_test(1);
py::tuple tt=result6.cast<py::tuple>();
std::cout<<tt<<std::endl;
return 0;
}
EOF
编写cmake配置
##方式一:
cat >>CMakeLists.txt <<EOF
# 建议使用CMake3.12+以支持现代Python查找
cmake_minimum_required(VERSION 3.12)
project(pf_test)
# 设置 C++11 标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 查找Python解释器和库
# 可以利用cmake内置的自动发现配置,或者像下面方式二手动指定,手动指定需要我们自己找到对应目录
find_package(Python REQUIRED COMPONENTS Interpreter Development)
# 不能使用如下方式,cmake自动发现机制要求安装的pybind11下有配置Config.cmake文件,或者cmake内置有Findxxx.cmake
# find_package(pybind11 REQUIRED /software/py_c_ext/lib/python3.12/site-packages/pybind11/include/)
# 添加可执行文件或库
add_executable(pf_test # 生成执行文件
main.cpp
)
# 查找 pybind11(确保已安装 pybind11)
# 使用find_package自动查找到的头文件
target_include_directories(pf_test PRIVATE Python)
# 这里需要指定完整路径,不能像上面Python头文件一样自动发现。
target_include_directories(pf_test PRIVATE /software/py_c_ext/lib/python3.12/site-packages/pybind11/include/)
# 链接Python, 不需要链接pybind11,因为我们已经在代码中引入了头文件,Python为pybind11所依赖的
target_link_libraries(pf_test PRIVATE
Python::Python
)
# 设置输出文件名(可选)
set_target_properties(pf_test PROPERTIES
PREFIX ""
SUFFIX ".exe" # 生成后缀.exe执行文件
)
EOF
##方式二:
cat >>CMakeLists.txt <<EOF
# 建议使用 CMake 3.12+ 以支持现代 Python 查找
cmake_minimum_required(VERSION 3.12)
project(pf_test)
# 设置C++11标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 查找Python 解释器和库
#find_package(Python REQUIRED COMPONENTS Interpreter Development)
# 添加可执行文件或库
add_executable(pf_test # 生成执行文件
main.cpp
)
# 查找 pybind11(确保已安装 pybind11)
# 头文件路径怎么获取吗?
# python -c "import sysconfig; print(sysconfig.get_path('include'))"
target_include_directories(pf_test PRIVATE /usr/include/python3.12)
# 一般性的pip安装路径,可以通过Python搜索路径查找。
# python3 -c "import sys; print(sys.path)"
target_include_directories(pf_test PRIVATE /software/py_c_ext/lib/python3.12/site-packages/pybind11/include/)
# 链接Python
# Python::Python
# 不用上面find_package的自动发现机制,我们手动指定了路径,这个路径怎么获取吗?
# python3 -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))"
target_link_libraries(pf_test PRIVATE
/usr/lib/x86_64-linux-gnu/libpython3.12.so
)
# 设置输出文件名(可选)
set_target_properties(pf_test PROPERTIES
PREFIX ""
SUFFIX ".exe" # 生成后缀.exe执行文件
)
EOF
执行
# 将上面三个文件保存后,放在同一个目录下,比如src
mkdir src && cd src
# 创建上面三个文件
...
# 创建构建目录
mkdir build && cd build
# 执行构建
cmake ..
make
# 构建完成后复制执行文件到src目录下,因为py脚本在该目录
cp pf_test.exe ../
# 运行
./pf_test.exe
备注
这里面的关键点在于c++依赖包pybind11中py::module::import方法,导入Python代码,通过pybind11内置的属性或者方法去加载py脚本使用。而我们通过Python调用C++模块则是通过PYBIND11_MODULE(example, m)提供给Python使用。