Deep dive into python packaging

L-cloud·2023년 1월 10일
0
post-thumbnail

이전 포스팅

내가 경험한 문제는 PIP를 하는 도중 실패하는 상황이었기에 PIP를 조금 더 살펴보기로 했다.
python에서 pip로 하나의 패키지을 다운 받으며 어떤 작업이 발생하는지를 살펴보자.

python -m pip install 'uwsgi==2.0.*'
Collecting uwsgi==2.0.*
  Downloading uwsgi-2.0.18.tar.gz (801 kB)
     |████████████████████████████████| 801 kB 1.1 MB/s
Building wheels for collected packages: uwsgi
  Building wheel for uwsgi (setup.py) ... done
  Created wheel for uwsgi ... uWSGI-2.0.18-cp38-cp38-macosx_10_15_x86_64.whl
  Stored in directory: /private/var/folders/jc/8_hqsz0x1tdbp05 ...
Successfully built uwsgi
Installing collected packages: uwsgi
Successfully installed uwsgi-2.0.18
  1. uwsgi-2.0.18.tar.gz 파일을 다운로드 받는다.
  2. setup.py를 통해 .whl파일을 빌드한다.

위 과정의 궁금증을 해소하기 전에 다른 모듈을 하나 더 설치해보자.

python -m pip install 'chardet==3.*'
Collecting chardet
  Downloading chardet-3.0.4-py2.py3-none-any.whl (133 kB)
     |████████████████████████████████| 133 kB 1.5 MB/s
Installing collected packages: chardet
Successfully installed chardet-3.0.4

이번 패키지인 cahrdet.tar.gz 가 아니라 .whl파일을 바로 다운로드 받는다.

이제 궁금증이 발생한다. 도대체 pip에서 다운 받은 것은 어디에 저장이 되며 .tar.gz.whl는 무엇일까?

먼저 pip에 대해 알아보자.
pip 혹은 setup.py install로 설치된 패키지는 site_packages 디렉토리 아래에 저장이 된다. 각자 site_packages의 위치를 알고 싶으면 여기를 참고해보자.

참고
저장된 모듈은 기본값으로 site-packages 디렉토리에서 찾는다. 그래서 우리가 pip install somthing을 하게 된다면,
별도의 경로 지정없이 .py 파일에서 import someting 을 할 수 있다.
setup.py는 파이썬이 어떻게 패키지 및 모듈 설치를 해야하는가를 안내해주는 파일이다.

cahrdet 패키지를 다운 받으면 site_packages 디렉토리아래 저장이 된다.

(velog) L–cloud@-MacBookPro site-packages % ls -al 
total 40
drwxr-xr-x   17 L-cloud  staff    544  1  8 22:43 .
drwxr-xr-x  213 L-cloud  staff   6816  1  8 19:24 ..
-rw-r--r--@   1 L-cloud  staff  10244  1  8 19:25 .DS_Store
-rw-rw-r--    2 L-cloud  staff    119  5 19  2021 README.txt
drwxr-xr-x    5 L-cloud  staff    160  1  8 19:22 _distutils_hack
drwxr-xr-x    8 L-cloud  staff    256  1  8 19:22 certifi
drwxr-xr-x   10 L-cloud  staff    320  1  8 19:22 certifi-2022.12.7.dist-info
drwxr-xr-x   43 L-cloud  staff   1376  1  8 22:43 chardet
...

.tar.gz.whl은 각각 source distribution, built distribution이라 할 수 있다. (.whl.pycpython bytecode를 포함하고 있지 않을 때에 만 한정해서)

.whl은 이미 build된 파일이고, .tar.gz는 따로 빌드가 필요한 파일이다. 그렇게 때문에 window환경에서 build.whllinuxmac에서 사용하지 못 하는 경우가 있다.

잠깐
왜 특정 환경에서 compile된 코드는 다른 os에서 사용하지 못 하는 것일까?
크게 cpu는 amd, intel 같은 x86기반과 arm으로 나뉘며 이들의 명령어 셋과 취급하는 데이터 크기들이 모두 다르다.
따라서 같은 코드를 컴파일 했더라도 다른 바이너리 코드들이 생성될 수 있다.

