파이썬

[pyinstaller] 파이썬 실행파일 만들어주는 pyinstaller 활용백서

mistive 2020. 8. 20. 15:08

해당 포스팅은 windows10 64bit / python 3.6 / IDE: pycharm / anaconda3에서 진행하였습니다.

귀여운 pyinstaller 아이콘..ㅋㅋ

pyinstaller란?

pyinstaller는 python으로 만든 프로그램을 python이 없는 환경에서 실행시켜주기 위해 실행파일로 만들어주는 프로그램입니다~

 

어떻게 설치하나?

설치 방법은 매우 간단합니다!

$ pip install pyinstaller

끝!

 

사용방법은?

사용방법은.....간단하지만 간단하지 않습니다. 하지만 하나씩 차근차근 해본다면 쉽게 만들 수 있다는 것!

제가 만든 프로젝트를 실행파일로 만들면서 겪은 여러 시행착오들을 하나씩 적어보려고 합니다.

 

일단 먼저 최초 실행

$ pyinstaller -F main.py

pyinstaller 명령어를 사용하여 본인이 만든 프로젝트의 main.py를 실행파일로 만들어주게 됩니다.

 

-F : 이 놈은 --onefile 옵션입니다. 즉, 모든 것들(리소스, 라이브러리 등등)이 실행파일 내부로 들어가기 때문에 하나의 실행파일로 내가 만든 기능을 수행할 수 있습니다. 

해당 옵션을 사용하지 않을 경우 여러가지 dll(=Dynimic Link Library)과 함께 생성되기 때문에 실행파일 크기면으로는 이득이지만, 배포하는데 문제가 생길 소지가 있어, 크지 않은 프로그램같은 경우는 단일 실행파일로 배포하는게 훨씬 깔끔합니다.

 

이렇게 명령어를 실행하면 'build' 폴더와 'dist' 폴더, 그리고 'main.spec' 파일이 생성이 됩니다.

 

만든 실행파일을 실행시켜보자!

 

자, 그럼 dist 폴더로 들어가서 main.exe 파일을 실행시켜보면?

아니 무슨 cmd창이 뜨고 바로 사라져버리는 것이 아닌가....ㅋㅋ

만약 바로 원하던 프로그램이 실행이 되면 그냥 그대로 쓰시면 됩니다.

 

하지만 조금이라도 큰 프로젝트를 만들었다면 분명 바로 실행이 될 일이 없으실 겁니다. 

 

자.....순식간에 사라진 cmd 창을 자세히 보셨으면 어떤 글씨들이 썻다가 지워지는 것을 볼 수 있으셨을 겁니다.

 

어떤 메세지가 떴나 확인을 하기 위해서는 실행파일을 cmd창에서 실행시키면 됩니다.

 

저는 git bash를 이용하여 실행시켰습니다.

$ ./main.exe

흠..... KeyError가 떳었구나.....

저의 경우는 KeyError가 떴군요...?

 

해당 에러 이외에도 모듈을 찾을 수 없는 에러라던가, 해당 파일이 존재하지 않는다던가 하는 에러들이 뜹니다.

 

문제를 해결하기 위해서는! 처음 pyinstaller를 실행했을 당시 생성된 'main.spec' 파일을 수정해야 합니다.

 

main.spec 파일을 알아보자

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

block_cipher = None


a = Analysis(['main.py'],
             pathex=['C:\\Users\\PC\\PycharmProjects\\plcMonitoring_2'],
             binaries=[],
             datas=[],
             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,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='main',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True )

※ 최초에는 pyinstaller -F main.py로 실행파일을 만들었지만, main.spec을 수정한 후에는 pyinstaller -F main.spec을 실행시켜줄 겁니다.

$ pyinstaller -F main.py
$ pyinstaller -F main.spec

 

여기서 우리가 주목해야 할 부분은 datashiddenimports 값들입니다.

 

datas : 리소스 파일의 경로를 입력하게 됩니다. 입력방법은 tuple 또는 list 형태로 들어가게 되구요.

저는 튜플 방식을 사용했고, 만약 './img/image.png' 파일을 실행파일에 포함시키고 싶다?

튜플 형식 : (src, dest)

datas = [('./img/image.png', './img')]

 

이렇게 넣어주면 됩니다.

 

여러개의 파일을 추가할 때는 

datas = [('./img/image.png', './img'),

('./img/image2.png', './img'),

('./img/image3.png', './img')

]

콤마를 이용하여 작성하면 되구요.

 

폴더 내에있는 모든 리소스를 추가하고 싶으면 

datas = [('./img/*', './img')]

*표를 사용해주면 됩니다.

 

다음으로는 hiddenimports 속성을 한 번 보겠습니다.

 

hiddenimports : 여러가지 패키지, 모듈을 연결할 때 사용합니다.

모듈을 찾지 못했다는 에러가 나왔을 경우 해당 값을 수정해주시면 됩니다.

pyinstaller의 경우 사용자 모듈을 추가해서 작성해주어야 합니다.

 

예를 들어, 내가 a.py에서 'from 공통.통신 import 시리얼통신'이라는 모듈을 못찾았다는 에러를 확인할 경우

 

hiddenimports = ['공통.통신.시리얼통신']

와 같이 작성해주시면 됩니다.

 

여러 개의 모듈을 등록할 경우

 

hiddenimports = ['공통.통신.시리얼통신',

'공통.통신.시리얼통신2'

]

콤마(,)를 이용하여 나열해주시면 되구요.

 

hiddenimports = ['공통.통신.*']

이와 같이 별표(*)를 이용하여 패키지 안의 모든 모듈들을 연결해줄 수도 있습니다.

 

어..? 그런데도 리소스가 안찾아지는데요?

이건 제가 겪은 상황입니다ㅋㅋ.

 

문제의 원인은 실행 위치.....ㅋ

 

저는 프로젝트를 만들 때 상대경로를 이용하여 리소스를 불러왔습니다.

 

하지만 실행파일을 이용하여 프로그램을 실행시키려고 하니.... 

 

리소스들의 위치가 실행파일위치 기준이 아닌 AppData/local 내부에 있는 것이었습니다.

 

문제 해결을 위해서

try:
    os.chdir(sys._MEIPASS)
    print(sys._MEIPASS)
except:
    os.chdir(os.getcwd())

main문 최초 실행 당시 위와같이 작업 경로 변경을 통해 문제를 해결해주었습니다.

 

위와 같이 해주면 실행파일에 포함된 리소스들이 잘 해결될 겁니다.

 

혹시 이렇게 해도 리소스를 못찾을 경우 댓글 남겨주세요!

 

콘솔창 안뜨게 하기

이건 정말 간단합니다.

 

main.spec 파일을 보면 console=True 되어있는데 False로 바꿔주면 됩니다.

 

프로그램 이름이랑 아이콘 생성하기

이것도 간단합니다.

 

main.spec 파일을 보면 name='main'으로 되어있을 텐데 원하시는 것으로 바꾸면 됩니다.

icon의 경우 

EXE( ... ) 내부에

icon = 'icon.ico'

를 추가해주면 됩니다.

exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='실행파일이름',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True,
          icon='아이콘.ico')

 

이상 pyinstaller를 이용하여 실행파일 만들기였습니다!