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 포맷으로 변경이 될지도 모르니
그때 다시 한번테스트를 한번해봐야 할 것 같다.