pip如何告诉Python如何导入C扩展



我希望以可移植的方式使用sysv_ipc库。

我用安装了它

pip3 install sysv_ipc

然后从Python:

import sysv_ipc
sysv_ipc.__file__
# Output:
# /home/x/.local/lib/python3.9/site-packages/sysv_ipc.cpython-39-x86_64-linux-gnu.so

如果我将该文件复制到一个文件夹,pip uninstall库,然后从该文件夹打开python并尝试相同的导入,则失败。

我试着检查安装了什么,发现:

/home/x/.local/lib/python3.9/site-packages/sysv_ipc-1.1.0.dist-info
/home/x/.local/lib/python3.9/site-packages/sysv_ipc.cpython-39-x86_64-linux-gnu.so
/home/x/.local/lib/python3.9/site-packages/sysv_ipc-1.1.0.dist-info/INSTALLER
/home/x/.local/lib/python3.9/site-packages/sysv_ipc-1.1.0.dist-info/LICENSE
/home/x/.local/lib/python3.9/site-packages/sysv_ipc-1.1.0.dist-info/METADATA
/home/x/.local/lib/python3.9/site-packages/sysv_ipc-1.1.0.dist-info/RECORD
/home/x/.local/lib/python3.9/site-packages/sysv_ipc-1.1.0.dist-info/REQUESTED
/home/x/.local/lib/python3.9/site-packages/sysv_ipc-1.1.0.dist-info/WHEEL
/home/x/.local/lib/python3.9/site-packages/sysv_ipc-1.1.0.dist-info/top_level.txt

我也没有在setup.py中找到线索。

我想弄清楚的是-

pip与要从该特定文件导入sysv_ipc的Python有何关联?

Pip在Python处理扩展模块导入的方式中不起任何作用。Python所需要的只是扩展模块文件本身,前提是它是当前操作系统支持的格式,并且该文件位于sys.path搜索路径上的目录中。

Pip只负责确保组成项目分发的文件最终位于sys.path位置。您找到的.dist-info目录是包元数据的一部分,由pip和importlib.metadata用于卸载、依赖项跟踪和报告等操作。导入时不使用这些文件。

你还没有分享你是如何尝试导入扩展模块的,也没有分享它是如何失败的,所以我不能评论你出了什么问题。

但是,如果工作正常,从动态加载的共享对象库导入模块的工作方式与导入常规模块非常相似:

  1. Python使用PathFinder对象在sys.path列表上的所有目录中搜索与导入名称匹配的文件和目录。它知道要根据文件扩展名查找扩展模块(支持的文件扩展名取决于您的操作系统,请参阅importlib.machinery.EXTENSION_SUFFIXES以获取列表(
  2. 如果找到一个扩展名后缀与导入的名称匹配的文件,则使用importlib.machinery.ExtensionFileLoader类加载库

加载意味着:使用依赖于操作系统的动态加载函数加载文件中的代码,然后访问入口点函数(通常为PyInit_<modulename>(以获取模块名称空间。请参阅有关创建扩展模块的文档。对于.so文件,Python/dynload_shlib.c文件实现加载器,但在同一目录中还有其他dynload_实现。要加载.so文件,Python将文件路径(至少包含一个/斜线(传递给dlopen()函数。

至于在您的案例中可能出错的地方:您使用了与用于安装项目的Python解释器不同的Python解释器。请注意,扩展模块文件名在模块名称后面包含一个字符串,用于标识PythonABI(应用程序二进制接口(:

sysv_ipc.cpython-39-x86_64-linux-gnu.so
######## ^^^^^^^^^^^^^^^^^^^^^^^^^^^
module   ABI identifier

标识符可以将多个Python版本的扩展文件安装到同一目录中。查看importlib.machinery.EXTENSION_SUFFIXES:,检查您的特定Python二进制文件接受哪些扩展

$ python3 -c "from importlib.machinery import EXTENSION_SUFFIXES;print(EXTENSION_SUFFIXES)"
['.cpython-39-x86_64-linux-gnu.so', '.abi3.so', '.so']

输出告诉我,此解释器将只查找要加载的sysv_ipc.cpython-39-x86_64-linux-gnu.sosysv_ipc.abi3.sosysv_ipc.so文件名。

给定的Python版本支持扩展模块可能想要使用的特定导出的C函数,ABI告诉您编译它的版本。使用短abi3.so后缀的扩展是根据稳定的ABI编译的,ABI是Python功能的一个子集,保证存在于许多Python版本中。

虽然可以重命名扩展文件以仅使用最短后缀([module_name].so(,但如果它仍能在不同的Python版本上工作,这在很大程度上取决于动态加载的机器代码调用的Python功能。

这里有一个快速演示,显示您可以从任意目录导入sysv_ipc动态库,前提是我使用正确的Python版本:

$ virtualenv /demo
... creating a virtualenv ...
done.
$ cd /demo
demo/ $ source bin/activate
(demo) /demo/ $ pip install sysv_ipc
Collecting sysv_ipc
... installing ...
Successfully installed sysv-ipc-1.1.0
(demo) /demo/ $ mkdir newdir
(demo) /demo/ $ cp lib/python3.9/site-packages/sysv_ipc.cpython-39-x86_64-linux-gnu.so newdir
(demo) /demo/ $ pip uninstall -y sysv_ipc
Found existing installation: sysv-ipc 1.1.0
... uninstalling ...
Successfully uninstalled sysv-ipc-1.1.0
(demo) /demo/ $ cd newdir/
(demo) /demo/newdir/ $ python
Python 3.9.2 (default, Mar 15 2021, 17:53:50)
[Clang 7.0.1 (tags/RELEASE_701/final)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sysv_ipc
>>> sysv_ipc.__file__
'/demo/newdir/sysv_ipc.cpython-39-x86_64-linux-gnu.so'

最新更新