python-3.x Pyinstaller忽略作为依赖项一部分的DLL

tkclm6bt  于 2023-11-20  发布在  Python
关注(0)|答案(1)|浏览(139)

我正在创建一个超薄的Python项目,它 Package 了一个本地dll,这样其他Python开发人员就可以使用这个dll的功能,而不必担心C内部的问题。这个项目可以构建到一个轮子中,它可以被pip安装,并且可以在脚本中成功使用。但是,当与pyinstaller捆绑时,dll被忽略,因此捆绑的程序崩溃。
我知道有一个解决办法,就是明确告诉pyinstaller包含dll:pyinstaller --add-binary="source/path/mylib.dll:destination/path ./main.py。然而,这有点违背了这样一个 Package 器的目的,即向用户混淆dll的存在。我想知道是否有一种方法可以改进我的 Package 器的项目结构,以便pyinstaller可以自动找到dll。
这就是我的 Package 器项目的结构:

wrapper
|-- wrapper
|   |-- __init__.py
|   |-- mylib.dll
|-- pyproject.toml

字符串
pyproject.toml

[tool.poetry]
name = "wrapper"
version = "0.1.0"
description = ""
authors = []

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"


__init__.py

import ctypes
import importlib.resources as res

lib = None
with res.path("wrapper", "mylib.dll") as dll_path:
  lib = ctypes.CDLL(str(dll_path))

# now defining several python functions accessing lib


如上所述,这个项目可以通过运行poetry build成功构建到wheel,也可以通过pip install <wheel name>安装。在这两种情况下,dll都被识别并复制到正确的方向(例如site-packages/wrapper)。安装后,以下脚本成功运行:
main.py

import wrapper

# calling arbitrary functions from the wrapper module


但是,当运行pyinstaller ./main.py时,库mylib.dll被忽略,捆绑的可执行文件崩溃并出现PyInstallerImportError

**稍后添加:**运行pyinstaller --collect-binaries wrapper .\main.py实际上运行良好。这是一个对我的口味来说不算太差的解决方案。然而,作为一个库开发人员,我仍然更喜欢一个不需要用户设置非标准标志就能使用我的库的解决方案。所以我期待更好的想法。

eqqqjvef

eqqqjvef1#

Python团队引导我使用PyInstaller hooks,这正是我所需要的。有一个非常general example演示了这些钩子的许多功能。在我的情况下,我需要以以下方式更改我的项目结构:

wrapper
|-- wrapper
|   |-- __init__.py
|   |-- mylib.dll
|   |-- __pyinstaller
|       |-- __init__.py
|       |-- hook-wrapper.py
|-- pyproject.toml

字符串
新添加的文件如下所示:
__init__.py

import os

def get_hook_dirs():
    return [os.path.dirname(__file__)]


hook-wrapper.py

from PyInstaller.utils.hooks import collect_data_files
datas = collect_data_files('wrapper', excludes=['__pyinstaller'])


我还必须在pyproject.toml中添加一个额外的部分:

[tool.poetry]
name = "wrapper"
version = "0.1.0"
description = ""
authors = []

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.poetry.plugins.pyinstaller40]
hook-dirs = "wrapper.__pyinstaller:get_hook_dirs"


现在,任何使用我的 Package 器库的脚本都可以通过运行pyinstaller <script name>进行绑定。

相关问题