获取非托管 DLL 路径以独立于版本加载 Python

Posted

技术标签:

【中文标题】获取非托管 DLL 路径以独立于版本加载 Python【英文标题】:Get unmanaged DLL path to load Python independent of the version 【发布时间】:2020-12-28 21:33:37 【问题描述】:

我寻找一种方法来检索安装在用户计算机中的 dll 的路径,但路径可能会根据他们决定安装它的位置而改变。找不到任何东西,所以我用自己的发现写了这篇文章(随意添加你自己的)。

一些背景:

我正在编写一个将 Python 加载到 C++ 中的模块(我的用户的机器已经在他们的路径中安装了 Python,但是 Python 版本和路径可能因用户而异)

但是,我发现了 2 个问题:

即使我使用可用于任何 python 3 版本的函数(例如 python 3.6 需要 python36.dll),链接器也会创建 dll 版本依赖项。 必须设置 PYTHONPATH 才能找到已安装的模块。

对于第一个问题,我使用 LoadLibrary 在运行时加载适当的 dll,但这仍然给用户留下了配置的负担(他必须配置他的系统中的哪个 dll,以及它的安装位置)。 如果您的用户知道他的配置,则工作正常

这让我开始猜测:

我能够加载 python3.dll(位于 python36.dll 或 python38.dll 旁边)并且我需要 dll 的路径来计算 PTYHONPATH(并且可能使用 python3 版本来获取正确的 dll使用,如python37.dll、python38.dll等)

【问题讨论】:

【参考方案1】:

除非您为 Python 定义 stable ABI,否则我不认为有一个好方法可以允许不同的 Python 次要版本(例如 3.6 或 3.8)。然而,根据我的经验,这导致 Python 的一个糟糕的子集不支持PyMemoryView 之类的东西。如果您可以将代码的 Python 部分隔离到它自己的 DLL,我还建议使用 delay load 链接器标志。这样,您就可以拥有一个配置文件,该文件在运行时读取 Python 库所在的位置并从适当的路径加载它。

【讨论】:

嗨,马特。是的,共同的函数子集很小,但老实说,我完全希望在 python3.dll 中定义其中的许多函数,因为它们在 python36 和 python38 等中是相同的。无论如何,我主要按照你的描述做了,但是延迟加载除外,因为它仍然具有名称依赖性(例如 python36.dll)。我的第一种方法是让用户端的配置(路径和 dll 名称),但事实证明,许多使用 python,但甚至不知道它安装在哪里。这就是为什么我必须自己猜测。 如果您使用稳定的 ABI,那么您将链接到 python3.dll,从而避免次要版本具有的名称依赖性。如果您想让用户更新配置文件,用户可以使用sysconfig.get_path('data') 查询他们的 python 安装目录。 感谢您的提示。稳定 ABI 的文档暗示将 Py_LIMITED_API 设置为支持的最小值应该可以工作,这将是我的首选方法。但是,Python 代码另有说明。它使用简单的#ifndef Py_LIMITED_API,省略了很多功能。似乎甚至我选择的那些(如加载文件或解析字符串)都被遗漏了,并且一些可用的在 3.9 中已弃用【参考方案2】:

首先,使用 LoadLibraryA(或 LoadLibraryW)加载库,然后使用 GetModuleFileNameA(或 GetModuleFileNameW)获取完整路径

//#include <stdio.h>
//#include <iostream>

    HMODULE pythonLib = nullptr;
    pythonLib = LoadLibraryA("python3.dll");
    if (pythonLib != nullptr) 
        char path[MAX_PATH];
        GetModuleFileNameA(pythonLib, path, MAX_PATH);
        std::cout << path << std::endl;
    

【讨论】:

以上是关于获取非托管 DLL 路径以独立于版本加载 Python的主要内容,如果未能解决你的问题,请参考以下文章

这个 DLL 是托管的还是非托管的?

在加载上下文中加载非托管静态 dll

非托管 DLL 无法在 ASP.NET 服务器上加载

使用非托管 DLL 来自 .NET 的系统范围外壳挂钩

几个appdomains调用相同的非托管DLL

C# 加载非托管 DLL:IIS 上的控制台应用程序和 webapp 之间的巨大性能差异