Jiwift

PyInstaller : 파이썬(Python) 배포를 위한 exe 실행 파일을 만드는 방법 본문

다른 개발/Python

PyInstaller : 파이썬(Python) 배포를 위한 exe 실행 파일을 만드는 방법

지위프트 2022. 12. 29. 03:00
반응형

 

개요

Python으로 작업한 프로그램을 배포하기 위해서는 실행 파일로 만들어야 한다. 다른 사용자에게 주는 것이 아닌 나 혼자 어디서든 사용하기 위해서도 실행 파일로 바꾸는 게 좋다. Python 배포파일을 생성하기 위한 방법은 아래 두 가지 방법이 있다.

  1. PyInstaller
  2. cx_freeze

이 글에서는 PyInstaller를 다룬다.

 

※ 읽기 전에 주의
개인적으로 기억하려고 남긴 것.
가독성이 많이 떨어진다.
더 좋은 글들이 많다.


PyInstaller

공식 사이트

"PyInstaller는 파이썬 응용 프로그램과 모든 종속성을 단일 패키지로 번들로 묶는다."
공식 사이트 내용을 번역한 것이다.

쉽게 생각해서 프로젝트 작업을 하면서 사용하는 ui, 이미지, 아이콘 등 다 같이 배포하기 쉽게 묶어준다.

Windows와 Linux 호환은 안되며, 32bit와 64bit 환경에서 각각 배포파일을 생성해야 한다.

도큐먼트
라이선스

 

PyInstaller Manual — PyInstaller 5.7.0 documentation

PyInstaller bundles a Python application and all its dependencies into a single package. The user can run the packaged app without installing a Python interpreter or any modules. PyInstaller supports Python 3.7 and newer, and correctly bundles many major P

pyinstaller.org

 

License — PyInstaller 5.7.0 documentation

License PyInstaller is distributed under a dual-licensing scheme using both the GPL 2.0 License, with an exception that allows you to use it to build commercial products - listed below - and the Apache License, version 2.0, which only applies to a certain

pyinstaller.org

설치

pip install pyinstaller

 위 명령어를 통해서 python을 이용해본 누구라도 쉽게 설치할 수 있다.

 

준비물 : 예제 코드

예제 코드

1번 테스트 프로그램은 basic_test.py 파일 하나로 이루어진 단순 덧셈 프로그램이다.

 

2번 테스트 프로그램은 UI폴더 image폴더가 있고 그 안에 각각 사진과 py파일이 들어있다.

사용방법

  1. 명령어만 입력해서 콘솔창에서 실행하는 방법 
  2. 옵션파일을 만들어서 명령어로 그 옵션을 실행하는 방법

 위 두 방법에서 원하는 것을 선택하면 된다.

 

간단한 프로그램은 명령어 방법으로도 충분한데 옵션파일을 만들어서 사용하면 관리적인 측면이 좋다.

 

※둘 다 최종적으로 명령어를 입력해서 실행하기 때문에 콘솔 위치는 python파일 혹은 spec파일이 위치한 곳으로 이동해야 한다.

명령어 방식

명령어 방식은 해당 옵션들을 기억하고 입력해주어야 한다.
옵션은 기본 명령어 축약 명령어로 두 가지 방법이 있으니 편하게 사용하면 된다.

0. 제일 기본 방법

pyinstaller basic_test.py

 제일 기본적인 방법이다. 모든 값이 default값으로 설정되며 build폴더, dist폴더, spec(옵션파일) 파일이 생성되는데 dist폴더는 최종 결과물이 들어있다.

기본적인 실행 방법 예시

1. 프로그램을 하나의 폴더로 배포하기

pyinstaller --onedir basic_test.py
pyinstaller -D basic_test.py
이 옵션은 입력을 안 해도 default로 적용된다. 결과는 위에 제일 기본 방법과 같다.

"내 컴퓨터 - 프로그램 파일"에 설치된 파일들처럼 폴더 안에 프로그램 실행에 필요한 구성 요소들이 생성된다.

 

2. 프로그램을 하나의 파일로 배포하기

