使用 Cython 连接具有重复方法名称的外部 C 代码
Interfacing external C code with duplicate method names using Cython
我想为我的 Python 代码中的某些 C 代码提供本机接口。为此,我决定使用 Cython.
在这种特定情况下,我有一些重名的 C 文件,导致编译问题。有什么办法可以避免这个吗?官方文档(https://cython.readthedocs.io/en/latest/src/userguide/external_C_code.html#resolving-naming-conflicts-c-name-specifications)的解决方案似乎还不够。
以下示例已被精简以演示问题,而我的实际用例是针对更大的第三方库。在最好的情况下,我可以避免拥有多个内容相似的 *.so
文件。我可能需要在运行时使用同一方法的不同定义。
例子
# File setup.py
from setuptools import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize("my_test.pyx", language_level=3)
)
# File my_test.pyx
from binding cimport add as _add, subtract as _subtract, module1_main as _main
print('Hello World')
def add(a, b):
return _add(a, b)
def subtract(a, b):
return _subtract(a, b)
def main():
return _main()
# File binding.pxd
cdef extern from "module1.c":
int add (int a, int b)
int subtract (int a, int b)
int module1_main "main" ()
cdef extern from "module2.c":
int module2_main "main" ()
// File module1.c
#include <stdio.h>
static int add(int a, int b) {
return a + b;
}
static int subtract(int a, int b) {
return a - b;
}
int main() {
printf("Result: %d", add(40, 2));
return 0;
}
// File module2.c
#include <stdio.h>
int main() {
printf("Hello from module 2");
return 0;
}
错误信息
(venv) user@host ~/path/to/directory $ python setup.py build_ext --inplace
Compiling my_test.pyx because it changed.
[1/1] Cythonizing my_test.pyx
running build_ext
building 'my_test' extension
x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -I. "-I/home/user/path/to/directory/venv/include" -I/usr/include/python3.8 -c my_test.c -o build/temp.linux-x86_64-cpython-38/my_test.o
In file included from my_test.c:716:
module2.c:4:5: error: redefinition of ‘main’
4 | int main() {
| ^~~~
In file included from my_test.c:715:
module1.c:13:5: note: previous definition of ‘main’ was here
13 | int main() {
| ^~~~
error: command '/usr/bin/x86_64-linux-gnu-gcc' failed with exit code 1
一般static
用于将函数限制在一个复杂单元,所以你需要修改你的C文件并制作重复的函数static
。将函数定义为 static
将允许您创建 separate Cython 模块来包装该函数,但不允许您像您尝试的那样在同一模块中使用冲突的函数在这里做。这样做的 flip-side 是你必须在你的 Cython 文件中包含函数定义 - 你不能只包含一个 header 和 link 它稍后。
main
在 C 语言中有特殊含义(它定义了一个完整程序的起点),因此您几乎可以肯定不希望 C 函数调用 main
。
您 link int module2_main "main" ()
的 Cython“cname”功能不能(而且永远不会!)解决您的问题。它实际上允许您仅在 Cython 代码中将 main
称为 module2_main
。它仍然被翻译成 C 代码 main
,因此您的定义冲突仍然是一个问题。
这是您必须在 C 中解决的问题(可能通过重命名函数)。如果 C 库确实是外部的并且您无法修改它们,那么您就陷入困境了。
经过一些测试的快速附录:
- 您可以用 Cython 包装一个名为
main()
的函数;
- 如果您想包装两个不同的同名函数,那么它们必须放在不同的 Cython 模块中。
- 由于Cython动态导入模块的方式,run-time两个模块之间没有冲突。
但这主要是一个 C/linker 问题...
我想为我的 Python 代码中的某些 C 代码提供本机接口。为此,我决定使用 Cython.
在这种特定情况下,我有一些重名的 C 文件,导致编译问题。有什么办法可以避免这个吗?官方文档(https://cython.readthedocs.io/en/latest/src/userguide/external_C_code.html#resolving-naming-conflicts-c-name-specifications)的解决方案似乎还不够。
以下示例已被精简以演示问题,而我的实际用例是针对更大的第三方库。在最好的情况下,我可以避免拥有多个内容相似的 *.so
文件。我可能需要在运行时使用同一方法的不同定义。
例子
# File setup.py
from setuptools import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize("my_test.pyx", language_level=3)
)
# File my_test.pyx
from binding cimport add as _add, subtract as _subtract, module1_main as _main
print('Hello World')
def add(a, b):
return _add(a, b)
def subtract(a, b):
return _subtract(a, b)
def main():
return _main()
# File binding.pxd
cdef extern from "module1.c":
int add (int a, int b)
int subtract (int a, int b)
int module1_main "main" ()
cdef extern from "module2.c":
int module2_main "main" ()
// File module1.c
#include <stdio.h>
static int add(int a, int b) {
return a + b;
}
static int subtract(int a, int b) {
return a - b;
}
int main() {
printf("Result: %d", add(40, 2));
return 0;
}
// File module2.c
#include <stdio.h>
int main() {
printf("Hello from module 2");
return 0;
}
错误信息
(venv) user@host ~/path/to/directory $ python setup.py build_ext --inplace
Compiling my_test.pyx because it changed.
[1/1] Cythonizing my_test.pyx
running build_ext
building 'my_test' extension
x86_64-linux-gnu-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -fPIC -I. "-I/home/user/path/to/directory/venv/include" -I/usr/include/python3.8 -c my_test.c -o build/temp.linux-x86_64-cpython-38/my_test.o
In file included from my_test.c:716:
module2.c:4:5: error: redefinition of ‘main’
4 | int main() {
| ^~~~
In file included from my_test.c:715:
module1.c:13:5: note: previous definition of ‘main’ was here
13 | int main() {
| ^~~~
error: command '/usr/bin/x86_64-linux-gnu-gcc' failed with exit code 1
一般
static
用于将函数限制在一个复杂单元,所以你需要修改你的C文件并制作重复的函数static
。将函数定义为static
将允许您创建 separate Cython 模块来包装该函数,但不允许您像您尝试的那样在同一模块中使用冲突的函数在这里做。这样做的 flip-side 是你必须在你的 Cython 文件中包含函数定义 - 你不能只包含一个 header 和 link 它稍后。main
在 C 语言中有特殊含义(它定义了一个完整程序的起点),因此您几乎可以肯定不希望 C 函数调用main
。您 link
int module2_main "main" ()
的 Cython“cname”功能不能(而且永远不会!)解决您的问题。它实际上允许您仅在 Cython 代码中将main
称为module2_main
。它仍然被翻译成 C 代码main
,因此您的定义冲突仍然是一个问题。这是您必须在 C 中解决的问题(可能通过重命名函数)。如果 C 库确实是外部的并且您无法修改它们,那么您就陷入困境了。
经过一些测试的快速附录:
- 您可以用 Cython 包装一个名为
main()
的函数; - 如果您想包装两个不同的同名函数,那么它们必须放在不同的 Cython 模块中。
- 由于Cython动态导入模块的方式,run-time两个模块之间没有冲突。
但这主要是一个 C/linker 问题...