파이썬 + conda - mysqlclient 사용 시 "NameError: name '_mysql' is not defined" 에러
분명히 mysqlclient를 잘 설치했는데,
$ sudo apt-get install libmysqlclient-dev
$ conda create --name py38build python=3.8 -y
$ conda activate py38build
$ python -m pip install mysqlclient==2.0.3
MySQLdb를 import하면 다음과 같은 에러가 발생합니다.
$ python -c 'import MySQLdb;'
Traceback (most recent call last):
File "/home/testusr/miniconda3/envs/py38build/lib/python3.8/site-packages/MySQLdb/__init__.py", line 18, in <module>
from . import _mysql
ImportError: /home/testusr/miniconda3/envs/py38build/lib/libstdc++.so.6: version `GLIBCXX_3.4.32' not found (required by /lib/x86_64-linux-gnu/libmysqlclient.so.21)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/testusr/miniconda3/envs/py38build/lib/python3.8/site-packages/MySQLdb/__init__.py", line 24, in <module>
version_info, _mysql.version_info, _mysql.__file__
NameError: name '_mysql' is not defined
예전에는 해당 현상을 해결하지 못했지만, 이제는 경험이 쌓여 저 문제가 보이기 시작합니다. ^^ (게다가 진짜 문제는 그게 아니라 좀 더 위에 있는 GLIBC 버전 문제입니다.)
MySQLdb의 __init__.py 파일을 보면, 초기에 _mysql 모듈을 import 하는데요,
$ cat /home/testusr/miniconda3/envs/py38build/lib/python3.8/site-packages/MySQLdb/__init__.py
"""
MySQLdb - A DB API v2.0 compatible interface to MySQL.
This package is a wrapper around _mysql, which mostly implements the
MySQL C API.
connect() -- connects to server
See the C API specification and the MySQL documentation for more info
on other items.
For information on how MySQLdb handles type conversion, see the
MySQLdb.converters module.
"""
try:
from MySQLdb.release import version_info
from . import _mysql
# ...[생략]...
저 코드로 인해 로드가 되는 모듈은 같은 디렉터리에 있는 "_mysql.cpython-38-x86_64-linux-gnu.so" 파일입니다. 즉, 해당 so 파일이 GLIBCXX_3.4.32 버전을 요구하고 있지만,
$ ldd /home/testusr/miniconda3/envs/py38build/lib/python3.8/site-packages/MySQLdb/_mysql.cpython-38-x86_64-linux-gnu.so
/home/testusr/miniconda3/envs/py38build/lib/python3.8/site-packages/MySQLdb/_mysql.cpython-38-x86_64-linux-gnu.so: /home/testusr/miniconda3/envs/py38build/lib/libstdc++.so.6: version `GLIBCXX_3.4.32' not found (required by /lib/x86_64-linux-gnu/libmysqlclient.so.21)
linux-vdso.so.1 (0x00007ffd0a3fa000)
libmysqlclient.so.21 => /lib/x86_64-linux-gnu/libmysqlclient.so.21 (0x00007ffb2c1d2000)
libzstd.so.1 => /lib/x86_64-linux-gnu/libzstd.so.1 (0x00007ffb2c118000)
libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007ffb2c105000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ffb2c01c000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffb2be0a000)
libssl.so.3 => /home/testusr/miniconda3/envs/py38build/lib/libssl.so.3 (0x00007ffb2bd63000)
libcrypto.so.3 => /home/testusr/miniconda3/envs/py38build/lib/libcrypto.so.3 (0x00007ffb2b913000)
libz.so.1 => /home/testusr/miniconda3/envs/py38build/lib/libz.so.1 (0x00007ffb2b8f5000)
libstdc++.so.6 => /home/testusr/miniconda3/envs/py38build/lib/libstdc++.so.6 (0x00007ffb2b6e1000)
libgcc_s.so.1 => /home/testusr/miniconda3/envs/py38build/lib/libgcc_s.so.1 (0x00007ffb2b6c7000)
/lib64/ld-linux-x86-64.so.2 (0x00007ffb2c869000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ffb2b6c0000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ffb2b6bb000)
$ ls -l /home/testusr/miniconda3/envs/py38build/lib/libstdc++.so.6
lrwxrwxrwx 1 testusr testusr 19 Jun 4 13:51 /home/testusr/miniconda3/envs/py38build/lib/libstdc++.so.6 -> libstdc++.so.6.0.29
정작 그로 인해 로드되는 "libstdc++.so.6.0.29" 파일은 29 버전이기 때문에 문제가 발생하고 있는 것입니다. 따라서 이런 경우라면 conda 환경에서 제공하는 libstdc++.so.6 파일을 32 버전으로 교체해 줘야 하는데요, 전에 이야기한 것처럼 "libstdcxx-ng=13"으로 지정해 패키지를 설치해 주시면 됩니다.
$ conda install -c conda-forge libstdcxx-ng=13 -y
그럼 동일한 경로의 libstdc++.so.6 링크 파일이 교체된 32 버전으로 향하게 되고,
$ ls -l /home/testusr/miniconda3/envs/py38build/lib/libstdc++.so.6
lrwxrwxrwx 1 testusr testusr 19 Jun 4 14:28 /home/testusr/miniconda3/envs/py38build/lib/libstdc++.so.6 -> libstdc++.so.6.0.32
이후 정상적으로 MySQLdb를 import 할 수 있습니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]