在C++ DLL中嵌入Python:移除vcpkg依赖并解决编码模块缺失问题
问题:将Python嵌入C++ DLL并实现独立运行
尝试将Python嵌入C++ DLL,目标是DLL发布后可独立运行,无需依赖外部Python安装包或资源。目前仅在包含vcpkg_installed目录的解决方案路径下能正常运行,将文件移至其他目录(如scraps文件夹)时,抛出ModuleNotFoundError: No module named 'encodings'错误,如何摆脱对vcpkg_installed目录的依赖?
代码
py_wrap.cpp(DLL实现文件)
void assertPyInit() { if (!Py_IsInitialized()) { PyConfig config; PyConfig_InitPythonConfig(&config); // Get the executable path instead of current working directory wchar_t exePath[MAX_PATH]; GetModuleFileNameW(NULL, exePath, MAX_PATH); // Remove the executable name to get the directory std::wstring exeDir = exePath; size_t lastSlash = exeDir.find_last_of(L"\\"); if (lastSlash != std::wstring::npos) { exeDir = exeDir.substr(0, lastSlash); } // Now build Python path relative to executable location std::wstring pythonHome = exeDir + L"\\..\\..\\vcpkg_installed\\x64-windows-static-md\\x64-windows-static-md\\tools\\python3"; // Resolve the full path to eliminate .. references wchar_t resolvedPath[MAX_PATH]; GetFullPathNameW(pythonHome.c_str(), MAX_PATH, resolvedPath, NULL); pythonHome = resolvedPath; std::wstring pythonLib = pythonHome + L"\\Lib"; std::wstring pythonSitePackages = pythonLib + L"\\site-packages"; std::wstring pythonDLLs = pythonHome + L"\\DLLs"; // Set the Python home directory PyConfig_SetString(&config, &config.home, pythonHome.c_str()); // Set the module search paths std::wstring pythonPathEnv = pythonLib + L";" + pythonSitePackages + L";" + pythonDLLs; PyConfig_SetString(&config, &config.pythonpath_env, pythonPathEnv.c_str()); PyStatus status = Py_InitializeFromConfig(&config); PyConfig_Clear(&config); if (PyStatus_Exception(status)) { PyErr_Print(); return; } PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.append(\".\")"); } } void MY_DLL pyPrint(const char* message) { assertPyInit(); PyObject* pyStr = PyUnicode_FromString(message); if (pyStr) { PyObject* builtins = PyEval_GetBuiltins(); PyObject* printFunc = PyDict_GetItemString(builtins, "print"); if (printFunc && PyCallable_Check(printFunc)) { PyObject* args = PyTuple_Pack(1, pyStr); PyObject_CallObject(printFunc, args); Py_DECREF(args); } Py_DECREF(pyStr); } }
DLLTester.cpp(测试客户端程序)
#include <iostream> #include "py_wrap.h" int main() { std::cout << "Hello\n"; pyPrint("Hello from python:D !"); }
文件结构与运行输出
在解决方案目录AsyncDLLMQL\x64\Release\下运行DLLTester.exe可正常输出;移至scraps目录运行时出现错误,输出如下:
PS D: \RedactedLabs\Dev > .\scraps\DLLTester.exe Hello Python path configuration: PYTHONHOME= 'D:\RedactedLabs\vcpkg_installed\x64-windows-static-md\x64-windows-static-md\tools\python3' PYTHONPATH = 'D:\RedactedLabs\vcpkg_installed\x64-windows-static-md\x64-windows-static-md\tools\python3\Lib;D:\RedactedLabs\vcpkg_installed\x64-windows-static-md\x64-windows-static-md\tools\python3\Lib\site-packages;D:\RedactedLabs\vcpkg_installed\x64-windows-static-md\x64-windows-static-md\tools\python3\DLLs' program name = 'python' isolated = 0 environment = 1 user site = 1 safe_path = 0 import site = 1 is in build tree = 0 stdlib dir = 'D:\RedactedLabs\vcpkg_installed\x64-windows-static-md\x64-windows-static-md\tools\python3\Lib' sys._base_executable = 'D:\\RedactedLabs\\Dev\\scraps\\DLLTester.exe' sys.base_prefix = 'D:\\RedactedLabs\\vcpkg_installed\\x64-windows-static-md\\x64-windows-static-md\\tools\\python3' sys.base_exec_prefix = 'D:\\RedactedLabs\\vcpkg_installed\\x64-windows-static-md\\x64-windows-static-md\\tools\\python3' sys.platlibdir = 'DLLs' sys.executable = 'D:\\RedactedLabs\\Dev\\scraps\\DLLTester.exe' sys.prefix = 'D:\\RedactedLabs\\vcpkg_installed\\x64-windows-static-md\\x64-windows-static-md\\tools\\python3' sys.exec_prefix = 'D:\\RedactedLabs\\vcpkg_installed\\x64-windows-static-md\\x64-windows-static-md\\tools\\python3' sys.path = [ 'D:\\RedactedLabs\\vcpkg_installed\\x64-windows-static-md\\x64-windows-static-md\\tools\\python3\\Lib', 'D:\\RedactedLabs\\vcpkg_installed\\x64-windows-static-md\\x64-windows-static-md\\tools\\python3\\Lib\\site-packages', 'D:\\RedactedLabs\\vcpkg_installed\\x64-windows-static-md\\x64-windows-static-md\\tools\\python3\\DLLs', 'D:\\RedactedLabs\\Dev\\scraps\\python312.zip', 'D:\\RedactedLabs\\vcpkg_installed\\x64-windows-static-md\\x64-windows-static-md\\tools\\python3\\DLLs', 'D:\\RedactedLabs\\vcpkg_installed\\x64-windows-static-md\\x64-windows-static-md\\tools\\python3\\Lib', 'D:\\RedactedLabs\\Dev\\scraps', ] ModuleNotFoundError: No module named 'encodings'
环境配置信息
- 平台:Windows
- IDE:Visual Studio
- 使用Vcpkg清单:是
- 目标三元组:
x64-windows-static-md - 附加包含目录:
$(SolutionDir)vcpkg_installed\x64-windows-static-md\x64-windows-static-md\include\python3.12 - 附加库目录:
$(VcpkgInstalledDir)\x64-windows-static-md\lib
解决方案
1. 打包Python运行时文件到发布目录
从vcpkg安装路径x64-windows-static-md\tools\python3下,复制以下内容到你的DLL和测试程序所在的目录(如scraps):
Lib文件夹:核心模块所在目录,必须保留encodings子文件夹DLLs文件夹:包含编译后的Python扩展模块- 若存在
python312._pth等配置文件,一并复制
2. 修改Python初始化代码,移除vcpkg路径依赖
修改assertPyInit函数,让Python从当前程序目录加载运行时文件,而非依赖vcpkg的固定路径:
void assertPyInit() { if (!Py_IsInitialized()) { PyConfig config; PyConfig_InitPythonConfig(&config); // 获取当前程序所在目录 wchar_t exePath[MAX_PATH]; GetModuleFileNameW(NULL, exePath, MAX_PATH); std::wstring exeDir = exePath; size_t lastSlash = exeDir.find_last_of(L"\\"); if (lastSlash != std::wstring::npos) { exeDir = exeDir.substr(0, lastSlash); } // 设置Python home为当前目录下的python3文件夹(即我们复制的运行时目录) std::wstring pythonHome = exeDir + L"\\python3"; std::wstring pythonLib = pythonHome + L"\\Lib"; std::wstring pythonSitePackages = pythonLib + L"\\site-packages"; std::wstring pythonDLLs = pythonHome + L"\\DLLs"; // 配置Python环境 PyConfig_SetString(&config, &config.home, pythonHome.c_str()); std::wstring pythonPathEnv = pythonLib + L";" + pythonSitePackages + L";" + pythonDLLs; PyConfig_SetString(&config, &config.pythonpath_env, pythonPathEnv.c_str()); // 启用孤立模式,避免读取系统或用户的Python配置,保证独立性 config.isolated = 1; PyStatus status = Py_InitializeFromConfig(&config); PyConfig_Clear(&config); if (PyStatus_Exception(status)) { PyErr_Print(); return; } // 添加当前目录到模块搜索路径 PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.append(\".\")"); } }
3. 确认静态链接Python库
由于使用的是x64-windows-static-md三元组,vcpkg已提供静态版本的Python库。确保项目链接的是静态库(如python312.lib),无需携带Python的动态DLL文件。
4. 验证独立运行
将DLL、测试程序、以及复制的python3文件夹放在同一目录下,运行测试程序,即可正常执行,不再依赖vcpkg_installed目录。
内容的提问来源于stack exchange,提问作者Fares
相关产品推荐
相关产品推荐

