Cmake 在 Windows 10 上找不到 python37.dll,但文件路径在缓存文件中 (pybind11)

问题描述

我正在 Windows 10 机器上进行 64 位安装,python 3.7.9 安装在典型的“Program Files”目录中(不在 Anaconda 下),pybind11 安装在我的工作目录中。这里的目标只是让 pybind11 从 C++ 运行。程序编译正常,但可执行文件不运行,给出错误代码执行无法继续,因为找不到 python37.dll。”重新安装程序可能会解决这个问题。”但是,python37.dll(和调试版本)文件位置在生成的 CMakeCache.txt 文件中(包括在下面以及其他详细信息)。我尝试在 CMakeCache 中的文件路径周围加上引号.txt 希望错误只是由于“Program Files”目录名中的空格,并且在环境路径变量(PROGRA~1)中有“Program Files”的短代码版本,但错误仍然存​​在。我我是 Cmake 和 C++ 的新手。我缺少什么?

我发现的其他相关帖子涉及移动文件https://www.reddit.com/r/techsupport/comments/c2z5rl/python37dll_not_found_but_i_find_it_in_windows/,这不是这里的问题),或未安装 python 的系统(python37.dll not linked in executable,这里也不是这种情况),问题使用 Anaconda 安装(Why do I get a python37.dll error when starting jupyter notebook via conda,但我没有运行 Anaconda)或其他我没有使用的软件。所有其他链接都指向下载站点


两个程序的安装过程都没有错误。下面给出了程序目录、相关代码、构建命令和输出

从 ./NewKamodo/build 目录,通过在 cmd 提示符下的命令输出是(为了隐私,我已经用 ... 替换了我的内部结构):

...\NewKamodo\build>cmake .. -G"Visual Studio 15 2017" -A x64  
-- Selecting Windows SDK version 10.0.17763.0 to target Windows 10.0.19041.  
-- The C compiler identification is MSVC 19.16.27045.0  
-- The CXX compiler identification is MSVC 19.16.27045.0  
-- Detecting C compiler ABI info  
-- Detecting C compiler ABI info - done  
-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x64/cl.exe - skipped  
-- Detecting C compile features  
-- Detecting C compile features - done  
-- Detecting CXX compiler ABI info  
-- Detecting CXX compiler ABI info - done  
-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x64/cl.exe - skipped  
-- Detecting CXX compile features  
-- Detecting CXX compile features - done  
-- pybind11 v2.6.3 dev1  
-- Found PythonInterp: C:/Program Files/python37/python.exe (found version "3.7.9")  
-- Found PythonLibs: C:/Program Files/python37/libs/python37.lib  
-- Performing Test HAS_MSVC_GL_LTCG  
-- Performing Test HAS_MSVC_GL_LTCG - Success  
-- Found python3: C:/Program Files/python37/python.exe (found version "3.7.9") found components: Interpreter Development Development.Module Development.Embed  
-- Configuring done  
-- Generating done  
-- Build files have been written to: .../NewKamodo/build  

...\NewKamodo\build>cmake --build .  
Microsoft (R) Build Engine version 15.9.21+g9802d43bc3 for .NET Framework  
copyright (C) Microsoft Corporation. All rights reserved.  

  Checking Build System  
  Building Custom Rule .../NewKamodo/CMakeLists.txt  
  KamodoCXX.cpp  
  KamodoCXX.vcxproj -> ...\NewKamodo\build\Debug\KamodoCXX.exe  
  Building Custom Rule .../NewKamodo/CMakeLists.txt  

...\NewKamodo\build>cd Debug  
...\NewKamodo\build\Debug>KamodoCXX.exe  

弹出窗口错误:“代码执行无法继续,因为没有找到python37.dll。重新安装程序可能会解决这个问题。”


我的程序目录结构是:
新卡莫多

  • ./build
  • ./pybind11
  • CMakeLists.txt
  • KamodoCXX.cpp

KamodoCXX.cpp 中的 C++ 代码是取自 https://pybind11.readthedocs.io/en/stable/advanced/embedding.html 并复制到下面的 hello world 示例。

#include <pybind11/embed.h> // everything needed for embedding
namespace py = pybind11;

int main() {
    py::scoped_interpreter guard{}; // start the interpreter and keep it alive

    py::print("Hello,World!"); // use the Python API
}

CMakeLists.txt 文件也很简单:

cmake_minimum_required(VERSION 3.4)
project(KamodoCXX)

#specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_required True)

add_subdirectory(pybind11)
find_package(python3 COMPONENTS Interpreter Development)

add_executable(KamodoCXX KamodoCXX.cpp)
target_link_libraries(KamodoCXX PRIVATE pybind11::embed)

CMakeCache.txt 内容文件的 python 部分仅为简洁起见):
...

