我正在尝试使用pyInstaller打包一个wxpython应用程序。我正在寻找“单文件夹”模式的变体,其中dll和pyds不存储在顶级目录中,而是存储在子目录中(如“dlls”或“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。
答案 0 :(得分:2)
问题是sys.path
不包含您的子目录。因此,当程序运行时,它不知道在哪里查找.dll或.pyd文件。
当然会想到将代码sys.path.append("relative/path/to/your/subdirectories")
放在主脚本之上。但是,这个代码只会在所有内容加载到位后执行。
根据这个blog,解决方案是使用pyinstaller的运行时钩子。 运行时挂钩告诉引导代码在主脚本运行之前运行任何任意代码 - 在导入任何内容之前。
创建hooker.py
,将所有自定义路径添加到sys.path
。把它放在某处,只做一次。
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
使用spec文件:
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
文件,清单,library.zip以及一堆.dll
和.pyd
现在,您可以在步骤1中创建windll
文件夹和lib
或您添加到sys.path
的所有内容。然后将所有.pyd
个文件移至lib
以及.dll
的所有windll
个文件。
运行你的exe
它会崩溃!因此,请将以下文件移回父文件夹。
引导程序需要这些文件,因此我们无法在不修改引导程序代码的情况下移动它们。
再次运行exe
,它应该正常工作。
创建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
即可。
pause
命令使控制台窗口保持打开状态,以便您知道编译是否成功。
答案 1 :(得分:-4)
另一种方式,新的loadmyapp.c:
#include<stdlib.h>
main(int argc,char *argv[]) {
execv("yourapp/app.exe", argv);
}
gcc -o loadmyapp loadmyapp.c
./ loadmyapp