PySide6로 데스크톱 앱 만들기 #7 패키징과 배포 — PyInstaller로 실행 파일 만들기
앱이 완성되어도 python main.py로 실행하는 동안은 개발자의 물건입니다. 다른 사람에게 전달하려면 마지막 관문이 남아 있습니다. 받는 쪽 컴퓨터에는 파이썬도, PySide6도 설치되어 있지 않다는 사실입니다. 이번 글은 인터프리터와 라이브러리까지 통째로 묶어 더블클릭으로 실행되는 배포판을 만드는 과정을 다룹니다. 시리즈의 마지막 편입니다.
총 7편으로 구성됩니다.
- #1 PySide6란 — Qt와 파이썬으로 데스크톱 앱
- #2 위젯과 레이아웃 — 화면을 조립하는 법
- #3 시그널과 슬롯 — 이벤트 처리의 핵심
- #4 Qt Designer와 UI 파일 — 화면을 그려서 불러오기
- #5 모델과 뷰 — 리스트·테이블에 데이터 연결
- #6 스레드와 타이머 — 멈추지 않는 UI
- #7 패키징과 배포 — PyInstaller로 실행 파일 만들기 ← 이번 글
무엇을 묶어야 하는가 #
배포판에는 세 층이 함께 들어가야 합니다. 내가 쓴 코드, PySide6 와 Qt 라이브러리, 그리고 파이썬 인터프리터 자체입니다. 이 세 층을 하나의 실행 파일(또는 폴더)로 묶어 주는 도구가 PyInstaller입니다. 가장 널리 쓰이고 자료가 많아 첫 배포 도구로 알맞습니다.
uv add --dev pyinstaller배포 도구는 앱 실행에 필요한 의존성이 아니므로 --dev로 개발 의존성에 넣습니다.
첫 빌드 — onedir 기본 #
프로젝트 루트에서 한 줄로 시작합니다.
pyinstaller --windowed --name TodoApp main.py--windowed— 실행 시 검은 콘솔 창을 띄우지 않습니다. GUI 앱은 필수 옵션입니다.--name— 산출물의 이름을 지정합니다.
빌드가 끝나면 dist/TodoApp/ 폴더가 생기고, 그 안에 실행 파일과 라이브러리 파일들이 함께 들어 있습니다. 이 폴더 전체가 배포 단위이고, 폴더째 압축해 전달하면 받는 쪽은 압축을 풀고 실행 파일을 더블클릭하면 됩니다. 이것이 기본값인 onedir 방식입니다.
파일 하나로 만들고 싶다면 --onefile을 붙입니다. 두 방식의 차이는 배포 편의와 시작 속도의 교환입니다.
| 구분 | onedir (기본) | onefile |
|---|---|---|
| 산출물 | 폴더 하나 (파일 다수) | 실행 파일 하나 |
| 시작 속도 | 빠름 | 느림 (실행 때마다 임시 폴더에 압축 해제) |
| 전달 편의 | 압축해서 전달 | 파일 하나라 간단 |
| 문제 진단 | 쉬움 (구성이 눈에 보임) | 어려움 |
전달이 간단하다는 이유로 onefile을 고르는 경우가 많지만, 실행할 때마다 전체를 임시 폴더에 풀기 때문에 Qt 앱처럼 라이브러리가 큰 경우 시작이 눈에 띄게 느려집니다. 설치 프로그램이나 압축 파일로 전달할 수 있다면 onedir이 무난한 기본값입니다.
데이터 파일 포함 — .spec과 –add-data #
PyInstaller는 파이썬 코드의 import를 따라가며 묶을 대상을 수집합니다. 그래서 코드가 아닌 파일, 예를 들어 #4에서 만든 .ui 파일이나 아이콘 이미지는 자동으로 들어가지 않습니다. --add-data로 직접 지정합니다.
# macOS / Linux
pyinstaller --windowed --name TodoApp --add-data "ui/main.ui:ui" main.py
# Windows
pyinstaller --windowed --name TodoApp --add-data "ui/main.ui;ui" main.py구분자 왼쪽이 원본 경로, 오른쪽이 배포판 안에서의 폴더입니다. 옵션이 늘어나기 시작하면 매번 명령줄에 붙이는 대신 첫 빌드 때 생성된 TodoApp.spec 파일을 편집하는 편이 관리하기 좋습니다. spec은 빌드 설정을 담은 파이썬 파일이고, 이후에는 pyinstaller TodoApp.spec으로 같은 설정을 재현할 수 있습니다.
sys._MEIPASS에 담기므로, “개발 중에는 소스 폴더, 배포판에서는 sys._MEIPASS“를 기준으로 경로를 계산하는 헬퍼 함수를 하나 두는 것이 정석입니다.플랫폼별 주의점 #
PyInstaller는 크로스 컴파일을 지원하지 않습니다. Windows 배포판은 Windows에서, macOS 배포판은 macOS에서 각각 빌드해야 합니다. CI를 쓴다면 운영체제별 러너에서 병렬로 빌드하는 구성이 일반적입니다.
- Windows —
--windowed를 빠뜨리면 앱 뒤에 콘솔 창이 함께 뜹니다. 아이콘은--icon app.ico로 지정하며.ico형식이어야 합니다. - macOS —
--windowed를 주면dist/에.app번들이 생성됩니다. 다른 사람의 컴퓨터에서 경고 없이 실행되려면 Apple Developer 인증서로 서명(codesign)하고 공증(notarization)을 받아야 합니다. 서명 없는 앱은 Gatekeeper 가 실행을 막고 우회 절차를 요구합니다. 개인 배포 단계에서는 이 사실을 안내문으로 알리는 것으로 시작해도 됩니다. - Linux — 빌드한 배포판과 같은 계열, 비슷한 버전의 배포판에서 잘 동작합니다. 넓은 호환성이 필요하면 오래된 배포판에서 빌드하는 관행이 있습니다.
배포 크기는 미리 감각을 잡아 두는 편이 좋습니다. Qt 라이브러리가 함께 들어가므로 간단한 앱도 배포판이 수십 MB 수준이 됩니다. 이것은 PySide6 배포의 정상 범위이고, 사용하지 않는 Qt 모듈을 제외하는 튜닝으로 일부 줄일 수 있습니다.
안티바이러스 오탐 #
Windows에서 PyInstaller 산출물이 백신에 오탐되는 일이 종종 있습니다. 실행 파일이 자기 자신을 풀어서 실행하는 구조가 일부 악성코드와 닮았기 때문입니다. 근본 대응은 코드 서명 인증서로 실행 파일에 서명하는 것이고, 서명이 어려운 단계라면 onefile 대신 onedir을 쓰는 것만으로 오탐이 줄어드는 경우가 많습니다. 배포 전에 자신의 산출물을 백신으로 한 번 검사해 보고 안내문을 준비해 두면 문의 대응이 수월해집니다.
배포 전 점검 체크리스트 #
빌드가 성공했다는 것과 남의 컴퓨터에서 실행된다는 것은 다른 문제입니다. 개발 머신에는 파이썬과 각종 라이브러리가 이미 깔려 있어서, 배포판에 빠진 파일이 있어도 증상이 드러나지 않는 경우가 있기 때문입니다. 전달 전에 최소한 다음을 확인합니다.
- 깨끗한 환경에서 실행 테스트 — 파이썬이 설치되지 않은 가상 머신이나 다른 컴퓨터에서 배포판을 실행해 봅니다. 이 한 번의 테스트가 배포 사고의 대부분을 걸러 줍니다.
- 데이터 파일 확인 — .ui 파일, 아이콘, 설정 템플릿이 배포판 안에 실제로 들어갔는지
dist/폴더에서 눈으로 확인합니다. - 콘솔 빌드로 에러 확인 — 배포판이 이유 없이 꺼질 때는
--windowed를 잠시 빼고 빌드하면 콘솔에 에러가 출력되어 원인을 찾기 쉽습니다. - 버전 표기 — 창 제목이나 정보 대화상자에 버전을 표기해 두면, 사용자 문의가 왔을 때 어느 빌드인지 바로 특정할 수 있습니다.
공식 대안 — pyside6-deploy #
PySide6에는 공식 배포 도구인 pyside6-deploy도 포함되어 있습니다. 내부적으로 파이썬 코드를 C로 변환해 컴파일하는 Nuitka를 사용하며, 설정 파일(pysidedeploy.spec) 기반으로 동작합니다. 시작 속도와 난독화 측면에서 장점이 있지만 빌드 시간이 길고 문제 진단 자료가 PyInstaller만큼 많지 않습니다. PyInstaller로 배포 흐름을 먼저 익힌 뒤, 필요가 생기면 검토할 대안으로 기억해 두면 됩니다.
시리즈 전체 요약 #
일곱 편의 핵심을 한 줄씩 정리합니다.
- #1 PySide6 는 Qt 의 공식 파이썬 바인딩이고, LGPL 라이선스라 상용 앱까지 만들 수 있습니다.
- #2 화면은 위젯을 레이아웃에 담아 조립하며, 좌표 대신 레이아웃이 배치를 계산합니다.
- #3 위젯의 사건은 시그널로 발신되고, 시그널을 슬롯에 연결하는 것이 이벤트 처리의 전부입니다.
- #4 Qt Designer 로 화면을 그리고 .ui 파일을 불러오면 화면 구성과 로직이 분리됩니다.
- #5 데이터가 많아지면 위젯에 직접 담지 않고 모델과 뷰로 분리합니다.
- #6 무거운 작업은 Worker 스레드로 옮기고 시그널로 결과를 받아, UI 를 멈추지 않게 만듭니다.
- #7 PyInstaller 로 인터프리터까지 묶으면 파이썬이 없는 컴퓨터에서도 실행됩니다.
마무리 #
여기까지 따라왔다면 창을 띄우고, 화면을 조립하고, 이벤트를 처리하고, 데이터를 연결하고, 멈추지 않는 UI 를 만들고, 배포판까지 만드는 한 사이클을 완주한 것입니다. 다음 단계로는 선언형 UI 인 QML 과 Qt Quick, 모델/뷰의 심화(정렬·필터 프록시 모델), 국제화(Qt Linguist) 같은 주제가 이어집니다. 필요해지는 시점에 공식 문서의 해당 장을 찾아 읽을 수 있는 기초는 이미 갖춰졌습니다.
이상으로 PySide6로 데스크톱 앱 만들기 시리즈를 마칩니다.