增加exe打包配置
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
"""
|
||||
PyInstaller 运行时钩子:固定 MSVC 运行库加载顺序,再注册 DLL 搜索路径。
|
||||
|
||||
打包阶段在 strip 掉各 wheel 自带 CRT 后,会 **仅嵌入** 构建所用 Python ``DLLs``
|
||||
下的 ``vcruntime140.dll`` / ``vcruntime140_1.dll`` / ``msvcp140.dll`` 至 ``_MEIPASS``。
|
||||
本钩子在导入 chroma/torch 等扩展 **之前**,用 ``ctypes.WinDLL(绝对路径)`` 从 **同一目录**
|
||||
(优先 exe 旁若用户自行放置了完整三件套,否则 ``_MEIPASS``)预加载,避免进程落到
|
||||
目标机 ``System32`` 里较旧版本(如 14.29)再与 native 扩展不兼容触发 ``0xc0000005``。
|
||||
|
||||
随后再 ``add_dll_directory`` exe 目录与 ``_MEIPASS``,并调整 ``PATH``。不使用 ``SetDllDirectoryW``。
|
||||
"""
|
||||
|
||||
|
||||
def _preload_msvc_crt_once():
|
||||
"""若 exe 目录或 ``_MEIPASS`` 下存在 ``msvcp140.dll``,则按依赖顺序预加载该目录内 CRT。"""
|
||||
import ctypes
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
if sys.platform != "win32" or not getattr(sys, "frozen", False):
|
||||
return
|
||||
|
||||
order = ("vcruntime140.dll", "vcruntime140_1.dll", "msvcp140.dll")
|
||||
search_dirs = []
|
||||
try:
|
||||
exe_parent = Path(sys.executable).resolve().parent
|
||||
search_dirs.append(exe_parent)
|
||||
except OSError:
|
||||
pass
|
||||
meipass = getattr(sys, "_MEIPASS", None)
|
||||
if meipass:
|
||||
search_dirs.append(Path(meipass))
|
||||
|
||||
for d in search_dirs:
|
||||
if not d.is_dir():
|
||||
continue
|
||||
if not (d / "msvcp140.dll").is_file():
|
||||
continue
|
||||
for name in order:
|
||||
p = d / name
|
||||
if p.is_file():
|
||||
try:
|
||||
ctypes.WinDLL(str(p))
|
||||
except OSError:
|
||||
pass
|
||||
return
|
||||
|
||||
|
||||
def _apply_dll_search_paths():
|
||||
"""将 exe 目录与 ``_MEIPASS`` 注册为 DLL 目录,并置于 PATH 最前(exe 目录优先)。"""
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
if not getattr(sys, "frozen", False):
|
||||
return
|
||||
|
||||
dirs = []
|
||||
try:
|
||||
exe_dir = str(Path(sys.executable).resolve().parent)
|
||||
if exe_dir:
|
||||
dirs.append(exe_dir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
meipass = getattr(sys, "_MEIPASS", None)
|
||||
if meipass:
|
||||
dirs.append(meipass)
|
||||
|
||||
for d in dirs:
|
||||
if not d:
|
||||
continue
|
||||
try:
|
||||
if hasattr(os, "add_dll_directory"):
|
||||
os.add_dll_directory(d)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
path = os.environ.get("PATH", "")
|
||||
prefix = os.pathsep.join([d for d in dirs if d])
|
||||
if not prefix:
|
||||
return
|
||||
if path.startswith(prefix):
|
||||
return
|
||||
os.environ["PATH"] = f"{prefix}{os.pathsep}{path}"
|
||||
|
||||
|
||||
_preload_msvc_crt_once()
|
||||
_apply_dll_search_paths()
|
||||
Reference in New Issue
Block a user