增加exe打包配置

This commit is contained in:
lasean.zhou
2026-04-15 13:08:12 +08:00
parent 150250817b
commit 9369563942
+89
View File
@@ -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()