本文介绍了使用从Cython生成的头文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 限时删除!! 根据文档,可以使用从Cython生成的C头文件。我完全按照 Hello World 的示例进行操作,现在我想尝试一些不同的方法。我想使用公共声明来使用自定义方法。我的代码结构如下: hello.pyx setup.py main.c hello.pyx cdef public void say_hello(): print( Hello World) setup.py $ dist $ utils中的 .core从distutils.extension导入设置,从Cython.Distutils导入扩展$ b $b。Distutils导入build_ext ext_modules = [ Extension( hello,[ hello.pyx , main.c]),] 设置( name ='Hello app', cmdclass = {'build_ext':build_ext}, ext_modules = ext_modules ) main.c #include hello.h int main(void){问好(); } main.c 充当测试文件,以验证 say_hello()方法是否按预期工作。 构建安装文件 python3 setup.py build_ext 会产生以下输出。 运行build_ext 跳过'hello.c'Cython扩展(最新)构建'hello'扩展 x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict原型-g -fstack-protector-strong -Wformat -Werror = format-security -Wdate-time -D_FORTIFY_SOURCE = 2 -fPIC -I / usr / include / python3.5m -c hello.c -o build / temp.linux-x86_64-3.5 / hello.o x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-保护强-Wformat -Werror =格式安全-Wdate-time -D_FORTIFY_SOURCE = 2 -fPIC -I / usr / include / python3.5m -c main.c -o build / temp.linux-x86_64-3.5 / main。 o 在main.c:1:0中包含的文件中: hello.h:26:1:错误:未知类型名称'PyMODINIT_FUNC' PyMODINIT_FUNC inithello(void); ^ 错误: 命令'x86_64-linux-gnu-gcc'失败,退出状态为1 hello.h文件包含以下内容 / *由Cython生成0.25.2 * / #ifndef __PYX_HAVE__hello #定义__PYX_HAVE__hello $ b #ifndef __PYX_HAVE_API__hello #ifndef __PYX_EXTERN_C b $ b #ifdef __cplusplus #定义__PYX_EXTERN_C extern C #else #define __PYX_EXTERN_C extern #endif #endif #ifndef DL_IMPORT #定义DL_IMPORT(_T)_T #endif __PYX_EXTERN_C DL_IMPORT(void)say_hello(void); #endif / *!__ PYX_HAVE_API__你好* / #if PY_MAJOR_VERSION< 3 PyMODINIT_FUNC inithello(无效); //<-第26行 #else PyMODINIT_FUNC PyInit_hello(void); #endif #endif / *!__ PYX_HAVE__hello * / 据我了解,似乎gcc无法获得正确版本的Python(我正在使用Python 3.5)。有办法设置吗?此外,如果确实如此,为什么当我运行 python3 setup.py build_ext 命令时,为什么没有处理链接? 我对C没有太多经验,所以我可能会缺少一些东西。 解决方案我认为问题在于您的误解,认为 distutils 会建立您的可执行文件。事实并非如此。 目标是使用C程序中的某些python功能。让我们自己做一些必要的步骤: 使用cython生成 hello.h 和 hello.c 从给定的pyx文件。 使用创建的 hello.h 用于在C程序( main.c )中导入python功能。 使用编译器来编译两者文件 hello.c 和 main.c 。 使用链接器将最后一步中创建的目标文件链接到可执行文件。 第一步很简单: #hello.pyx: cdef public void say_hello(): print( Hello World) >>> python -m cython hello.pyx 现在我们有了 hello.c 和 hello.h 在我们的工作目录中。您的 main.c 是错误的,应如下所示: //main.c #include< Python.h> //需要 #include hello.h int main(void){ Py_Initialize(); //需要! inithello(); //需要!为Python3调用了PyInit_hello() say_hello(); Py_Finalize(); //需要! } 重要提示:如果使用Python> = 3.5和Cython> = 0.29,您必须考虑多阶段模块初始化,如 SO-post 中所述-否则 我不确定为什么cython的结果不包含 Python.h (这会使它成为独立的),但这就是它的样子-您需要在 hello.h 之前包含它。在使用 Py_Initialize()和 Py_Finalize() c> hello.h 。此外,您还需要使用 inithello() hello >>否则,分段错误会在可执行文件的开始处困扰您。 现在,我们需要找到进行编译的标志。这可以通过实用程序 / usr / bin / python-config (我使用python2.7,您需要对python3做同样的事情)和选项-cflags : >> / usr / bin / python-config --cflags -I / usr / include / python2.7 -I / usr / include / x86_64-linux-gnu / python2.7 -fno-strict-别名-Wdate-time -D_FORTIFY_SOURCE = 2 -g -fstack-protector-strong -Wformat -Werror = format-security -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict原型 所以让我们构建它: >>> gcc -c hello.c -o hello.o< our cflags> >>> gcc -c main.c -o main.o< our cflags> 现在我们都有两个目标文件 hello.o 和 main.o 在我们的工作目录中。我们需要链接它们,为了找到正确的标志,我们再次使用 python-config 实用程序,但这一次使用-ldflags -option: >> / usr / bin / python-config --ldflags --L / usr / lib / python2.7 / config-x86_64-linux-gnu -L / usr / lib -lpython2.7 -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-O1 -Wl,-符号函数 这意味着: >> gcc main.o hello.o -o prog< our ldflags> 现在我们终于有了可执行文件! 实际上,请求的内容不完全相同,但还有另一种可能性,可以通过使用选项从cython代码生成可执行文件-嵌入。打开此开关,不仅对模块进行了加密,而且创建了主要功能。为此,您的 hello.pyx 可能如下所示: #hello .pyx: cdef公共无效say_hello(): print( Hello World) ## main: say_hello() 也可以使用 __ name __ == __ main __ 技巧,但这不是必需的。 现在运行后: >>> python -m cython hello.pyx-嵌入 a main 函数在生成的 hello.c 中创建,该函数负责设置/初始化python环境。因此,我们可以构建并链接它: >> gcc hello.c -o prog< our cflags> <我们的ldflags> 我们已经完成了-无需知道如何初始化整个python-stuff! / p> According to the documentation it is possible to use C header files generated from Cython. I have followed the Hello World example with no problem and now I want to try something different. I want to use a public declaration to be able to use a custom method. My code structure is the following:hello.pyxsetup.pymain.chello.pyxcdef public void say_hello(): print("Hello World")setup.pyfrom distutils.core import setupfrom distutils.extension import Extensionfrom Cython.Distutils import build_extext_modules = [ Extension("hello", ["hello.pyx", "main.c"]),]setup( name='Hello app', cmdclass={'build_ext': build_ext}, ext_modules=ext_modules)main.c#include "hello.h"int main(void){ say_hello();}The main.c acts as a test file to verify that the say_hello() method works as intended.Building the setup file python3 setup.py build_ext produces the following output. running build_ext skipping 'hello.c' Cython extension (up-to-date) building 'hello' extension x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.5m -c hello.c -o build/temp.linux-x86_64-3.5/hello.o x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.5m -c main.c -o build/temp.linux-x86_64-3.5/main.o In file included from main.c:1:0: hello.h:26:1: error: unknown type name ‘PyMODINIT_FUNC’ PyMODINIT_FUNC inithello(void); ^ error: command 'x86_64-linux-gnu-gcc' failed with exit status 1The hello.h file contains the following /* Generated by Cython 0.25.2 */#ifndef __PYX_HAVE__hello#define __PYX_HAVE__hello#ifndef __PYX_HAVE_API__hello#ifndef __PYX_EXTERN_C #ifdef __cplusplus #define __PYX_EXTERN_C extern "C" #else #define __PYX_EXTERN_C extern #endif#endif#ifndef DL_IMPORT #define DL_IMPORT(_T) _T#endif__PYX_EXTERN_C DL_IMPORT(void) say_hello(void);#endif /* !__PYX_HAVE_API__hello */#if PY_MAJOR_VERSION < 3PyMODINIT_FUNC inithello(void); // <-- Line 26#elsePyMODINIT_FUNC PyInit_hello(void);#endif#endif /* !__PYX_HAVE__hello */To my understanding, it seems that gcc in not able to get the right version of Python (I'm using Python 3.5). Is there a way to set that somehow? Also, if that is indeed the case, why isn't this linking taken care of when I run the python3 setup.py build_ext command?I don't have much experience with C so I might be missing something. 解决方案 I think the problem is your misconception, that distutils will build the executable for you. That is not the case.Out goal is to use some python functionality from a C-program. Let's do the necessary steps by ourselves:Using cython to produce hello.h and hello.c from the given pyx-file.Using the created hello.h for importing the python functionality in a C-program (main.c).Using a compiler to compile both files hello.c and main.c.Using a linker to link the in the last step created object files to an executable.The first step is easy:#hello.pyx:cdef public void say_hello(): print("Hello World")>>>python -m cython hello.pyxNow we have hello.c and hello.h in our working directory. Your main.c is wrong and should look like the following: //main.c#include <Python.h> //needed#include "hello.h"int main(void){ Py_Initialize(); //Needed! inithello(); //Needed! called PyInit_hello() for Python3 say_hello(); Py_Finalize(); //Needed!}Important: If you use Python>=3.5 and Cython>=0.29 you must take multi-phase module initialisation into account, as described in this SO-post - otherwise the resulting program will crash.I'm not sure why the result of the cython doesn't include Python.h (this would make it self-contained), but this is the way it is - you need to include it prior to hello.h. Also Py_Initialize() and Py_Finalize() should be called before and after the usage of the functionality from hello.h.Also you need to initialize the module hello with inithello() otherwise a segmentation fault will haunt you at the start of the executable.Now we need to find the flags for compiling. This can be done with the utility /usr/bin/python-config (I use python2.7, you need to do the same for python3) and option --cflags:>>> /usr/bin/python-config --cflags-I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7-fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong-Wformat -Werror=format-security -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypesSo let's build it:>>>gcc -c hello.c -o hello.o <our cflags>>>>gcc -c main.c -o main.o <our cflags>Now we have both object files hello.o and main.o in our working directory. We need to link them and in order to find the right flags we use once again the python-config utility but this time with the --ldflags-option:>>> /usr/bin/python-config --ldflags--L/usr/lib/python2.7/config-x86_64-linux-gnu -L/usr/lib -lpython2.7-lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functionsThat means:>>> gcc main.o hello.o -o prog <our ldflags>And now we have finally our executable!Actually, it is not exactly what is asked for, but there is another possibility to generate an executable from the cython code, by using the option --embed. With this switch on not only the module is cythonized but also a main-function is created. For this your hello.pyx could look as follows:#hello.pyx:cdef public void say_hello(): print("Hello World")##main:say_hello()It is possible also to use __name__=="__main__" trick, but not needed.Now after running:>>>python -m cython hello.pyx --embeda main function is created in the resulting hello.c which takes care of setting up/initializing the python-environment. So we just can build and link it:>>> gcc hello.c -o prog <our cflags> <our ldflags>And we are done - no need to know, how to initialize the whole python-stuff right! 这篇关于使用从Cython生成的头文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 1403页,肝出来的..
09-06 10:31