0

我正在尝试使用 pyinstaller 将我的 Python 包打包成可执行文件。脚本名叫做“run-jointbuilder.py” 包有很多依赖(比如numpy),但重要的是gmsh。

使用 pyinstaller 编译我的代码时,它似乎是成功的,但是当我尝试运行可执行文件时,我收到以下错误:

import gmsh # PyInstaller PYZ\
import ctypes.util # PyInstaller PYZ\
import 'ctypes.util' # <pyimod03_importers.FrozenImporter object at 0x000001BD783FC910>\
Traceback (most recent call last):\
  File "PyInstaller\loader\pyiboot01_bootstrap.py", line 144, in __init__
  File "ctypes\__init__.py", line 381, in __init__\
FileNotFoundError: Could not find module 'C:\Users\willber\Anaconda3\Scripts\gmsh' (or one of its dependencies). Try using the full path with constructor syntax.

然后我得到这个错误:

__main__.PyInstallerImportError: Failed to load dynlib/dll

'C:\\Users\\willber\\Anaconda3\\Scripts\\gmsh'. Most probably this dynlib/dll was not found when the application was frozen.

[18612] Failed to execute script run-jointbuilder

有没有人尝试编译一些导入 gmsh 包的 Python 代码?我真的很感激一个示例 .spec 文件,如果是这样的话,可以与 pyinstaller 一起使用!

4

1 回答 1

1

gmsh python 包包装了一堆编译的库,其中包含您从 python 调用的方法的实现。当您将 gmsh.py 导入脚本时,gmsh 会在后台加载这些库,让您可以通过 python 方法访问它们的功能。因此,必须将这些库嵌入到 pyinstaller 输出中,以便您的代码能够像直接通过 python 解释器运行它时那样运行。

pyinstaller 很难始终如一地找到这些库,因为它们的访问方式与普通 python 导入不同,它们是使用 cytpes 包加载的。在 docs 中有一些关于 pyinstaller 如何执行此操作的描述。由于您在运行编译后的 python 脚本时看到 dynlib/dll 加载错误,这表明 pyinstaller 在编译期间没有找到 gmsh 库,因此它从可执行文件中丢失。

如果您查看gmsh.py 源代码,您可以看到 gmsh.py 加载了一个gmsh-4.9.dll为 Windows 操作系统调用的 .dll 库。您可以使用binariespyinstaller .spec 文件的输入将编译器指向gmsh-4.9.dll.

这是一个示例 .spec 文件,它gmsh-4.9.dll在编译时动态定位 .dll 以便为您的活动环境选择正确的 .dll。您可以通过过滤 gmsh 目录中的所有 *.dll 来使其更通用,但为了清楚起见,我已经硬编码:

# -*- mode: python ; coding: utf-8 -*-
from pathlib import Path
import gmsh

# get the location of the gmsh dll which sits next to the gmsh.py file
libname = 'gmsh-4.9.dll'
libpath = Path(gmsh.__file__).parent / libname
print('Adding {} to binaries'.format(libpath))

block_cipher = None

a = Analysis(['gmsh-test.py'],
         pathex=['C:\\Users\\user\\dev\\gmsh'],
         # tell pyinstaller to add the binary to the compiled path
         binaries=[(str(libpath), '.')],
         datas=[],
         hiddenimports=[],
         hookspath=[],
         runtime_hooks=[],
         excludes=[],
         win_no_prefer_redirects=False,
         win_private_assemblies=False,
         cipher=block_cipher,
         noarchive=False)

pyz = PYZ(a.pure, a.zipped_data,
         cipher=block_cipher)

exe = EXE(pyz,
      a.scripts,
      a.binaries,
      a.zipfiles,
      a.datas,
      name='gmsh-test',
      debug=False,
      bootloader_ignore_signals=False,
      strip=False,
      upx=True,
      console=True,
      runtime_tmpdir=None,
      )
于 2021-05-15T09:40:52.937 回答