V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
wsds
V2EX  ›  Python

求助! Python 如何调用 C 语言.SO 动态库(并且被调用的动态库还依赖其它的动态库)

  •  
  •   wsds · 2018-05-28 11:28:51 +08:00 · 7044 次点击
    这是一个创建于 2375 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近要做 SDK 测试,SDK 是由 C 语言封装成的,函数封装在了 .so动态库中,而且该动态库还依赖其他的第三方动态库,不知道该怎么调用,求助各位大神,给个 demo

    ps: linux平台的库

    #call_c.py
    
    import ctypes
    from ctypes import *
    
    ll = ctypes.cdll.LoadLibrary
    lib = ll("./libIFaceRecSDK.so")
    

    单独调用就大概是上面这样子了,但 libIFaceRecSDK.so 这个动态库还依赖其他库,且带有头文件时,我该怎么调用啊??你们看,这个库还依赖以下的这多么的库,还有头文件!!求救!

    2pLxlT.png

    第 1 条附言  ·  2018-05-28 14:55:16 +08:00

    用了楼下老铁们推荐的cffi模块,调用的时候,还是报错,不知道咋回事

    2ps98r.png

    24 条回复    2018-05-29 13:14:36 +08:00
    mashiro233
        1
    mashiro233  
       2018-05-28 11:47:56 +08:00
    遇到这种情况,我的解决方法就是要么自己封装一个 C 模块给 py,要么 FFI。前者偏向调用复杂模块的时候,后者偏向调用简单模块。
    另外这个依赖和你没多少关系,系统或者 libffi 会帮你解决。

    给个 CFFI 参考链接。
    https://eli.thegreenplace.net/2013/03/09/python-ffi-with-ctypes-and-cffi/
    wsds
        2
    wsds  
    OP
       2018-05-28 11:57:12 +08:00
    @mashiro233
    /尴尬,不会 C 语言,现在手里就一份 SDK 内置函数文档,还有些库文件,头文件,我要做的就是用 python 调 SDK 中的这些方法;
    我看一下这个 FFI,谢谢哈
    wellsc
        3
    wellsc  
       2018-05-28 12:03:39 +08:00 via iPhone
    Cffi 了解一下
    wsds
        4
    wsds  
    OP
       2018-05-28 17:40:38 +08:00
    @mashiro233 调不通啊,报错
    qieqie
        5
    qieqie  
       2018-05-28 18:33:50 +08:00
    你只需要知道返回值和参数列表的类型,不需要头文件。
    ld-linux.so 会帮你找到依赖。

    ```
    import ctypes

    lib = ctypes.CDLL('libm.so.6')
    func = getattr(lib, 'pow')
    func.argtypes = [ctypes.c_double, ctypes.c_double]
    func.restype = ctypes.c_double

    print (func(2, 10))
    ```
    Shazoo
        6
    Shazoo  
       2018-05-28 18:51:45 +08:00
    我觉得有点像比较初级的库路径问题。可能是你的 LD_LIBRARY 设置有些问题。
    一般做这种工作的步骤大概是:
    1、先写个 C 的程序,简单调用下 SDK 功能。如果 C 程序链接、运行有问题,那就及时解决。
    2、C 程序搞定后,再弄成 python 库。

    一般来说,库都会依赖不少第三方和系统库。这部分依赖,一般做的好的 SDK 是无需关心的。只要能搜索到就可以。做的不好的 SDK,也应该可以在步骤 1 解决掉。

    参考下?
    http://oi.0w0.io/2018/01/05/Ubuntu-16-04-Python3-%E9%85%8D%E7%BD%AESQLite3-%E7%9A%84-icu-%E5%88%86%E8%AF%8D/#more
    wsds
        7
    wsds  
    OP
       2018-05-28 19:22:41 +08:00
    @qieqie 首先就是用的 ctypes 的,调用 so 报错:undefined symbol: _ZN6apache6thrift12GlobalOutputE
    然后才换的 cffi
    wsds
        8
    wsds  
    OP
       2018-05-28 19:23:06 +08:00
    @Shazoo 看报错像是路径有问题,但我代码跟 so 就在同级目录下啊,不该是路径问题啊
    wsds
        9
    wsds  
    OP
       2018-05-28 19:24:08 +08:00
    @qieqie 函数名,入参,出参,都有文档,可现在首要是调不通 so
    wevsty
        10
    wevsty  
       2018-05-28 19:34:26 +08:00
    @wsds
    undefined symbol: _ZN6apache6thrift12GlobalOutputE
    表示的是找不到_ZN6apache6thrift12GlobalOutputE 这个函数,这个函数可能是哪个 so 中引用了,但是你系统里面没有。
    google 一下这个函数大概是来自这些 so 文件
    /usr/lib64/libthriftnb.so.0.0.0
    /usr/lib/libthriftz-1.0.0-dev.so
    所以你得看你系统是否安装了 libthrift ?或者版本是否正确?
    gnaggnoyil
        11
    gnaggnoyil  
       2018-05-28 19:37:53 +08:00
    _ZN6apache6thrift12GlobalOutputE 不出意外应该是来自 Apache Thrift 的库的 symbol.LZ 你 Apache Thrift 装了没?

    @wsds 人家说的是你那个库的依赖库没配置好,你为什么要强调你的"代码怎么着怎么着"......
    lonccc
        12
    lonccc  
       2018-05-28 19:38:57 +08:00 via Android
    pybind11 了解一下
    wsds
        13
    wsds  
    OP
       2018-05-28 19:49:37 +08:00
    @wevsty lib 下有这个库 libthrift.so
    wsds
        14
    wsds  
    OP
       2018-05-28 19:50:08 +08:00
    @wevsty 不过,目录有什么要求吗?我是从别的地方拷过来的
    wevsty
        15
    wevsty  
       2018-05-28 20:11:30 +08:00
    @wsds
    Linux 默认不会搜索工作目录这样,如果 so 不是在 /usr/lib 或者 /lib 这样的地方,那么就需要你指定路径。
    可以修改 /etc/ld.so.conf 这样来加载,但是既然缺少库,用包管理安装一下不是更好么?
    wsds
        16
    wsds  
    OP
       2018-05-28 20:14:44 +08:00
    @wevsty 我试过绝对路径,也是还是提示:undefined symbol: _ZN6apache6thrift12GlobalOutputE

    ```
    from cffi import FFI

    ffi = FFI()

    # ffi.cdef()
    lib_IOTCAPIs = ffi.dlopen("/home/install/linux/x86_64/lib/libthrift.so")
    lib_IOTCAPIs = ffi.dlopen("/home/lib/cpu/libIFaceRecSDK.so")
    print('Loaded lib {0}'.format(lib))
    ```
    wevsty
        17
    wevsty  
       2018-05-28 22:01:32 +08:00
    @wsds 那只能说明这个函数可能不在这个 so 文件里,再去检查这个库有没有其他的 so 文件吧。
    qieqie
        18
    qieqie  
       2018-05-29 00:12:04 +08:00
    @wsds export LD_LIBRARY_PATH=/home/install/linux/x86_64/lib:$LD_LIBRARY_PATH
    Shazoo
        19
    Shazoo  
       2018-05-29 09:40:11 +08:00
    @wsds 都说啦~写个简单 c 程序。调试通了,再跑 python。这样就能排除库本身问题。善用 readelf 之类的工具,导出引用表看看。

    当然,如果已经通了,那就实验下 LD_LIBRARY
    wsds
        20
    wsds  
    OP
       2018-05-29 10:55:04 +08:00
    @Shazoo 加载通了,但调里边 C 的方法,提示 AttributeError: function
    AX5N
        21
    AX5N  
       2018-05-29 11:00:48 +08:00
    @wsds
    你以前尝试过调用 c 的库没,如果没有的话,建议你写个 hello world 试试。
    我大概猜到你啥问题了,不过还是建议你先自己试试。
    wsds
        22
    wsds  
    OP
       2018-05-29 11:10:21 +08:00
    @AX5N 以前用 python 调用过 C,调通了的
    wsds
        23
    wsds  
    OP
       2018-05-29 11:10:34 +08:00
    @AX5N 求告之,快被开除了
    AX5N
        24
    AX5N  
       2018-05-29 13:14:36 +08:00
    @wsds 不好意思 可能是我理解错了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5864 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 06:27 · PVG 14:27 · LAX 22:27 · JFK 01:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.