pyinstaller --onefile basic_test.py
pyinstaller -F basic_test.py
이 옵션은 하나의 파일로 모두 압축하는 방법으로 포터블 프로그램이 공유되듯이 파일 하나로 생성된다.

3. 콘솔 표시하지 않기

pyinstaller --noconsole basic_test.py
pyinstaller -w basic_test.py
표준 i/o에 대 한 콘솔 창을 제공하지 않습니다. 설정하지 않으면 콘솔창 표시되는 게 기본 값이다.

GUI가 없는 프로그램이라면 콘솔창으로 입/출력하기 때문에 적용하면 안 된다. (적용해도 실행하면 에러 발생)
※ 나만 나는 것인지 아닌지 지금은 모르겠다. 콘솔 창을 제공하지 않아 cmd로 실행시켜도 에러가 발생한다.

 

반대로 GUI가 있는 프로그램은 입/출력을 대신하는 화면이 있기 때문에 콘솔 창이 필요 없다면 꼭 설정하기!
콘솔 창이 출력되면 에러와 print가 모두 출력되니 최종 배포하기 전 까지는 콘솔창을 출력하는 게 좋다.

 콘솔로만 동작하는 코드에 옵션 적용하고 에러가 나는 모습이다.

 

 

옵션을 적용하지 않은 GUI 프로그램, print문이 콘솔창에 출력되기 때문에 동작 상태를 볼 수 있다.

4. 예시

예시는 정답이 아닙니다. 이렇게도 사용하는구나 하면서 봐주세요.

pyinstaller --onefile basic_test.py
  • GUI가 없는 콘솔 프로그램인데 폴더가 아닌 하나의 파일로 배포 or 테스트하고 싶은 경우
  • GUI가 있는데 하나의 파일로 만들어서 콘솔로 만들어서 테스트하고 싶은 경우
pyinstaller --onedir basic_test.py
  • GUI가 없이 콘솔 프로그램인데 폴더로 생성해서 배포하고 싶은 경우
  • GUI가 있는데 폴더로 만들어서 테스트하고 싶은 경우
pyinstaller -w --onefile basic_test.py
  • GUI가 있으면서 하나의 파일로 배포하고 싶은 경우
pyinstaller -w --onedir basic_test.py
  • GUI가 있으면서 하나의 폴더로 배포하고 싶은 경우

5. 명령어 방법 주의

1. 프로그램 코드에 상대주소를 사용한다면 최종 배포물 폴더 안에 파일들을 이동해야 한다.
2. 처음 배포파일 만들 때 콘솔창 끄는 옵션은 주지 말고 콘솔 창을 확인하면서 에러를 잡아가는 게 좋다.
3. 가끔 뭔가 안 되는 것 같다.

SPEC(옵션파일) 방식

1. 준비

프로젝트에 icon, image, ui 폴더가 있다. 실행은 My_Program.py으로 한다. My_Program.py과 같은 자리에 My_Program.spec 파일을 만들어 아래 설정들을 넣어 준다. (복사 붙여 넣기 고고)

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

added_files = [함께 가지고 가야하는 파일들]
a = Analysis([실행하는 코드 파일],
            pathex=[실행하는 코드 파일 경로],
            binaries=[],
            datas=added_files,
            hiddenimports=[강제로 가지고가는 라이브러리],
            hookspath=[],
            runtime_hooks=[],
            excludes=[],
            win_no_prefer_redirects=False,
            win_private_assemblies=False,
            cipher=block_cipher,
            noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
            cipher=block_cipher)
exe = EXE(pyz,
        a.scripts,
        [],
        exclude_binaries=True,
        name=프로그램 이름,
        debug=True,
        bootloader_ignore_signals=False,
        strip=False,
        upx=True,
        console=False,
        uac_admin=True,
        icon=아이콘 경로)
coll = COLLECT(exe,
            a.binaries,
            a.zipfiles,
            a.datas,
            strip=False,
            upx=True,
            upx_exclude=[],
            name=dist안 폴더이름)

2.  옵션(설정 예시)

2번 테스트 프로그램을 기준으로 설정하는 법을 진행하겠습니다.

