pyInstaller 更改 dll 和 pyd 输出位置 [英] pyInstaller changing dll and pyd output location

查看:147
本文介绍了pyInstaller 更改 dll 和 pyd 输出位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 pyInstaller 来打包 wxpython 应用程序.我正在寻找一种单文件夹"模式的变体,其中 dll 和 pyd 不存储在顶级目录中,而是存储在子目录中(如dlls"或libs").

I'm trying to use pyInstaller to package a wxpython application. I looking for a variation of the "one-folder" mode whereby the dlls and pyds are not stored in the top-level directory but in a subdirectory instead (like "dlls" or "libs").

这是当前的规范文件:

# -*- mode: python -*-
import os

a = Analysis\
(
    ["..\\job_scraper\\load_gui.py"],
    pathex        = ["C:\\Users\\Administrator\\Documents\\Projects\\python\\PyInstaller\\load_gui"],
    hiddenimports = [],
    hookspath     = None,
    runtime_hooks = None
)

a_binaries = []
for (name, path, data_type) in a.binaries:
    (non_ext, ext) = os.path.splitext(name)
    if(ext in [".pyd", ".dll"]):
        a_binaries.append((os.path.join("libs", name), path, data_type))
    else:
        a_binaries.append((name, path, data_type))

a.binaries = TOC(a_binaries)

pyz = PYZ(a.pure)

exe = EXE\
(
    pyz,
    a.scripts,
    exclude_binaries = True,
    name             = "load_gui.exe",
    debug            = False,
    strip            = None,
    upx              = True,
    console          = False
)

coll = COLLECT\
(
    exe,
    a.binaries,
    a.zipfiles,
    a.datas,
    [("control.csv", "..\\job_scraper\\control.csv", "DATA")],
    strip = None,
    upx   = True,
    name  = "load_gui"
)

这样做是为了将 dll(而不是 pyds)放入 lib 文件夹,但是它似乎是在链接后执行此操作,因此程序无法启动,因为它找不到预期的 dll.

This does to put the dlls (not the pyds) into a lib folder, however it seems to do this after linking and so the program fails to launch because it can't find the expected dlls.

推荐答案

问题在于 sys.path 不包含您的子目录.所以当程序运行时,它不知道去哪里寻找你的 .dll 或 .pyd 文件.

The problem is that the sys.path doesn't include your subdirectories. So when the program runs, it doesn't know where to look for your .dll or .pyd files.

当然会想到将代码 sys.path.append("relative/path/to/your/subdirectories") 放在主脚本之上.但同样,此代码仅在所有内容加载并就位后才执行.

Of course putting the code sys.path.append("relative/path/to/your/subdirectories") on top of your main script would come to mind. But one again, this code is only executed after everything is loaded and in place.

根据这个博客,解决方法正在使用 pyinstaller 的运行时钩子.运行时钩子告诉引导代码在主脚本运行之前运行任意代码 - 在导入任何内容之前.

According to this blog, the solution is using the runtime hook of pyinstaller. Runtime hook tells the bootstrapping code to run any of your arbitrary code before your main script runs - before importing any stuff.

创建一个 hooker.py,它将把你所有的自定义路径添加到 sys.path.把它放在某个地方,只做 1 次.

Create a hooker.py which will add all your custom paths to sys.path. Put it somewhere and do it 1 time only.

import sys
import os
sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), "lib"))    # for pyd
sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), "windll")) # for dll

2.告诉 pyinstaller 包含 hooker.py

带有规范文件:

a = Analysis\
(
    ["..\\job_scraper\\load_gui.py"],
    pathex        = ["C:\\Users\\Administrator\\Documents\\Projects\\python\\PyInstaller\\load_gui"],
    hiddenimports = [],
    hookspath     = None,
    runtime_hooks = "absolute/path/to/hooker.py"  # <----- add it here
)

或使用命令行:

pyinstaller --runtime-hook="absolute/path/to/hooker.py" the_rest_parameters

通常,它会创建dist/your_main_script_name文件夹,其中包含exe文件、manifest、library.zip和一堆.dllcode> 和 .pyd

As usually, it will create dist/your_main_script_name folder which contains the exe file, manifest, library.zip, and a bunch of .dll and .pyd

现在您可以创建一个 windll 文件夹和 lib 或您在步骤 1 中添加到 sys.path 的任何内容.然后移动所有 .pyd 文件到 lib,所有 .dll 文件到 windll.

Now you can create a windll folder and lib or anything that you add to sys.path at step 1. Then move all .pyd files to lib and all .dll files to windll.

运行你的exe,它会崩溃!所以将这些下面的文件移回父文件夹.

Run your exe and it will crash! So move back these below files to parent folder.

  • pythonXX.dll ,其中 XX 是你的 python 版本
  • VCRUNTIME140.dll
  • pywintypesXX.dll,其中 XX 是您的 python 版本,如果包含它

引导程序需要这些文件,因此我们无法在不修改引导程序代码的情况下移动它们.

These files are needed for the bootstrap so we cannot move them without modifying the bootstrap code.

再次运行exe,它应该可以正常工作了.

Run the exe again and it should work normally.

很快你就会厌倦一遍又一遍地重复以上所有内容.所以这就是我一直在做的事情.

Soon you will get bored of repeating all of the above over and over again. So here is what I have been doing.

创建compiler.bat,内容类似于:

pyinstaller --runtime-hook="absolute/path/to/hooker.py" --onedir --icon path/to/icon ^
--exclude-module=UnNeeded_module_A ^
--exclude-module=UnNeeded_module_B ^
%1

@echo off
for %%F in (%1) do set pyi_output=%%~nxF
set pyi_output=%pyi_output:~0,-3%

mkdir dist\%pyi_output%\windll
mkdir dist\%pyi_output%\lib

move dist\%pyi_output%\*.dll dist\%pyi_output%\windll
move dist\%pyi_output%\*.pyd dist\%pyi_output%\lib

move dist\%pyi_output%\windll\python36.dll dist\%pyi_output%
move dist\%pyi_output%\windll\VCRUNTIME140.dll dist\%pyi_output%
if exist dist\%pyi_output%\windll\pywintypes36.dll (
    move dist\%pyi_output%\windll\pywintypes36.dll dist\%pyi_output%
)

pause

为了不弄乱你的项目,创建一个你的代码文件夹的副本并将这个 compile.bat 放在里面.然后,只需将您的 main_script.py 拖放到 compile.bat.

To not mess up your project, create a copy of your code folder and place this compile.bat inside. Then, just drag and drop your main_script.py to compile.bat.

pause 命令使控制台窗口保持打开状态,以便您知道编译是否成功.

The pause command keeps the console windows open so that you know if the compilation is successful or not.

这篇关于pyInstaller 更改 dll 和 pyd 输出位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