编辑
2024-09-03
Python
0
请注意,本文编写于 226 天前,最后修改于 226 天前,其中某些信息可能已经过时。

目录

pybind11安装
库的编写
CMake编译配置
cmakelists
vscode编译
终端编译
python调用
可能的错误及解决办法
测试成功但是编译不成功
编译成功python调用提示‘找不到指定的模块’

pybind11安装

pybind11安装很简单,只需要

shell
pip install pybind11

库的编写

编写一个简单的加法函数myadd.cpp

cpp
#include <pybind11/pybind11.h> // 一个简单的 C++ 函数 int add(int i, int j) { return i + j; } // PYBIND11_MODULE 宏用于定义 Python 模块 PYBIND11_MODULE(myadd, m) // 这里将模块名称改为 'myadd' { m.def("add", &add, "A function that adds two numbers"); }

编辑器会在第一行报错,因为它找不到这个文件。此时就要在编辑器的Include Path中加上

C:\Users\gbwat\AppData\Local\Programs\Python\Python311\Include C:\Users\gbwat\AppData\Local\Programs\Python\Python311\Lib\site-packages\pybind11\include C:\Users\gbwat\AppData\Local\Programs\Python\Python311\libs

这样就不会报错了。此处需要根据自己的python版本和安装位置进行修改

CMake编译配置

cmakelists

使用CMake编译是非常方便的,我使用的CMakelists.txt如下

cmake
cmake_minimum_required(VERSION 3.12) project(myadd) # 设置 pybind11 的目录路径 set(pybind11_DIR "C:/Users/gbwat/AppData/Local/Programs/Python/Python311/Lib/site-packages/pybind11/share/cmake/pybind11") # 寻找 pybind11 包 find_package(pybind11 REQUIRED) # 设置静态链接 set(BUILD_SHARED_LIBS OFF) # 添加 C++ 模块 pybind11_add_module(myadd myadd.cpp) # 模块名称 'myadd' # 设置输出目录 set_target_properties(myadd PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) # 针对 Windows 平台的额外设置 if (WIN32) target_compile_definitions(myadd PRIVATE NOMINMAX) target_link_libraries(myadd PRIVATE ${PYTHON_LIBRARIES}) # 针对 MinGW 添加静态链接选项 if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") target_link_options(myadd PRIVATE -static-libgcc -static-libstdc++) endif() endif() if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") target_compile_options(myadd PRIVATE -Wall -Wextra -Wpedantic) elseif (MSVC) target_compile_options(myadd PRIVATE /W4 /permissive-) endif() message(STATUS "Using C++ compiler: ${CMAKE_CXX_COMPILER}") message(STATUS "Using Python include directories: ${PYTHON_INCLUDE_DIRS}") message(STATUS "Output library will be placed in: ${CMAKE_CURRENT_SOURCE_DIR}")

注意一定要设置静态链接,否则在python中调用会找不到dll从而出错!!!

vscode编译

在vscode中安装CMAKE扩展后直接点击生成即可

image.png

生成完毕即可在当前目录下找到编译出的文件myadd.cp311-win_amd64.pyd

终端编译

我使用的是MinGW编译器,不同的编译器需要使用不同的命令

在当前目录建立一个新文件夹build,在终端中进入文件夹

ahell
cd build

随后执行cmake命令进行配置

shell
cmake -G "MinGW Makefiles" ..

随后执行编译

mingw32-make

就可以在上级目录(build文件夹的上级目录)看见编译出的myadd.cp311-win_amd64.pyd

python调用

确保python脚本与myadd.cp311-win_amd64.pyd处于同一目录中,随后直接import就可以了。一个实例如下

python
import myadd print(myadd.add(1, 2))

运行之,会输出结果3

可能的错误及解决办法

测试成功但是编译不成功

该情况下CMake会输出

[main] 正在生成文件夹: d:/py/build [build] 正在启动生成 [proc] 执行命令: "C:\Program Files\CMake\bin\cmake.EXE" --build d:/py/build --config Debug --target all -j 24 -- [build] [ 50%] Linking CXX shared module myadd.cp311-win_amd64.pyd [build] Copying runtime dependencies [build] Error copying file "/python312.dll" to "D:/py/build". [build] mingw32-make[2]: *** [CMakeFiles\myadd.dir\build.make:104: myadd.cp311-win_amd64.pyd] Error 1 [build] mingw32-make[2]: *** Deleting file 'myadd.cp311-win_amd64.pyd' [build] mingw32-make[1]: *** [CMakeFiles\Makefile2:82: CMakeFiles/myadd.dir/all] Error 2 [build] mingw32-make: *** [Makefile:90: all] Error 2 [proc] 命令“"C:\Program Files\CMake\bin\cmake.EXE" --build d:/py/build --config Debug --target all -j 24 --”已退出,代码为 2 [driver] 生成完毕: 00:00:01.309 [build] 生成已完成,退出代码为 2 [rollbar] 未处理的异常: 未处理的拒绝承诺: ctest Error: 生成失败。 {}

这是因为gcc版本太低,经测试gcc 8.1不能成功编译但是gcc 14可以

编译成功python调用提示‘找不到指定的模块’

这种情况下python会报错

PS D:\py> python .\test.py Traceback (most recent call last): File "D:\py\test.py", line 1, in <module> import myadd ImportError: DLL load failed while importing myadd: 找不到指定的模块。

这是因为找不到dll。用Process Monitor查看调用情况如下

image.png

可见是c++库的dll找不到。这是因为编译器的lib没有加入PATH。好的做法是使用静态链接,就像前面说的那样

本文作者:GBwater

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!