Files
s-canvas/scanvas_maker.spec

138 lines
4.4 KiB
Python

# -*- mode: python ; coding: utf-8 -*-
"""S-CANVAS PyInstaller spec — onedir 배포 빌드 설정.
빌드:
pyinstaller --clean scanvas_maker.spec
결과:
dist/S-CANVAS/ ← 통째로 zip 해서 배포
S-CANVAS.exe ← 더블클릭 진입점
Design/, prompt_templates/, structure_types/
_internal/ ← Python 런타임 + 의존 라이브러리
...
런타임 데이터(DB·로그·캐시):
%LOCALAPPDATA%\\S-CANVAS\\ ← 사용자별 분리, 설치 폴더 쓰기 권한 불필요
"""
from PyInstaller.utils.hooks import collect_all, collect_submodules
from pathlib import Path
block_cipher = None
PROJECT_DIR = Path(SPECPATH).resolve()
# ────────────────────── 자산 번들링 ──────────────────────
# (소스경로, 번들 내 상대경로) — 런타임에서 sys._MEIPASS 아래에 같은 트리로 추출됨.
datas = [
(str(PROJECT_DIR / "Design"), "Design"),
(str(PROJECT_DIR / "prompt_templates"), "prompt_templates"),
(str(PROJECT_DIR / "structure_types"), "structure_types"),
]
# ────────────────────── 거대 패키지 collect_all ──────────────────────
# pyvista/vtk: PyInstaller 자동 감지 부분이 거나 → 명시적 collect_all 로 누락 방지.
# pyproj: PROJ 데이터(proj.db) 자동 누락 빈번 → collect_all 로 datas/binaries 모두 집어 옴.
binaries = []
hiddenimports = []
for pkg in [
"pyvista",
"vtkmodules",
"pyproj",
"ezdxf",
"tkintermapview",
"structlog",
"customtkinter",
"PIL",
]:
try:
_d, _b, _h = collect_all(pkg)
datas += _d
binaries += _b
hiddenimports += _h
except Exception:
pass
# google-genai 의 서브모듈은 collect_all 로 충분히 커버되지 않을 때가 있어 별도 추가
hiddenimports += collect_submodules("google.genai")
hiddenimports += [
"sqlalchemy.dialects.sqlite",
"sqlalchemy.dialects.sqlite.pysqlite",
"sqlalchemy.ext.declarative",
"scipy.spatial.transform._rotation_groups",
"scipy.special.cython_special",
"encodings.idna",
]
# ────────────────────── 분석 단계 ──────────────────────
a = Analysis(
["scanvas_maker.py"],
pathex=[str(PROJECT_DIR)],
binaries=binaries,
datas=datas,
hiddenimports=hiddenimports,
hookspath=[],
hooksconfig={},
runtime_hooks=[],
# 번들 크기 절감: 불필요한 거대 패키지 제외
excludes=[
"pytest",
"IPython",
"jupyter",
"notebook",
"tornado",
"zmq",
"matplotlib.tests",
"numpy.tests",
"scipy.tests",
"pyvista.examples", # 거대 샘플 데이터 제외
"vtkmodules.test",
],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
# ────────────────────── 실행파일 ──────────────────────
# 아이콘: 빌드 전 build.bat 가 cache/icons/scanvas_S.ico 를 생성. 없으면 None 폴백.
_icon_path = PROJECT_DIR / "cache" / "icons" / "scanvas_S.ico"
_exe_icon = str(_icon_path) if _icon_path.exists() else None
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name="S-CANVAS",
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True, # UPX 가 PATH 에 있으면 압축. 없어도 빌드 진행.
upx_exclude=[
"vcruntime140.dll",
"python311.dll",
"python312.dll",
"VCRUNTIME140.dll",
],
console=False, # GUI 앱 — 콘솔 창 안 띄움
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=_exe_icon,
)
# ────────────────────── onedir 패키지 ──────────────────────
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name="S-CANVAS",
)