내가 경험한 문제는 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
uwsgi-2.0.18.tar.gz
파일을 다운로드 받는다. 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
이 .pyc
나 python bytecode
를 포함하고 있지 않을 때에 만 한정해서)
.whl
은 이미 build
된 파일이고, .tar.gz
는 따로 빌드가 필요한 파일이다. 그렇게 때문에 window
환경에서 build
된 .whl
은 linux
나 mac
에서 사용하지 못 하는 경우가 있다.
잠깐
왜 특정 환경에서 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_64
는 mac
환경 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
내용 지적은 언제나 환영입니다.