如何通过我的规范文件说服 PyInstaller 在它生成的 EXE 中包含 libvlc.dll?

问题描述 投票:0回答:4

我可以使用 PyInstaller 创建一个在我的机器上运行的 EXE。我满怀希望而不是幻想地工作,我希望 EXE 确实是独立的。但是,该 EXE 不能在其他计算机上运行。它由于缺少 libvlc.dll 而阻塞,错误消息显示这可能是由于 PyInstaller 明显无法找到它。我已经对规范文件尝试了几种方法,但都无济于事。我没有包含任何代码,因为我认为这没有密切关系。这是我的规格文件:

# -*- mode: python -*-

block_cipher = None

added_files = [
     ( "D:/Applications/Python/Rogues Gallery/images/*.*", "images"),
     ( "D:/Applications/Python/Rogues Gallery/videos/*.*", "videos"),
     ( "D:/Applications/Python/MyMediaPlayer/icons/*.*", "icons")
     ]

a = Analysis(["Rogues_Gallery.py"],
         pathex=["D:/Applications/Python/Rogues Gallery/Rogues Gallery",
                 "C:/Program Files/VideoLAN/VLC/"],
         binaries=[("C:/Program Files/VideoLAN/VLC/plugins/*", "plugins"),
                   ("C:/Program Files/VideoLAN/VLC/libvlc.dll", ".")],
         datas=added_files,
         hiddenimports=[],
         hookspath=[],
         runtime_hooks=[],
         excludes=[],
         win_no_prefer_redirects=False,
         win_private_assemblies=False,
         cipher=block_cipher)

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

exe = EXE(pyz,
      a.scripts,
      a.binaries,
      a.zipfiles,
      a.datas,
      name="Rogues_Gallery",
      debug=True,
      strip=False,
      upx=False,
      runtime_tmpdir=None,
      console=True )

在此规范文件上运行 PyInstaller 会生成包含以下行的记帐:

1677 WARNING: One binary added with two internal names.
1677 WARNING: ('libvlc.dll', 'C:\\Program Files\\VideoLAN\\VLC\\libvlc.dll', 'BINARY')
1678 WARNING: was placed previously at
1678 WARNING: ('libvlc.dylib', 'C:\\Program Files\\VideoLAN\\VLC\\libvlc.dll', 'BINARY')

顺便问一下,什么是“dylib”文件?这不是 MAC 的东西吗?它在我的 PC 上做什么?实际上,我在我的电脑上找不到“dylib”文件,除非是 PyInstaller 构建的结果;也就是说,当我运行EXE时,MEIPASS临时文件夹中有一个libvlc.dylib;还有libvlc.dll。它似乎是 PyInstaller 正在创建的东西。如果我省略 ("C:/Program Files/VideoLAN/VLC/libvlc.dll", "."),我不会收到警告,并且临时文件中不存在 libvlc.dll。奇怪的是,EXE 继续工作,因此 libvlc.dll 潜伏在某个地方。这就引出了一个问题:“EXE 是否真的是独立的,或者它是在自身之外钓鱼,以从主机获取它所缺少的东西?”也许,这就是为什么它可以在我的机器上运行,而不能在任何地方根本没有 libvlc.dll 的其他计算机上运行。

就其价值而言,这是我的 Rogues Gallery 导入:

try:
    import tkinter     as tk
    import tkinter.ttk as ttk
except ImportError:
    import tkinter as tk
    import ttk

from tkinter.filedialog import askopenfilename
from tkinter import messagebox
from tkinter.constants import *
from PIL import Image, ImageTk

import os
import sys
import pathlib
import random
from datetime import datetime
import time
import vlc
import MyMediaPlayer

“import vlc”不需要在那里,但我留下了它,因为这只是我一直运行的方式;它应该出来。 Rogues Gallery 本身不做任何 vlc 的事情。 MyMediaPlayer.py 是我的 Python 脚本。这是所有 vlc 事情发生的地方。以下是其进口:

try:
    import tkinter     as tk
    import tkinter.ttk as ttk
except ImportError:
    import tkinter as tk
    import ttk

from tkinter.filedialog import askopenfilename
from tkinter import messagebox
from tkinter.constants import *
from PIL import Image, ImageTk

import os
import sys
import vlc
import pathlib
import atexit
from threading import Thread, Event
import time
import platform

我已经尝试了我能想到的一切。我需要其他更好的思想家。

python windows dll pyinstaller libvlc
4个回答
0
投票

我不是 PyInstaller 方面的专家,并且我在明确包含的 Qt dll 上收到相同的警告。但是,我的exe在其他计算机上运行。您的代码是否将

sys._MEIPASS
添加到 libvlc.dll 的 python-vlc 搜索路径中? 一些影响:

# handle pyInstaller temp directory 
if hasattr(sys, '_MEIPASS'):
    # add to your python-vlc search path

