学以致用

focus on Python , C++, and some interest in Go and R

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

将使用cx_freeze打包的python程序copy到别的机器上运行时碰到这样的错误:
jerrykwan@jerrykwan:~/Downloads/exe.linux-x86_64-2.7$ ./server_family_info
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/cx_Freeze/initscripts/Console.py", line 27, in <module>
  File "server_family_info.py", line 14, in <module>
  File "/usr/local/lib/python2.7/site-packages/tornado-2.4.1-py2.7.egg/tornado/web.py", line 59, in <module>
  File "/usr/local/lib/python2.7/email/utils.py", line 27, in <module>
  File "/usr/local/lib/python2.7/random.py", line 49, in <module>
  File "/usr/local/lib/python2.7/hashlib.py", line 136, in <module>
  File "/usr/local/lib/python2.7/hashlib.py", line 71, in __get_builtin_constructor
ImportError: No module named _md5
通过日志可以看出问题很明显,应该就是在hashlib模块中出的问题.
hashlib源码如下:

# This tuple and __get_builtin_constructor() must be modified if a new
# always available algorithm is added.
__always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')

algorithms = __always_supported

__all__ = __always_supported + ('new', 'algorithms')


def __get_builtin_constructor(name):
    try:
        if name in ('SHA1', 'sha1'):
            import _sha
            return _sha.new
        elif name in ('MD5', 'md5'):
            import _md5
            return _md5.new
        elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'):
            import _sha256
            bs = name[3:]
            if bs == '256':
                return _sha256.sha256
            elif bs == '224':
                return _sha256.sha224
        elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'):
            import _sha512
            bs = name[3:]
            if bs == '512':
                return _sha512.sha512
            elif bs == '384':
                return _sha512.sha384
    except ImportError:
        pass  # no extension module, this hash is unsupported.

    raise ValueError('unsupported hash type %s' % name)


def __get_openssl_constructor(name):
    try:
        f = getattr(_hashlib, 'openssl_' + name)
        # Allow the C module to raise ValueError.  The function will be
        # defined but the hash not actually available thanks to OpenSSL.
        f()
        # Use the C function directly (very fast)
        return f
    except (AttributeError, ValueError):
        return __get_builtin_constructor(name)


def __py_new(name, string=''):
    """new(name, string='') - Return a new hashing object using the named algorithm;
    optionally initialized with a string.
    """
    return __get_builtin_constructor(name)(string)


def __hash_new(name, string=''):
    """new(name, string='') - Return a new hashing object using the named algorithm;
    optionally initialized with a string.
    """
    try:
        return _hashlib.new(name, string)
    except ValueError:
        # If the _hashlib module (OpenSSL) doesn't support the named
        # hash, try using our builtin implementations.
        # This allows for SHA224/256 and SHA384/512 support even though
        # the OpenSSL library prior to 0.9.8 doesn't provide them.
        return __get_builtin_constructor(name)(string)


try:
    import _hashlib
    new = __hash_new
    __get_hash = __get_openssl_constructor
except ImportError:
    new = __py_new
    __get_hash = __get_builtin_constructor

for __func_name in __always_supported:
    # try them all, some may not work due to the OpenSSL
    # version not supporting that algorithm.
    try:
        globals()[__func_name] = __get_hash(__func_name)
    except ValueError:
        import logging
        logging.exception('code for hash %s was not found.', __func_name)

# Cleanup locals()
del __always_supported, __func_name, __get_hash
del __py_new, __hash_new, __get_openssl_constructor

从hashlib.py的源码很容易看出,对于hashlib提供的('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')等算法,hashlib的做法是先去检验python内置的_hashlib是否支持openssh,这点儿可以认为是python编译的时候是否加入了openssl的支持,如果已经拥有openssl的支持,则直接使用python内置的openssl提供的算法,否则使用其他第三方的算法
可以确定的是,我们使用cx_freeze进行编译的时候机器上的python是支持openssl的,但为什么编译完的程序却不具备该功能呢?
通过使用ldd查看动态库依赖关系可以看出如下信息:
jerrykwan@jerrykwan:~/Downloads/exe.linux-x86_64-2.7$ ldd server_family_info
    linux-vdso.so.1 =>  (0x00007fff5c5ff000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fe755d1f000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fe755b1b000)
    libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fe755917000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fe75561b000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe75525c000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fe755f53000)
jerrykwan@jerrykwan:~/Downloads/exe.linux-x86_64-2.7$ ldd _hashlib.so
    linux-vdso.so.1 =>  (0x00007fff042f3000)
    libssl.so.6 => not found
    libcrypto.so.6 => not found
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f2ed15fd000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2ed123e000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f2ed1a36000)
原来是 libssl.so.6libcrypto.so.6等动态库找不到的原因导致hashlib模块认为使用cx_freeze编译后的python环境不具备openssl支持,进而使用第三方md5等算法,但此时运行环境中第三方md5等模块也不具备,所以程序运行时出错
为解决这一问题可以在打包时将libssl.so.6libcrypto.so.6 copy到运行环境中,也可以调整系统的/etc/ld.so.conf以便很方便的找到libssl.so.6libcrypto.so.6



posted on 2013-04-03 16:42  Jerry.Kwan  阅读(16962)  评论(0编辑  收藏  举报