PYBIND11_INCLUDE_DIR:INTERNAL=.../NewKamodo/pybind11/include
//ADVANCED property for variable: PYTHON_EXECUTABLE
PYTHON_EXECUTABLE-ADVANCED:INTERNAL=1
PYTHON_INCLUDE_Dirs:INTERNAL=C:/Program Files/python37/include
PYTHON_IS_DEBUG:INTERNAL=0
PYTHON_LIBRARIES:INTERNAL=C:/Program Files/python37/libs/python37.lib
PYTHON_MODULE_EXTENSION:INTERNAL=.cp37-win_amd64.pyd
PYTHON_MODULE_PREFIX:INTERNAL=
PYTHON_VERSION:INTERNAL=3.7.9
PYTHON_VERSION_MAJOR:INTERNAL=3  
PYTHON_VERSION_MInor:INTERNAL=7  
Python_ADDITIONAL_VERSIONS:INTERNAL=3.10;3.9;3.8;3.7;3.6;3.5;3.4  
//CMAKE_INSTALL_PREFIX during last run  
_GNUInstallDirs_LAST_CMAKE_INSTALL_PREFIX:INTERNAL=C:/Program Files/KamodoCXX  
_Python:INTERNAL=PYTHON  
_python3_DEVELOPMENT_EMbed_SIGNATURE:INTERNAL=78025eb1b345e021c9dadb673f40d7b6  
_python3_DEVELOPMENT_MODULE_SIGNATURE:INTERNAL=78025eb1b345e021c9dadb673f40d7b6  
//Path to a program.  
_python3_EXECUTABLE:INTERNAL=C:/Program Files/python37/python.exe  
//Path to a file.  
_python3_INCLUDE_DIR:INTERNAL=C:/Program Files/python37/include  
//python3 Properties  
_python3_INTERPRETER_PROPERTIES:INTERNAL=Python;3;7;9;64;;cp37-win_amd64;C:\Program Files\python37\Lib;C:\Program Files\python37\Lib;C:\Program Files\python37\Lib\site-packages;C:\Program Files\python37  \Lib\site-packages  
_python3_INTERPRETER_SIGNATURE:INTERNAL=d8451d76c667fb34c5414ba253c4dadd  
//Path to a library.  
_python3_LIBRARY_DEBUG:INTERNAL=C:/Program Files/python37/libs/python37_d.lib  
//Path to a library.  
_python3_LIBRARY_RELEASE:INTERNAL=C:/Program Files/python37/libs/python37.lib  
//Path to a library.  
_python3_RUNTIME_LIBRARY_DEBUG:INTERNAL=C:/Program Files/python37/python37_d.dll  
//Path to a library.  
_python3_RUNTIME_LIBRARY_RELEASE:INTERNAL=C:/Program Files/python37/python37.dll  
//True if pybind11 and all required components found on the system
pybind11_FOUND:INTERNAL=TRUE  
//Directory where pybind11 headers are located  
pybind11_INCLUDE_DIR:INTERNAL=.../NewKamodo/pybind11/include  
//Directories where pybind11 and possibly Python headers are located  
pybind11_INCLUDE_Dirs:INTERNAL=.../NewKamodo/pybind11/include;C:/Program Files/python37/include 

解决方法

这是我们过去使用 python 2.7 所做的,但它可能适用于 3+。我们通过从 cmake 运行 python 来获取 python 库的完整路径。

add_subdirectory(pybind11)
find_package(Python3 COMPONENTS Interpreter Development)
FIND_PACKAGE(PythonLibs "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" REQUIRED)
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import sys; from distutils.sysconfig import get_python_lib; print(get_python_lib().split(sys.prefix)[-1][1:])"
                    OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE)

*为 python3 编辑

,

我与 Pybind11 开发人员在此 BUG 帖子上合作以实现最终解决方案,我将在下面进行总结。沿途弹出的替代错误是:

Fatal Python Error: initfsencoding: unable to load the file system codec
ModuleNotFoundError: No module named ‘encodings’

尝试从命令提示符运行可执行文件时。

https://github.com/pybind/pybind11/issues/2855#issuecomment-777648383


在 Windows 10 上(不使用适用于 linux 的 Windows 子系统):

  • 安装 Anaconda 或 miniconda
  • 使用命令构建 conda 环境
conda create -n embedtest -c conda-forge python==3.7.9 pybind11==2.6.2 cmake=3.19.4
conda activate embedtest

注意:3.15 以后的任何版本的 cmake 似乎都可以工作。我没有指定pybind11或cmake的哪个版本,并成功使用了cmake 3.19.4。 (Pybind11 版本 2.6.2 是当前默认值)。此外,请避免使用 3.8 或 3.9 的 Python 版本,因为它们已知不起作用(请参阅 pybind11 文档)。

CMakeLists.txt 内容:

cmake_minimum_required(VERSION 3.15)
project(main)

find_package(Python COMPONENTS Interpreter Development) 
find_package(pybind11 REQUIRED)

add_executable(main main.cpp)
target_link_libraries(main pybind11::embed)
  • 接下来从 Windows 命令提示符运行以下命令,其中 conda 环境已激活,并且您已移动到 main.cpp 和 CMakeLists.txt 文件所在的同一目录。请注意,-B 命令在名为 build 的子目录中构建输出。
cmake -B build -A x64
cmake --build build
set PYTHONHOME=C:\Users\test\Miniconda3\venvs\embedtest
build\Debug\main.exe

注意:必须从终端设置 PYTHONHOME 变量,因为使用 cmake 设置此变量不会使新定义在构建时或执行时可用,从而导致错误。这里给出的目录示例是python可执行文件在conda环境中的位置,在使用find_package(Python COMPONENTS ....)找到python包后,通过在CMakeLists.txt代码中添加以下行即可轻松获取

message(STATUS ${Python_EXECUTABLE})

如果您的目标是在没有虚拟环境的情况下使用 pybind11,则不需要 set(Python_VIRTUALENV ONLY) 行,但调用的 Python 版本将是默认安装的版本。


如果您希望通过 WSL 在 Windows 10 上使用 pybind11,那么说明几乎相同。 CMakeLists.txt 和 main.cpp 文件相同,但终端命令略有不同:

cmake -B build
cmake --build build
cd build
chmod +x main
./main