옵션 : added_files

프로그램 상대 경로에 필요한 파일들을 한 폴더에 넣기 위해서 작성. image폴더 및 아이콘을 가지고 온다.
added_files = [ ("./test.ico", '.'),
                ("./image/*", './image')]

 소괄호 안에 옮길 파일 or 폴더와 배포 폴더 안에 어디로 갈지 정해줍니다.

 

아이콘은 상위폴더에, image 폴더 속 사진들은 배포 폴더에서도 image폴더로 위치해주기 위해서 저렇게 설정합니다.


옵션 : Analysis

 

실행 코드 파일. 프로그램 실행할 때 제일 먼저 실행하는 파일을 적는다.
['My_Program.py']

옵션 : Analysis -> "pathex"

실행 파일이 있는 경로
pathex=['C:\\Users\\wlxo0\\Documents\\Python\\PyInstaller\\example\\002']

옵션 : Analysis -> "hiddenimports"

python - How to properly create a pyinstaller hook, or maybe hidden import? - Stack Overflow

 

How to properly create a pyinstaller hook, or maybe hidden import?

I have two packages (say, dataread and datainspector) that were somehow not detected by PyInstaller. Because of this, the application terminates when the running application reaches the point where...

stackoverflow.com

자동으로 배포에 포함되지 않는 라이브러리들을 작성. 지금 프로그램에서는 문제가 없어 공백으로 설정
// 만약에 필요하다면 아래 처럼 작성
hiddenimports=["PyQt5.QtMultimediaWidgets"]

옵션 : Analysis -> "datas"

위에 added_files을 작성한 내용을 사용
datas=added_files

옵션 : EXE -> "name"

프로그램 exe 실행 파일 이름과 프로세서 이름을 결정
name='My_Test_Program'

옵션 : EXE -> "debug"

콘솔창을 활성화해서 배포한다면 프로그램 실행하기 전 모습이 출력됨
debug=False

옵션 : EXE -> "console"

콘솔창 출력 여부 테스트하는 상황이라면 콘솔창도 뜨게 하는 게 좋다.
console=True

옵션 : EXE -> "uac_admin"

프로그램으로 파일을 읽고 쓴다면 관리자 권한 부여를 켜고 배포해야 한다. 그냥 설정하는 게 좋다고 생각됨
uac_admin=True

옵션  : EXE -> "icon"

배포하는 프로그램 아이콘을 설정해 준다.
icon='./test.ico'

옵션 : COLLECT -> "name"은 생성되는 폴더 이름

dist 폴더 속에 생성된 배포용 폴더 이름
name='Public_Program'

3. 최종 결과

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

added_files = [ ("./test.ico", '.'),
                ("./image/*", './image')]
a = Analysis(['My_Program.py'],
            pathex=['C:\\Users\\wlxo0\\Documents\\Python\\PyInstaller\\example\\002'],
            binaries=[],
            datas=added_files,
            hiddenimports=[],
            hookspath=[],
            runtime_hooks=[],
            excludes=[],
            win_no_prefer_redirects=False,
            win_private_assemblies=False,
            cipher=block_cipher,
            noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
            cipher=block_cipher)
exe = EXE(pyz,
        a.scripts,
        [],
        exclude_binaries=True,
        name='My_Test_Program',
        debug=False,
        bootloader_ignore_signals=False,
        strip=False,
        upx=True,
        console=True,
        uac_admin=True,
        icon='./test.ico')
coll = COLLECT(exe,
            a.binaries,
            a.zipfiles,
            a.datas,
            strip=False,
            upx=True,
            upx_exclude=[],
            name='Public_Program')

 

 

정리

  1. SPEC 파일을 잘 활용하자
  2. 안 켜지면 상대경로 파일들을 배포파일 위치로 잘 옮겨주자
  3. 한 번만에 되는 경우가 없다.
  4. 라이브러리 에러가 발생하면 스택오버플로우로 달려가자
  5. 자기가 어떤 프로그램을 만들지 생각하고 옵션을 적용하자
  6. 모르면 검색하고 댓글 달기
반응형