모든 조건이 같다면 .whl.tar.gz 보다 크기가 작다. 따라서 네트워크를 통해 보다 빠르게 설치가 가능하다. build 도 필요없고 크기도 더 작다면 모든 패키지들을 .whl 로 제공해주면 되지 않을까? 순수 python 코드로만 작성되어있거나 간단한 패키지들이라면 가능하다. 하지만 많은 패키지들의 경우 C/C++를 바인딩해서 사용하거나 Cython을 사용하기도 한다. C/C++,Cython 모두 gcc 같은 컴파일러로 컴파일을 해야 사용이 가능하다. 실제 내가 문제를 겪은 grpcio도 Cython을 사용하고 있다. 따라서 .whl 로 패키지를 제공하기 위해서는 OS, CPU별로 모두 C/C++,Cython 등을 컴파일한 후 바인딩 해야한다. 사용자는 자신의 환경에 맞는 .whl 버전을 다운로드 하거나 .tar.gz 를 다운 받고 환경에 맞게 build 를 해야한다. (setup.py 에서 컴파일 플래그도 지정이 가능하다.)

그럼 자신의 환경에서 알맞게 바인딩하는 코드들을 컴파일하고 패키지를 build 하면 아무 문제없는 것이 아닐까? 하지만 같은 C/C++, Cython 코드라도 특정 OS나 CPU에서 컴파일이나 실행에서 실패하는 경우가 있다. 특정 OS나 CPU에서만 사용가능한 라이브러리, 하드웨어 종속적인 코드, 바이너리 코드 등이 포함되는 경우가 그 예시이다. 드디어 Python 이 VM위에서 돌아가는데도 불구하고 환경에 따라 특정 패키지를 사용하지 못 하는 이유를 알아냈다.

번외) 파이썬 코드를 컴파일한 .pyc 란 무엇일까?
pyc파일은 py파일을 bytecode로 컴파일한 코드이다. 원본 py 파일이 없어도 실행이 가능하며 소스코드도 숨길 수 있다. 컴파일 하였기 때문에 실행 속도도 빨라진다.

마지막으로 .whl 파일 이름을 조금 자세히 살펴보자. 보통 {dist}-{version}(-{build})?-{python}-{abi}-{platform}.whl 이런 형식으로 되어있다. 예시를 통해서 살펴보자.

cryptography-2.9.2-cp35-abi3-macosx_10_9_x86_64.whl , chardet-3.0.4-py2.py3-none-any.whl 에서 주요 차이는 아래와 같다. 이들의 의미를 하나하나 살펴보자.

  • cp35 / py2.py3
  • abi3 / any
  • macosx_10_9_x86_64 /any

cp 는 Cptyhon, py 는 python을 의미한다. 즉 cryptography는 Cpython을 지원하고 Jython같은 다른 python 환경에서는 적합하지 않다. py 는 구현된 모든 python을 지원한다.

abi3 은 ABI 태그이다.

ABI란?

ABI(Application Binary Interface)는 어떻게 컴파일러가 build 를 해야하는지 정의한 규칙이다.

  • 어떻게 매개 변수를 함수로 전달 할 것인지

  • 스택에서 누가 매개 변수를 지울 것인지

  • 누가 에러를 전파할 것인지 등을 정의한다.

    예를 들어 window에서 외부 라이브러리인 시스템 콜을 사용하는 코드를 컴파일 했다고 가정해보자. window와 Linux의 ABI는 다르다. 따라서 시스템 콜에서 매개 변수를 어떻게 OS로 전달할 것인지,

어디에 외부 라이브러리가 저장 되어있는지 등이 다르다. 이러한 이유에서 window에서 컴파일된 코드는 Linux에서 동작하지 않는 경우가 생긴다.

Cpython의 경우 3.7.1, 3.7.2 처럼 .x가 동일한 버전에서는 ABI가 서로 호환가능하고, 3.8.x, 3.10.x 같은 다른 배포 버전은 독립적으로 컴파일 되어야 한다고 한다. (python 특정 버전 이상부터 지원 가능한 패키지가 있는 이유로 보인다. )

macosx_10_9_x86_64mac 환경 SDK 버전 10_9 , x86_64 아키테처에서 호환 가능하다는 의미이다. any 는 모든 환경에서 호환 가능 하다는 의미이다.


요약

왜 파이썬은 VM위에서 동작하는데 일부 파이썬 패키지는 특정 OS, CPU에서 사용이 불가능 한 것일까?

일부 패키지는 C/C++, Cython등을 바인딩하여 속도를 개선한다. 호환되는 ABI도 알 수 있다. 따라서 사용자 환경(OS, CPU)이 패키지의 ABI와 다르면 패키지를 사용 하지 못 할 가능성이 있다.


출처

https://stackoverflow.com/questions/2171177/what-is-an-application-binary-interface-abi
https://stackoverflow.com/questions/3784389/difference-between-api-and-abi
https://realpython.com/python-wheels/
https://docs.python.org/3/c-api/stable.html

내용 지적은 언제나 환영입니다.

profile
내가 배운 것 정리

0개의 댓글