您测试的机器是否安装了VLC?您能否给出尝试在另一台计算机上运行时看到的确切错误?


0
投票

成功!使用 PyInstaller 3.3.1(和 Python 3.6.4),我创建了一个可以在我的机器和其他机器上运行的 EXE,这可能与我的不同(不同的操作系统,没有 VLC 东西等)。最后一个问题的答案很简单,但并不容易找到。这对于我在 Python 之旅中遇到的每一个问题都是如此,从零开始到跨越我的第一个 Python 项目的终点线。解决方案是正确配置有关 VLC 的规范文件。我仍然不知道足以理解或解释,但这是工作规范文件。它不言而喻。也许专家可以解释一下,这样其他人就不必经历我所做的事情。

# -*- mode: python -*-

block_cipher = None

added_files = [
               ("D:/Applications/Python/RoguesGallery/images/*.*", "images"),
               ("D:/Applications/Python/RoguesGallery/videos/*.*", "videos"),
               ("D:/Applications/Python/MyMediaPlayer/icons/*.*", "icons")
              ]

a = Analysis(['RoguesGallery.py'],
         pathex=["C:/Program Files/VideoLAN/VLC/"],
         binaries=[("C:/Program Files/VideoLAN/VLC/plugins/*", "plugins")],
         datas=added_files,
         hiddenimports=[],
         hookspath=[],
         runtime_hooks=[],
         excludes=[],
         win_no_prefer_redirects=False,
         win_private_assemblies=False,
         cipher=block_cipher)

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

exe = EXE(pyz,
      a.scripts,
      a.binaries + [("libVLC.dll", "C:/Program Files/VideoLAN/VLC/libvlc.dll", "BINARY")],
      a.zipfiles,
      a.datas,
      name='RoguesGallery',
      debug=False,
      strip=False,
      upx=False,
      runtime_tmpdir=None,
      console=False)

我在这个项目中使用了 tkinter。我将在未来的项目中使用 PyQt5。我已经在使用它了。看这个视频。像我这样的 Emacs 和 Unix 人会很开心。 https://www.youtube.com/watch?v=ON0A1dsQOV0

如果有人想拿来试一试,我也可以提供来源。如果您想加快显示图像或“播放”文件或 GUI 内容的速度,我的小项目可能会对您有所帮助。它包括很多说教性的实验题外话,如何做这个,如何做那种事情。我的下一个项目是将这个项目从 tkinter 转换为 PyQt5。继续编码!


0
投票

我也遇到了同样的问题,你会对我为使其发挥作用所做的事情感到惊讶。

我从以下位置获取了所有文件:

C:\Program Files\VideoLAN\VLC
并将它们加载到 dist 文件夹
D:\Users\myprojects\python\musicPlayer\dist\main

原因是pyinstaller在编译时未能传输一些VLC库。

所以我就把它们全部拿走了,没有过滤。我确信我也添加了一些不必要的文件,但它有效,所以我不太关心。如果你愿意的话可以一一浏览,我刚刚全部加载了


0
投票

bloodbringer 是正确的,这可以工作,但它只适用于应用程序文件夹中有 VLC.app 的计算机(这是 Mac 信息)。

这是因为 vlc.py 本身会在应用程序文件夹中查找:https://github.com/oaubert/python-vlc/blob/master/ generated/3.0/vlc.py#L187

如果您希望 pyinstaller 应用程序能够在之前未安装 VLC.app 的计算机上运行,则需要修改 vlc.py。

这里是一个示例修改,您可以使用 vlc.py 来签入 sys._MEIPASS 文件夹(运行时 pyinstaller 的临时文件夹)。这也很容易更新以在终端和冻结的 pyinstaller 上工作,因为如果检查:

if hasattr(sys, "_MEIPASS")
,您就可以这样做。如果设置了
_MEIPASS
,则您的 python 正在从打包的 exe 运行,否则正常运行 vlc 和其他所有内容。

elif sys.platform.startswith('darwin'):
    d = sys._MEIPASS
    c = os.path.join(d, "libvlccore.dylib")
    p = os.path.join(d, "libvlc.dylib")
    print("paths exists and loaded?", c, p, os.path.exists(p), os.path.exists(c))
    if os.path.exists(p) and os.path.exists(c):
        # pre-load libvlccore VLC 2.2.8+
        ctypes.CDLL(c)
        dll = ctypes.CDLL(p)
        for p in ('modules', 'plugins'):
            p = os.path.join(d, p)
            print("newp?", p)
            if os.path.isdir(p):
                plugin_path = p
                print("pluginpath", plugin_path, os.path.exists(plugin_path))
                break

示例存储库:https://github.com/AccelQuasarDragon/BasicPyVLC/

© www.soinside.com 2019 - 2024. All rights reserved.