import sys, os from cx_Freeze import setup, Executable # from PySide6 import QtCore # import ssl from setuptools import find_packages from updateManager.__version__ import ( __title__, __version__, __description__, __author__, __author_email__, __license__, __install_requires__, __exe_name__, __icon_file__, __main_script__, __file_log_level__, __gui_log_level__ ) import subprocess from setuptools.command.build_ext import build_ext from setuptools.command.install import install from cx_Freeze.command.build_exe import build_exe as _build_exe import importlib.util import logging import shutil # 필요한 파일 경로 설정 base_dir = os.path.dirname(__file__) browsers_dir = os.path.join(base_dir, 'src', 'browsers') chromium_dir = os.path.join(browsers_dir, 'src', 'browsers', 'chromium-1200') extensions_dir = os.path.join(browsers_dir, 'src', 'browsers', 'extensions') updater_file = os.path.join(base_dir, 'updateManager', 'updater.exe') dll_files = [ # "LIBPQ.dll", # "MIMAPI64.dll", # "Qt63DQuickScene3D.dll", "api-ms-win-core-com-l1-1-0.dll", "api-ms-win-core-debug-l1-1-0.dll", "api-ms-win-core-errorhandling-l1-1-0.dll", "api-ms-win-core-handle-l1-1-0.dll", "api-ms-win-core-heap-l1-1-0.dll", # "api-ms-win-core-heap-l2-1-0.dll", "api-ms-win-core-interlocked-l1-1-0.dll", # "api-ms-win-core-libraryloader-l1-2-0.dll", # "api-ms-win-core-libraryloader-l1-2-1.dll", "api-ms-win-core-localization-l1-2-0.dll", # "api-ms-win-core-path-l1-1-0.dll", "api-ms-win-core-processthreads-l1-1-0.dll", "api-ms-win-core-processthreads-l1-1-1.dll", "api-ms-win-core-profile-l1-1-0.dll", # "api-ms-win-core-realtime-l1-1-1.dll", "api-ms-win-core-rtlsupport-l1-1-0.dll", "api-ms-win-core-synch-l1-1-0.dll", "api-ms-win-core-synch-l1-2-0.dll", "api-ms-win-core-sysinfo-l1-1-0.dll", # "api-ms-win-core-winrt-error-l1-1-0.dll", # "api-ms-win-core-winrt-l1-1-0.dll", # "api-ms-win-core-winrt-string-l1-1-0.dll", "api-ms-win-crt-conio-l1-1-0.dll", "api-ms-win-crt-environment-l1-1-0.dll", "api-ms-win-crt-filesystem-l1-1-0.dll", "api-ms-win-crt-multibyte-l1-1-0.dll", "api-ms-win-crt-private-l1-1-0.dll", "api-ms-win-crt-process-l1-1-0.dll", "api-ms-win-crt-time-l1-1-0.dll", "api-ms-win-crt-utility-l1-1-0.dll", # "api-ms-win-power-base-l1-1-0.dll", # "api-ms-win-power-setting-l1-1-0.dll", # "api-ms-win-shcore-scaling-l1-1-1.dll", ] # ✅ DLL 경로 설정 (Windows 10의 System32에서 가져오기) system32_path = "C:/Windows/System32/downlevel" dll_include_files = [(os.path.join(system32_path, dll), dll) for dll in dll_files] dll_include_files = [] # 충돌 가능성으로 인해 빈 리스트로 초기화 vc_runtime_files = [ ('C:/Windows/System32/vcruntime140.dll', 'vcruntime140.dll'), ('C:/Windows/System32/vcruntime140_1.dll', 'vcruntime140_1.dll'), ('C:/Windows/System32/msvcp140.dll', 'msvcp140.dll'), ('C:/Windows/System32/msvcp140_1.dll', 'msvcp140_1.dll'), ('C:/Windows/System32/msvcp140_2.dll', 'msvcp140_2.dll'), ('C:/Windows/System32/concrt140.dll', 'concrt140.dll'), ('C:/Windows/System32/vcomp140.dll', 'vcomp140.dll'), ] # DirectML 사용: Windows GPU 가속을 위해 DirectML 기반 ONNXRuntime 사용 # ✅ 기존 포함 파일 + DLL 추가 include_files = dll_include_files + vc_runtime_files + [ # 나머지 파일들 ('src/Edit_PartTimer3.ico', 'lib/src/Edit_PartTimer3.ico'), # 아이콘 파일 경로 수정 # ('win.exe.manifest', 'win.exe.manifest'), # ('libssl-3-x64.dll', 'libssl-3-x64.dll'), # ('libcrypto-3-x64.dll', 'libcrypto-3-x64.dll'), ('kiprisCategories.json', 'kiprisCategories.json'), ('src/keyword/kiprisCategories.json', 'lib/src/keyword/kiprisCategories.json'), ('src/modules/fonts', 'lib/src/modules/fonts'), # ('src/modules/fonts/Cafe24Ohsquare-v2.0.ttf', 'lib/src/fonts/Cafe24Ohsquare-v2.0.ttf'), # ('src/modules/fonts/gamtanload.ttf', 'lib/src/fonts/gamtanload.ttf'), # ('src/modules/fonts/NanumBarunGothic.ttf', 'lib/src/fonts/NanumBarunGothic.ttf'), # ('src/modules/fonts/NanumSquareRoundR.ttf', 'lib/src/fonts/NanumSquareRoundR.ttf'), # ('src/modules/fonts/HakgyoansimDunggeunmisoTTFB.ttf', 'lib/src/fonts/HakgyoansimDunggeunmisoTTFB.ttf'), # ('src/modules/fonts/Cafe24Ohsquare-v2.0.ttf', 'lib/src/modules/fonts/Cafe24Ohsquare-v2.0.ttf'), # ('src/modules/fonts/gamtanload.ttf', 'lib/src/modules/fonts/gamtanload.ttf'), # ('src/modules/fonts/NanumBarunGothic.ttf', 'lib/src/modules/fonts/NanumBarunGothic.ttf'), # ('src/modules/fonts/NanumSquareRoundR.ttf', 'lib/src/modules/fonts/NanumSquareRoundR.ttf'), # ('src/modules/fonts/HakgyoansimDunggeunmisoTTFB.ttf', 'lib/src/modules/fonts/HakgyoansimDunggeunmisoTTFB.ttf'), (updater_file, 'updater.exe'), ('퍼센티 다양한 카테고리 엑셀 수집(스스 기준).xlsx', '퍼센티 다양한 카테고리 엑셀 수집(스스 기준).xlsx'), ('src/Percenty_SS_Code.json', 'lib/src/Percenty_SS_Code.json'), ('src/browsers/chromium-1200', 'lib/src/browsers/chromium-1200'), ('src/browsers/extensions', 'lib/src/browsers/extensions'), ('C:/Windows/System32/vcomp140.dll', 'vcomp140.dll'), ] for src, dest in include_files: if not os.path.exists(src): print(f"경로가 존재하지 않습니다: {src}") # 사용된 패키지 정의 build_exe_options = { 'include_msvcr': True, # VC++ 런타임 자동 포함 'packages': [ 'ctypes', 'asyncio', 'subprocess', 'pyperclip', 'numpy', 'requests', 'PIL', 'bs4', 'PySide6', 'psutil', 'pandas', 'supabase', 'translatepy', 'markdown', 'supabase', 'gotrue', 'storage3', 'postgrest', # json 모듈 순환 import 문제 해결 'json', 'json.encoder', 'json.decoder', 'json.scanner', ], 'includes': [ 'shiboken6','playwright','comtypes.stream', 'win32com.client', 'win32com.server', 'pythoncom', 'loggerModule', 'toggleSwitch', 'browser_control', 'locatorManager', 'src.cmdDiag', 'src.inputDiag', 'src.keyword', 'src.priceSetDiag', 'src.contents', 'src.contents.option', 'src.contents.price', 'src.contents.details', 'src.contents.titleGenerator', 'src.contents.thumb', 'src.contents.tags', 'src.titleManager', 'src.titleManager.sp_ForbiddenM', 'src.titleManager.gpt_client', 'src.translator', 'src.translator.papago_translator', 'src.discord_manager', 'src.unwantedDiag', 'src.unwantedDiag.unwanted_words_dialog', 'src.logDialog', 'src.logDialog.log_dialog', 'src.logDialog.log_filter', 'src.modules.settings_manager', 'src.modules.gpu_status_checker', 'src.modules.gpu_utils', 'src.gpuDiag', 'src.modules.image_worker_client', # 이미지 워커 클라이언트만 포함 'src.img_module', 'src.img_module.image_processor_manager', 'src.img_module.image_processor_dialog', 'src.modules.fonts.fontSelectDialog', 'src.lens', 'src.lens.naver_lens_client', 'src.lens.naver_lens_parser', 'src.lens.naver_lens_adapter', 'src.lens.aliprice_lens_client', 'translatepy', 'translatepy.translators', 'translatepy.translators.google', # 썸네일 이미지 처리용 (thumb.py에서 사용) 'PIL', 'PIL.Image', 'PIL.ImageOps', 'PIL.ImageEnhance', 'PIL.ImageFilter', 'PIL.features', 'numpy', 'numpy.core', 'numpy.random', # supabase 전체 생태계 'supabase', 'gotrue', 'storage3', 'postgrest', 'supafunc', 'realtime', # pydantic 생태계 'pydantic', 'pydantic_core', # json 순환 import 문제 해결 'json', 'json.encoder', 'json.decoder', 'json.scanner', # httpx 의존성 모듈들 'httpx', 'httpx.__version__', 'httpx._models', 'httpx._client', 'httpx._config', 'curl_cffi', 'curl_cffi.requests', # pathlib 명시적 포함 (PySide6에서 필요) 'pathlib', ], 'include_files': include_files, 'excludes': [ 'tkinter', 'PyQt4', 'PyQt5', 'AppKit', 'Foundation', 'IPython', 'OpenSSL', 'curses', 'test', 'matplotlib', 'asyncpg', # importlib 관련 - metadata는 pydantic에서 필요하므로 제외하지 않음 'importlib._bootstrap', 'importlib.machinery', # 개발/테스트 도구들 제외 'pytest', 'hypothesis', 'mypy', 'coverage', 'tox', # 수학 라이브러리 (사용하지 않음) 'sympy', 'sympy.core', 'sympy.ntheory', 'sympy.external', 'sympy.polys', 'sympy.*', 'mpmath', 'gmpy2', # ImageProcessor3 관련 제외 (별도 프로젝트로 분리됨) 'paddle', 'paddleocr', 'paddlehub', 'onnxruntime', 'onnx', 'skimage', 'scikit-image', 'pyclipper', 'shapely', 'scipy', 'scipy.special', 'scipy.sparse', 'scipy.linalg', 'scipy.ndimage', 'imgaug', 'albumentations', 'torch', 'tensorflow', 'keras', # OCR 및 이미지 처리 관련 모듈 (별도 프로젝트로 분리됨) 'src.modules.image_processor3', 'src.modules.image_processor4', 'src.modules.image_worker', 'src.modules.image_worker_manager', 'src.modules.ocr_module', 'src.modules.mask_module_for_paddle', 'src.modules.text_rendering_module', 'src.modules.postImageManager', 'src.modules.request_inpaint', 'src.modules.migan_module', 'src.modules.background_removal_module', 'src.modules.bria_background_removal_module', 'src.modules.gemma_client', 'src.modules.onnx_ocr_module', ], 'zip_include_packages': [], # 아무 패키지도 압축하지 않음 (numpy 관련 문제 해결) 'optimize': 0, # 바이트 코드 최적화 비활성화 (numpy/scipy 호환성 보장) 'silent': True, # 디버그 메시지 활성화 # numpy 바이너리 파일 강제 포함 'include_msvcr': True, # VC++ 런타임 포함 } # 애플리케이션 메인 파일 및 설정 base = None if sys.platform == 'win32': base = 'Win32GUI' # ✅ 아이콘 지정: icon='파일경로.ico' executables = [ Executable( 'main.py', base=base, target_name='Edit_PartTimer3.exe', icon="Edit_PartTimer3.ico" ) ] # build_exe 클래스를 확장하여 빌드 전 의존성 체크 및 빌드 후 iss 파일 생성 class build_exe(_build_exe): def run(self): # 원래 빌드 프로세스 실행 _build_exe.run(self) # 빌드 후 불필요한 ImageProcessor3 관련 파일 정리 print("\n불필요한 ImageProcessor3 관련 파일 정리 중...\n") self._cleanup_unnecessary_files() print("\n빌드가 완료되었습니다. 이제 Inno Setup 스크립트 생성을 시작합니다...\n") try: # generate_iss.py 스크립트 실행 result = subprocess.run([sys.executable, "generate_iss.py"], capture_output=True, text=True) if result.returncode == 0: print(result.stdout) print("\nInno Setup 스크립트 생성이 완료되었습니다!") else: print(f"Inno Setup 스크립트 생성 중 오류 발생: {result.stderr}") except Exception as e: print(f"Inno Setup 스크립트 생성 중 예외 발생: {e}") def _cleanup_unnecessary_files(self): """빌드 결과물에서 ImageProcessor3 관련 불필요한 파일/디렉토리 제거""" # 빌드 디렉토리 경로 build_dir = os.path.join(os.path.dirname(__file__), "build") # 제거할 디렉토리/파일 목록 unnecessary_items = [ # 디렉토리 "lib/src/modules/briaaiModel", "lib/src/modules/migan_onnx", "lib/src/modules/modules", "lib/src/modules/ocr_backends", "lib/src/modules/onnx_ocr_module", "lib/src/modules/output", "lib/src/modules/outputs", "lib/src/modules/PP_Models", "lib/src/modules/rembg_models", "lib/src/PP_Models", # 상위 디렉토리의 PP_Models도 제거 # 대용량 패키지 (만약 포함되었다면) "lib/paddle", "lib/paddleocr", "lib/onnxruntime", "lib/skimage", "lib/scipy", # 모델 파일 "lib/src/modules/migan_traced.pt", # Python 소스 파일 "lib/src/modules/image_processor3.py", "lib/src/modules/image_processor4.py", "lib/src/modules/image_worker.py", "lib/src/modules/image_worker_manager.py", "lib/src/modules/ocr_module.py", "lib/src/modules/mask_module_for_paddle.py", "lib/src/modules/text_rendering_module.py", "lib/src/modules/postImageManager.py", "lib/src/modules/request_inpaint.py", "lib/src/modules/migan_module.py", "lib/src/modules/background_removal_module.py", "lib/src/modules/bria_background_removal_module.py", "lib/src/modules/gemma_client.py", # 컴파일된 파일 "lib/src/modules/image_processor3.pyc", "lib/src/modules/image_processor4.pyc", "lib/src/modules/image_worker.pyc", "lib/src/modules/image_worker_manager.pyc", "lib/src/modules/ocr_module.pyc", "lib/src/modules/mask_module_for_paddle.pyc", "lib/src/modules/text_rendering_module.pyc", "lib/src/modules/postImageManager.pyc", "lib/src/modules/request_inpaint.pyc", "lib/src/modules/migan_module.pyc", "lib/src/modules/background_removal_module.pyc", "lib/src/modules/bria_background_removal_module.pyc", "lib/src/modules/gemma_client.pyc", ] removed_count = 0 total_size_saved = 0 # build 디렉토리 내의 모든 exe.* 디렉토리를 찾아서 정리 if os.path.exists(build_dir): for item in os.listdir(build_dir): if item.startswith("exe."): exe_dir = os.path.join(build_dir, item) for unnecessary_item in unnecessary_items: target_path = os.path.join(exe_dir, unnecessary_item) try: if os.path.exists(target_path): # 디렉토리인 경우 if os.path.isdir(target_path): # 크기 계산 dir_size = sum( os.path.getsize(os.path.join(dirpath, filename)) for dirpath, dirnames, filenames in os.walk(target_path) for filename in filenames ) total_size_saved += dir_size shutil.rmtree(target_path) print(f" ✓ 디렉토리 삭제: {unnecessary_item} ({dir_size / (1024*1024):.1f} MB)") # 파일인 경우 else: file_size = os.path.getsize(target_path) total_size_saved += file_size os.remove(target_path) print(f" ✓ 파일 삭제: {unnecessary_item} ({file_size / (1024*1024):.2f} MB)") removed_count += 1 except Exception as e: print(f" ✗ 삭제 실패: {unnecessary_item} - {e}") if removed_count > 0: print(f"\n정리 완료: {removed_count}개 항목 삭제, 약 {total_size_saved / (1024*1024):.1f} MB 절약\n") else: print("정리할 항목이 없습니다.\n") if __name__ == '__main__': # Setup 설정 (cmdclass에 build_exe 추가) setup( name=__title__, version=__version__, description=__description__, author=__author__, author_email=__author_email__, license=__license__, packages=find_packages(), install_requires=__install_requires__, python_requires='>=3.11', include_package_data=True, zip_safe=False, options={'build_exe': build_exe_options}, executables=executables, cmdclass={ "build_exe": build_exe, }, )