You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 22:12:01