Python 编程 · 2013/11/30 1

Mac OS 下解决 import MySQLdb 报错的问题

使用的 dmg 包安装的 mysql ..
然后使用了
sudo easy_install MySQL-Python
安装了 Python 的安装包, 安装的时候毫无问题, 当到 python 下使用
import MySQLdb
时却抛出了如下的错误

ImportError: dlopen(/Users/xwsoul/.python-eggs/MySQL_python-1.2.4-py2.7-macosx-10.8-intel.egg-tmp/_mysql.so, 2): Library not loaded: libmysqlclient.18.dylib
Referenced from: /Users/xwsoul/.python-eggs/MySQL_python-1.2.4-py2.7-macosx-10.8-intel.egg-tmp/_mysql.so
Reason: image not found

看起来很像是有个关键的.so文件没法引用, 应该是 python 下的mysql包调用 mysql 库提供的接口的时候没有勾搭上, 网上搜了下轻松找到了解决方案
export DYLD_LIBRARY_PATH=/usr/local/mysql/lib/
重启终端, 打开python, import, 搞定

你以为这就搞定了? No

当按照上述方法设置后, 每当你使用 sudo 做切换用户的操作指令时, 终端总会提示

dyld: DYLD_ environment variables being ignored because main executable (/usr/bin/sudo) is setuid or setgid

这是 Mac 下一个已知的 Bug, 大多解决方案就是将 sudo 包装成一个 bash 函数来调用, 在调用的过程中注销该环境变量, 但是不得不说, 哥的精神洁癖还是很严重的, 如此 ugly 的解决方案, 对 sudo 命令进行 hack, 我是不能接受的, 于是只得继续找寻系统解决方案了, 最终解决方式还是要回到 Python 的 Mysql 扩展本身.
直接搜索 DYLD 看看,
dyld - the dynamic link editor(动态库编辑器)
程序接受很多环境变量的引导来找到所需的动态库, 上面提到的 DYLD_LIBRARY_PATH 就是这些环境变量其中之一.
那么现在就是上述错误中的 _mysql.so 找不到对应的动态库, 而配dyld置了环境变量后, _mysql.so 就能找到了. 那么有没有方式只改变 _mysql.so 的查找方式呢? 答案是 Yes.
首先, 我们要查看 _mysql.so 调用了哪些动态库
otool -L _mysql.so
返回结果如下:

_mysql.so:
libmysqlclient.18.dylib (compatibility version 18.0.0, current version 18.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)

而上述错误中, 恰恰是找不到 libmysqlclient.18.dylib

Library not loaded: libmysqlclient.18.dylib

由此我们引导 _mysql.so 正确的找到 libmysqlclient.18.dylib 就可以了, 通过上面的环境变量, 我们可以确定的是, libmysqlclient.18.dylib 是在 /usr/local/mysql/lib/ 下的, 因此我们要将 _mysql.so 对 libmysqlclient.18.dylib 的引用改成 /usr/local/mysql/lib/libmysqlclient.18.dylib, 使用下面的指令就可以轻松做到了:
install_name_tool -change libmysqlclient.18.dylib /usr/local/mysql/lib/libmysqlclient.18.dylib _mysql.so
再次使用
otool -L _mysql.so
返回结果如下:

_mysql.so:
/usr/local/mysql/lib/libmysqlclient.18.dylib (compatibility version 18.0.0, current version 18.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)

至此问题可以说是完满的解决了.