python으로 작성된 프로그램을 Package 단위로 배포의 편의성을 위해서 사용하는 것 같다.
아래의 사이트에서 글을 읽어보면 목적을 호환성으로 두고있다.
Python은 C Library로 사용이 가능하고, Python 의 내부 Library 가능하기때문에 Python으로만 개발을 진행을 했을 때, 이것을 다른곳에 배포할때 쉽지 않다.
이를 해결해주는 것이 아래의 Tool 이고 실행파일을 만들어준다.
https://www.pyinstaller.org/
1.1 설치방법
$ pip install pyinstaller
$ pip list | grep PyInstaller
PyInstaller (3.4)
$ pyinstaller --help
or
$ ~/.local/bin/pyinstaller --help
usage: pyinstaller [-h] [-v] [-D] [-F] [--specpath DIR] [-n NAME]
[--add-data ]
[--add-binary ] [-p DIR]
[--hidden-import MODULENAME]
[--additional-hooks-dir HOOKSPATH]
[--runtime-hook RUNTIME_HOOKS] [--exclude-module EXCLUDES]
[--key KEY] [-d [{all,imports,bootloader,noarchive}]] [-s]
[--noupx] [-c] [-w]
[-i ]
[--version-file FILE] [-m ] [-r RESOURCE]
[--uac-admin] [--uac-uiaccess] [--win-private-assemblies]
[--win-no-prefer-redirects]
[--osx-bundle-identifier BUNDLE_IDENTIFIER]
[--runtime-tmpdir PATH] [--bootloader-ignore-signals]
[--distpath DIR] [--workpath WORKPATH] [-y]
[--upx-dir UPX_DIR] [-a] [--clean] [--log-level LEVEL]
scriptname [scriptname ...]
$ pyinstaller --noconfirm --log-level=WARN \
--onefile --nowindow \
--add-data="README:." \
--add-data="image1.png:img" \
--add-binary="libfoo.so:lib" \ //library 를 추가시 세부 옵션은 아래의 사이트에서 확인 , 사용시, *.spec파일도 변경
--hidden-import=secret1 \
--hidden-import=secret2 \
--upx-dir=/usr/local/share/ \
myscript.spec
설치방법
https://pypi.org/project/PyInstaller/
사용방법- 자세히 읽어보자
https://pyinstaller.readthedocs.io/en/stable/usage.html
간단하게 실행가능한 python을 작성해보고, 이와 관련된 부분들을 Package를 만드는 작업을 해보자.
- TEST python 작성
$ pip install procfs
$ vi test.py
import io
from procfs import Proc
def JHLEE():
print "Jeonghun LEE"
if __name__ == "__main__":
JHLEE()
proc = Proc()
print proc.loadavg
$ python test.py
Jeonghun LEE
{'average': {1: 0.08, 5: 0.09, 15: 0.07},
'entities': {'current': 1, 'total': 423},
'last_pid': 3833}
- Package 테스트
$ pyinstaller test.py or $ ~/.local/bin/pyinstaller test.py // 실행할 python 64 INFO: PyInstaller: 3.4 65 INFO: Python: 2.7.12 65 INFO: Platform: Linux-4.4.38-tegra-aarch64-with-Ubuntu-16.04-xenial 66 INFO: wrote /home/nvidia/jhlee/pyinstall/test.spec 90 INFO: UPX is not available. 94 INFO: Extending PYTHONPATH with paths ['/home/nvidia/jhlee/pyinstall', '/home/nvidia/jhlee/pyinstall'] 94 INFO: checking Analysis 106 INFO: checking PYZ 112 INFO: checking PKG 113 INFO: Bootloader /home/nvidia/.local/lib/python2.7/site-packages/PyInstaller/bootloader/Linux-64bit-aarch/run 113 INFO: checking EXE 114 INFO: checking COLLECT WARNING: The output directory "/home/nvidia/jhlee/pyinstall/dist/test" and ALL ITS CONTENTS will be REMOVED! Continue? (y/n)y 5285 INFO: Removing dir /home/nvidia/jhlee/pyinstall/dist/test 5312 INFO: Building COLLECT COLLECT-00.toc 5357 INFO: Building COLLECT COLLECT-00.toc completed successfully. $ cat test.spec //pyinstaller 상위 실행으로 생성 # -*- mode: python -*- block_cipher = None a = Analysis(['test.py'], pathex=['/home/nvidia/jhlee/pyinstall'], binaries=[], //binaries=[('foo.so', 'lib')], 직접 추가해도 됨 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, [], exclude_binaries=True, name='test', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=True ) coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, name='test')
- 생성된 Package 부분 확인 및 실행
$ ls dist/test/ bz2.aarch64-linux-gnu.so _codecs_tw.aarch64-linux-gnu.so libtinfo.so.5 _codecs_cn.aarch64-linux-gnu.so _hashlib.aarch64-linux-gnu.so libz.so.1 _codecs_hk.aarch64-linux-gnu.so libbz2.so.1.0 _multibytecodec.aarch64-linux-gnu.so _codecs_iso2022.aarch64-linux-gnu.so libcrypto.so.1.0.0 readline.aarch64-linux-gnu.so _codecs_jp.aarch64-linux-gnu.so libpython2.7.so.1.0 resource.aarch64-linux-gnu.so _codecs_kr.aarch64-linux-gnu.so libreadline.so.6 test $ dist/test/test //ELF 실행 완료 Jeonghun LEE '1.10 1.06 1.03 1/554 11741\n'
- spec 파일로 Package 생성
$ pyinstaller test.py or $ ~/.local/bin/pyinstaller test.spec 64 INFO: PyInstaller: 3.4 65 INFO: Python: 2.7.12 65 INFO: Platform: Linux-4.4.38-tegra-aarch64-with-Ubuntu-16.04-xenial 88 INFO: UPX is not available. 93 INFO: Extending PYTHONPATH with paths ['/home/nvidia/jhlee/pyinstall', '/home/nvidia/jhlee/pyinstall'] 93 INFO: checking Analysis 100 INFO: Building because inputs changed 101 INFO: Initializing module dependency graph... 105 INFO: Initializing module graph hooks... 265 INFO: running Analysis Analysis-00.toc 369 INFO: Caching module hooks... 403 INFO: Analyzing test.py 3816 INFO: Loading module hooks... 3818 INFO: Loading module hook "hook-encodings.py"... 5360 INFO: Looking for ctypes DLLs 5360 INFO: Analyzing run-time hooks ... 5371 INFO: Looking for dynamic libraries 6439 INFO: Looking for eggs 6440 INFO: Python library not in binary dependencies. Doing additional searching... 6724 INFO: Using Python library /usr/lib/aarch64-linux-gnu/libpython2.7.so.1.0 6741 INFO: Warnings written to /home/nvidia/jhlee/pyinstall/build/test/warn-test.txt 6799 INFO: Graph cross-reference written to /home/nvidia/jhlee/pyinstall/build/test/xref-test.html 6908 INFO: checking PYZ 6918 INFO: checking PKG 6919 INFO: Bootloader /home/nvidia/.local/lib/python2.7/site-packages/PyInstaller/bootloader/Linux-64bit-aarch/run 6919 INFO: checking EXE 6921 INFO: checking COLLECT WARNING: The output directory "/home/nvidia/jhlee/pyinstall/dist/test" and ALL ITS CONTENTS will be REMOVED! Continue? (y/n)y 12143 INFO: Removing dir /home/nvidia/jhlee/pyinstall/dist/test 12167 INFO: Building COLLECT COLLECT-00.toc 12214 INFO: Building COLLECT COLLECT-00.toc completed successfully.
1.3 Spec 파일 수정 및 옵션
상위에서 처럼 실행하면 spec파일은 자동으로 생성이 되며, 사용되는 옵션에따라 spec파일도 변경이 된다.
제대로 생성이 안되거나 동작이 안되면, WARNING 과 build/warn-xxxx 파일을 파악하여 분석하여 상위 옵션을 변경하거나, spec을 직접 수정하자.
PYTHONPATH (-p)
pyinstaller setup.spec
https://pythonhosted.org/PyInstaller/spec-files.html
2. pyinstaller 사용후 결론
회사동료가 추천을 해주어 Python Project를 이 프로그램을 이용하여 쉽게 Package를 만들고, 이것이 ELF 포맷으로 동작되는 것을 보고,
Python의 Package가 완전 Compile되어 동작되는 줄 잠시 착각했다.
하지만 동작방식을 세부적으로 분석을 해 보면, Python을 Compile되는 방식이 아니라 ELF 포맷으로 맞춰주고 안에 구성을 Python library을 넣어
나머지 의 기본틀로 동작시켜 구동하는 구조이다.
(확인 방법은 간단하며, ELF Format을 간단히 분석을 해보면 된다 ldd 와 readelf )
결론적으로 Python의 성능상의 개선은 있겠지만, 다만 관련 Library를 한곳에 넣어 배포의 편이성 및 호환성에 맞추어 야 할 것 같다.
나중에는 완전히 Library 형태로 Python의 종속을 벗어난 형태로 ELF 포맷으로 변경이 될지도 모르니
그때 다시 한번테스트를 한번해봐야 할 것 같다.
하지만 동작방식을 세부적으로 분석을 해 보면, Python을 Compile되는 방식이 아니라 ELF 포맷으로 맞춰주고 안에 구성을 Python library을 넣어
나머지 의 기본틀로 동작시켜 구동하는 구조이다.
(확인 방법은 간단하며, ELF Format을 간단히 분석을 해보면 된다 ldd 와 readelf )
결론적으로 Python의 성능상의 개선은 있겠지만, 다만 관련 Library를 한곳에 넣어 배포의 편이성 및 호환성에 맞추어 야 할 것 같다.
나중에는 완전히 Library 형태로 Python의 종속을 벗어난 형태로 ELF 포맷으로 변경이 될지도 모르니
그때 다시 한번테스트를 한번해봐야 할 것 같다.