使用 Cython 公开静态链接的 c 库符号

Use Cython for exposing statically linked c-library symbols

我有一个关于如何将本地 C 库中的代码与 Cython 一起使用的最佳实践的问题。为了避免设置 LD_LIBRARY_PATH(或在 /usr/lib 或类似目录中安装 C 库),我认为静态链接是适合我的用例的解决方案。

但是,连接已静态链接的 c 函数并非易事。我可以 cimport 另一个具有静态链接 C 代码的 cython 模块的唯一方法是用 Cython 函数指针解释所有导出的函数(参见 https://github.com/HolgerPeters/cython-example/blob/master/cython-project/c_with_ptrs.pyx and https://github.com/HolgerPeters/cython-example/blob/master/cython-project/c_with_ptrs.pxd

仅仅将 pxd 中的原始 C 函数声明为 extern 似乎不起作用。我在 Github 上有一个示范项目,它隔离了不同的方法及其用法。

https://github.com/HolgerPeters/cython-example

对此有什么想法吗?我可以告诉 Cython 显式使用 externed 声明吗?

特定的堆栈跟踪

由于这个问题一开始是一个相当开放的问题,我想让它更具体以鼓励回答。

在名为 github 的项目中,我组合了几种链接方式。我现在将重点放在文档中看起来很自然的方式上。

https://github.com/HolgerPeters/cython-example/blob/master/cython-project/c_from_with_direct_compilation.pxd

来自 "foo.h" 的 cdef 外部:
    外部整数 clib_return_3(整数)

和相应的用例 https://github.com/HolgerPeters/cython-example/blob/master/cython-project/c_from_with_direct_compilation.pyx

定义使用它():
    打印(clib_return_3(4))

调用 c_from_with_direct_compilation.useit() 有效(test.sh 输出如下)。

但是当我尝试使用另一个 cython 文件中的 clib_return_3 时,它失败了!用法是

https://github.com/HolgerPeters/cython-example/blob/master/cython-project/c_from_with_direct_compilation_user.pyx

导入 c_from

定义使用它():
    打印(c_from.clib_return_3(4))

bash test.sh 测试所有使用情况,如您所见,cython 所以 clib_return_3 符号链接到的地方确实可以使用该符号,而另一个 cython 则试图导入它符号在此失败。

======================== c_from_w/_direct_comp,接口失败(为什么?)
从静态链接 c_from_with_direct_compilation 调用,通过 c_from_with_direct_compilation_user 调用
追溯(最近一次通话):
  文件“”,第 1 行,位于
导入错误:./c_from_with_direct_compilation_user.so:未定义的符号:clib_return_3
失败
========================c_from_w/_direct_comp
从静态链接调用 c_from_with_direct_compilation
3个
成功

您可以执行以下任一操作:

  1. cdef extern from "path/header.h": 然后列出您将在 cython 中使用的函数定义。 (http://docs.cython.org/src/userguide/external_C_code.html#referencing-c-header-files)
  2. 将 C 函数声明为 extern。 (http://docs.cython.org/src/userguide/external_C_code.html#external-declarations)

(这两种方法都适用于 pyxpxd 文件)。

旁注:在您的 setup.py 中,您使用了 2 种不同的方式来包含 C 代码(使用动态库和使用目标文件)。除非你的 C make 规则真的很复杂,否则第三种选择是将 .c 文件列在与 .pyx 文件相同的数组中,让 distutils 为你构建它们。

在盯着这个问题看够久之后,我想我知道发生了什么事了:

Cython-cdef-functions 的名称经过了修饰,而 extern 函数没有经过名称修饰并保留了它们的原始名称。名称修饰对于跨不同模块的功能的可发现性是必要的。因此,无法通过 cimport 共享未损坏的名称 - 对于那些,适用普通的 C 共享库机制。