在不使用 imp.load_dynamic 的情况下将 DLL 导入 Python 3

2024-02-26

Goal

我正在尝试添加 Windows 支持Total Phase Aardvark 的 Python 接口 https://github.com/kontron/python-aardvark目前仅限 Linux。这是一个设备的包装器,其可用接口仅为 .so (Linux) 或 .dll (Windows) 闭源二进制文件。然而,它是作为一个 Python 包制作的(不确定这是否是正确的术语),而不仅仅是使用 ctypes 加载的标准 C 接口。

文件结构

在这个项目中,我们有一个 ext 文件夹,它与执行导入的脚本处于同一级别,其中包含适用于 Linux 和 Windows 的 32/64 库(由我添加):

pyaardvark.py (file doing imports)
ext
  linux32
    __init.py__ (empty)
    aardvark.so
  linux 64
    __init.py__ (empty)
    aardvark.so
  win32
    __init.py__ (empty)
    aardvark.dll
  win64
    __init.py__ (empty)
    aardvark.dll

进口问题

Linux 实现使用:

from .ext.linux32 import aardvark as api

我最初测试在 Python 2.7 中添加 Windows 导入,但无法使相对路径样式导入起作用。我唯一成功的方法如下:

import imp
import os
cur_path = os.path.dirname(__file__)
api = imp.load_dynamic('aardvark', os.path.join(cur_path, 'ext', 'win32', 'aardvark.dll'))

这看起来很难看,但在 Python 2.7 上工作得很好,并且所有 api 都可用。

我切换到 Python 3.4 进行测试,发现 imp 已被弃用。不仅如此,从 3.2 开始,imp 在 Python 3 中似乎不再有 load_dynamic 了。我无法在 Python 3.4 中找到使该 DLL 可用的方法。

Attempts

Method 1

在 Python 2.7 和 Python 3.4 中均失败

from .ext.win32 import aardvark as api

Method 2

在 Python 2.7 和 Python 3.4 中均失败

import importlib
import os
cur_path = os.path.dirname(__file__)
api = importlib.import_module('aardvark', os.path.join(cur_path, 'ext', 'win32', 'aardvark.dll'))

Method 3

在 Python 2.7 中工作,在 Python 3.4 中失败

import imp
import os
cur_path = os.path.dirname(__file__)
api = imp.load_dynamic('aardvark', os.path.join(cur_path, 'ext', 'win32', 'aardvark.dll'))

Method 4

在 Python 2.7 或 Python 3.4 中不会抛出错误,但不是我想要的

import os
cur_path = os.path.dirname(__file__)
from ctypes import cdll
api = cdll.LoadLibrary(os.path.join(cur_path, 'ext', 'win32', 'aardvark.dll'))

在 Python 2.7 中使用 (imp.load_dynamic) 导入,dir(api)给我:

['__doc__', '__file__', '__name__', '__package__', 'py_aa_async_poll', 'py_aa_close', 'py_aa_configure', 'py_aa_features', 'py_aa_find_devices', 'py_aa_find_devices_ext', 'py_aa_gpio_change', 'py_aa_gpio_direction', 'py_aa_gpio_get', 'py_aa_gpio_pullup', 'py_aa_gpio_set', 'py_aa_i2c_bitrate', 'py_aa_i2c_bus_timeout', 'py_aa_i2c_free_bus', 'py_aa_i2c_monitor_disable', 'py_aa_i2c_monitor_enable', 'py_aa_i2c_monitor_read', 'py_aa_i2c_pullup', 'py_aa_i2c_read', 'py_aa_i2c_read_ext', 'py_aa_i2c_slave_disable', 'py_aa_i2c_slave_enable', 'py_aa_i2c_slave_read', 'py_aa_i2c_slave_read_ext', 'py_aa_i2c_slave_set_response', 'py_aa_i2c_slave_write_stats', 'py_aa_i2c_slave_write_stats_ext', 'py_aa_i2c_write', 'py_aa_i2c_write_ext', 'py_aa_i2c_write_read', 'py_aa_log', 'py_aa_open', 'py_aa_open_ext', 'py_aa_port', 'py_aa_sleep_ms', 'py_aa_spi_bitrate', 'py_aa_spi_configure', 'py_aa_spi_master_ss_polarity', 'py_aa_spi_slave_disable', 'py_aa_spi_slave_enable', 'py_aa_spi_slave_read', 'py_aa_spi_slave_set_response', 'py_aa_spi_write', 'py_aa_status_string', 'py_aa_target_power', 'py_aa_unique_id', 'py_aa_version', 'py_version']

ctypes 导入dir(api)给我:

['_FuncPtr', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_func_flags_', '_func_restype_', '_handle', '_name']

我不知道接下来要尝试什么。我可以在 Python 2.7 中使用我的东西,但我真的很想提供 Python 3 兼容性。


我通过以下方式在 Python 3.6 上导入外部库取得了一些成功importlib。官方文档给出了直接导入源文件的方法:

import importlib.util
import sys

# For illustrative purposes.
import tokenize
file_path = tokenize.__file__
module_name = tokenize.__name__

spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Optional; only necessary if you want to be able to import the module
# by name later.
sys.modules[module_name] = module

(https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly)

我将此调整为:

import importlib.util

def load_dynamic(module, path):
    spec = importlib.util.spec_from_file_location(module, path)
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    return mod

然后你应该能够在 Python 3 上执行类似的操作:

load_dynamic('aardvark', os.path.join(cur_path, 'ext', 'win32', 'aardvark.dll'))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在不使用 imp.load_dynamic 的情况下将 DLL 导入 Python 3 的相关文章

随机推荐