Python 使用ctypes/cffi解析循环共享对象依赖关系

Python 使用ctypes/cffi解析循环共享对象依赖关系,python,ctypes,circular-dependency,dlopen,python-cffi,Python,Ctypes,Circular Dependency,Dlopen,Python Cffi,我想使用cffi(如果必须的话,甚至ctypes)从Linux上的Python 3访问C ABI。该API由许多.so文件实现(我们称它们为libA.so,libB.so和libC.so),这样libA包含主要导出函数,其他lib为libA提供支持 现在,libA依赖于libB,libB依赖于libC。然而,有一个问题。有一个由libA定义的全局数组,libC希望它存在。所以libC实际上依赖于libA——一种循环依赖。尝试使用相当于dlopen的cffi或CTAG加载libA会导致libB和l

我想使用
cffi
(如果必须的话,甚至
ctypes
)从Linux上的Python 3访问C ABI。该API由许多
.so
文件实现(我们称它们为
libA.so
libB.so
libC.so
),这样
libA
包含主要导出函数,其他lib为
libA
提供支持

现在,
libA
依赖于
libB
libB
依赖于
libC
。然而,有一个问题。有一个由
libA
定义的全局数组,
libC
希望它存在。所以
libC
实际上依赖于
libA
——一种循环依赖。尝试使用相当于
dlopen
的cffi或CTAG加载
libA
会导致
libB
libC
中缺少符号,但尝试加载
libC
首先会导致缺少数组的错误(在
libA
中)

因为它是一个变量,而不是一个函数,所以RTLD_LAZY选项在这里似乎不适用

奇怪的是,
lddliba.so
没有将
libB
libC
显示为依赖项,所以我不确定这是否是问题的一部分。我认为这依赖于任何与这些库链接的程序来显式地指定它们

有没有办法绕过这个问题?一个想法是创建一个新的共享对象(比如,“all.so”),它依赖于
libA
libB
libC
,这样
dlopen(“all.so”)
可以一次性加载它所需的所有内容,但我也无法让它工作

处理这种情况的最佳策略是什么?事实上,我试图访问的ABI相当大,可能有20-30个共享对象文件。

这(如果我理解正确的话)是Nix上的一个非常正常的用例,应该可以毫无问题地运行

在处理与ctypes()相关的问题时,解决这些问题的最佳(通用)方法是:

  • 编写一个(小型)C应用程序来完成所需的工作(当然,工作正常)
  • 然后才转到ctypes(基本上这是翻译上述应用程序)
我准备了一个小的(和虚拟的)例子:

  • 定义.h:

    #pragma一次
    #包括
    #定义PRINT\u MSG\u 0()printf(“从C:[%s](%d)-[%s]\n”,\uuuu文件\uuuuuuuuuu,\uuuuu行\uuuuuuu,\uuuuuuu函数\uuuuu)
    
  • libC

    • libC.h:

      #pragma一次
      大小函数();
      
    • libC.c:

      #包括“defines.h”
      #包括“libC.h”
      #包括“libA.h”
      大小函数(){
      打印消息0();
      对于(大小i=0;i
  • libB

    • libB.h:

      #pragma一次
      大小函数b();
      
    • libB.c:

      #包括“defines.h”
      #包括“libB.h”
      #包括“libC.h”
      大小函数b(){
      打印消息0();
      返回func();
      }
      
  • libA

    • libA.h:

      #pragma一次
      #定义数组_DIM 3
      外部字符字符[ARRAY_DIM];
      大小函数();
      
    • libA.c:

      #包括“defines.h”
      #包括“libA.h”
      #包括“libB.h”
      字符数组[ARRAY_DIM]={'A','B','C'};
      大小函数(){
      打印消息0();
      返回funcB();
      }
      
  • code.py:

    #/usr/bin/env蟒蛇3
    导入系统
    从ctypes导入CDLL\
    c_尺寸
    DLL=“./libA.so”
    def main():
    lib_a=CDLL(DLL)
    func_a=lib_a.funcA
    func_a.restype=c_size\u t
    ret=func_a()
    打印({:s}返回{:d})。格式(func_a.\uu name_uu,ret))
    如果名称=“\uuuuu main\uuuuuuuu”:
    打印(“Python{:s}on{:s}\n.”格式(sys.version,sys.platform))
    main()
    
输出

[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q053327620]>ls
code.py定义.h libA.c libA.h libB.c libB.h libC.c libC.h
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q053327620]>gcc-fPIC-shared-o libC.so libC.c
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q053327620]>gcc-fPIC-shared-o libB.so libB.c-L-lC
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q053327620]>gcc-fPIC-shared-o libA.so libA.c-L-lB
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q053327620]>ls
code.py定义.h libA.c libA.h libA.so libB.c libB.h libB.so libC.c libC.h libC.h libC.so
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q053327620]>LD\u LIBRARY\u PATH=。ldd libC.so
linux vdso.so.1=>(0x00007ffdfb1f4000)
libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007f56dcf23000)
/lib64/ld-linux-x86-64.so.2(0x00007f56dd4ef000)
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q053327620]>LD\u LIBRARY\u PATH=。ldd libB.so
linux vdso.so.1=>(0x00007ffc2e7fd000)
libC.so=>。/libC.so(0x00007fdc90a9a000)
libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007fdc906d0000)
/lib64/ld-linux-x86-64.so.2(0x00007fdc90e9e000)
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q053327620]>LD\u LIBRARY\u PATH=。利巴索酒店
linux vdso.so.1=>(0x00007ffd20d53000)
libB.so=>。/libB.so(0x00007fdbee95a000)
libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007fdbee590000)
libC.so=>。/libC.so(0x00007fdbee38e000)
/lib64/ld-linux-x86-64.so.2(0x00007fdbeed5e000)
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q053327620]>nm-S libC.so | grep charArray
乌查拉雷
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q053327620]>nm-S libA.so | grep charArray
0000000000 201030000000000000000三维字符集
[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q053327620]>LD\u LIBRARY\u PATH=。python3代码.py
Python 3.5.2(默认值,2018年11月12日,13:43:14)
[GCC 5.4.0 20160609]在linux上
来自C:[libA