用cython简单地包装C代码(Simple wrapping of C code with cython)

编程入门 行业动态 更新时间:2024-10-27 18:18:12
用cython简单地包装C代码(Simple wrapping of C code with cython)

我有一些C函数,我想从python调用它们。 cython似乎是要走的路,但我真的不能找到一个如何做到这一点的例子。 我的C函数如下所示:

void calculate_daily ( char *db_name, int grid_id, int year, double *dtmp, double *dtmn, double *dtmx, double *dprec, double *ddtr, double *dayl, double *dpet, double *dpar ) ;

所有我想要做的是指定前三个参数(一个字符串和两个整数),并恢复8个numpy数组(或python列表,所有的双数组都有N个元素)。 我的代码假设指针指向已经分配的内存块。 此外,生成的C代码应该链接到一些外部库。

I have a number of C functions, and I would like to call them from python. cython seems to be the way to go, but I can't really find an example of how exactly this is done. My C function looks like this:

void calculate_daily ( char *db_name, int grid_id, int year, double *dtmp, double *dtmn, double *dtmx, double *dprec, double *ddtr, double *dayl, double *dpet, double *dpar ) ;

All I want to do is to specify the first three parameters (a string and two integers), and recover 8 numpy arrays (or python lists. All the double arrays have N elements). My code assumes that the pointers are pointing to an already allocated chunk of memory. Also, the produced C code ought to link to some external libraries.

最满意答案

这是一个非常完整的例子,它将numpy数组传递给外部C函数,逻辑上是这样

fc( int N, double* a, double* b, double* z ) # z = a + b

使用Cython。 (这肯定是知道那些谁知道很好的意见欢迎。最后更改:2011年2月23日,对于Cython 0.14。)

首先使用NumPy阅读或浏览Cython构建和Cython 。

2步:

python f-setup.py build_ext --inplace 转动f.pyx和fc.cpp - > f.so ,一个动态库 python test-f.py import f加载f.so ; f.fpy( ... )调用C fc( ... ) 。

python f-setup.py使用distutils来运行cython,编译并链接: cython f.pyx -> f.cpp 编译f.cpp和fc.cpp 链接fo fc.o - > f.so ,python import f将加载的动态库。

对于学生,我建议:制作这些步骤的图表,查看下面的文件,然后下载并运行它们。

( distutils是一个巨大的,卷曲的包,用于制作分发的Python包,并安装它们,这里我们只使用一小部分来编译和链接到f.so这一步与Cython无关,但是这可能会令人困惑,一个.pyx中的简单错误可能会导致g ++编译和链接的模糊错误消息页面,另请参见distutils文档和/或SO的问题 。

像make一样,如果f.pyx比f.cpp更新, setup.py将重新运行cython f.pyx和g++ -c ... f.cpp f.cpp 。 要清理, rm -r build/ 。

setup.py的替代方法是在脚本或Makefile中单独运行步骤: cython --cplus f.pyx -> f.cpp # see cython -h g++ -c ... f.cpp -> fo g++ -c ... fc.cpp -> fc.o cc-lib fo fc.o -> dynamic library f.so 修改下面的cc-lib-mac包装器用于您的平台和安装:它不漂亮,但很小。

对于Cython包装C的真实例子,请查看关于任何SciKit的 .pyx文件。

另请参见: Cython for NumPy用户和SO的问题/ tagged / cython 。


要解压缩以下文件,将批量剪切到一个大文件,如cython-numpy-c-demo ,然后在Unix(在一个干净的新目录中)运行sh cython-numpy-c-demo 。

#-------------------------------------------------------------------------------- cat >f.pyx <<\! # f.pyx: numpy arrays -> extern from "fc.h" # 3 steps: # cython f.pyx -> f.c # link: python f-setup.py build_ext --inplace -> f.so, a dynamic library # py test-f.py: import f gets f.so, f.fpy below calls fc() import numpy as np cimport numpy as np cdef extern from "fc.h": int fc( int N, double* a, double* b, double* z ) # z = a + b def fpy( N, np.ndarray[np.double_t,ndim=1] A, np.ndarray[np.double_t,ndim=1] B, np.ndarray[np.double_t,ndim=1] Z ): """ wrap np arrays to fc( a.data ... ) """ assert N <= len(A) == len(B) == len(Z) fcret = fc( N, <double*> A.data, <double*> B.data, <double*> Z.data ) # fcret = fc( N, A.data, B.data, Z.data ) grr char* return fcret ! #-------------------------------------------------------------------------------- cat >fc.h <<\! // fc.h: numpy arrays from cython , double* int fc( int N, const double a[], const double b[], double z[] ); ! #-------------------------------------------------------------------------------- cat >fc.cpp <<\! // fc.cpp: z = a + b, numpy arrays from cython #include "fc.h" #include <stdio.h> int fc( int N, const double a[], const double b[], double z[] ) { printf( "fc: N=%d a[0]=%f b[0]=%f \n", N, a[0], b[0] ); for( int j = 0; j < N; j ++ ){ z[j] = a[j] + b[j]; } return N; } ! #-------------------------------------------------------------------------------- cat >f-setup.py <<\! # python f-setup.py build_ext --inplace # cython f.pyx -> f.cpp # g++ -c f.cpp -> f.o # g++ -c fc.cpp -> fc.o # link f.o fc.o -> f.so # distutils uses the Makefile distutils.sysconfig.get_makefile_filename() # for compiling and linking: a sea of options. # http://docs.python.org/distutils/introduction.html # http://docs.python.org/distutils/apiref.html 20 pages ... # https://stackoverflow.com/questions/tagged/distutils+python import numpy from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext # from Cython.Build import cythonize ext_modules = [Extension( name="f", sources=["f.pyx", "fc.cpp"], # extra_objects=["fc.o"], # if you compile fc.cpp separately include_dirs = [numpy.get_include()], # .../site-packages/numpy/core/include language="c++", # libraries= # extra_compile_args = "...".split(), # extra_link_args = "...".split() )] setup( name = 'f', cmdclass = {'build_ext': build_ext}, ext_modules = ext_modules, # ext_modules = cythonize(ext_modules) ? not in 0.14.1 # version= # description= # author= # author_email= ) # test: import f ! #-------------------------------------------------------------------------------- cat >test-f.py <<\! #!/usr/bin/env python # test-f.py import numpy as np import f # loads f.so from cc-lib: f.pyx -> f.c + fc.o -> f.so N = 3 a = np.arange( N, dtype=np.float64 ) b = np.arange( N, dtype=np.float64 ) z = np.ones( N, dtype=np.float64 ) * np.NaN fret = f.fpy( N, a, b, z ) print "fpy -> fc z:", z ! #-------------------------------------------------------------------------------- cat >cc-lib-mac <<\! #!/bin/sh me=${0##*/} case $1 in "" ) set -- f.cpp fc.cpp ;; # default: g++ these -h* | --h* ) echo " $me [g++ flags] xx.c yy.cpp zz.o ... compiles .c .cpp .o files to a dynamic lib xx.so " exit 1 esac # Logically this is simple, compile and link, # but platform-dependent, layers upon layers, gloom, doom base=${1%.c*} base=${base%.o} set -x g++ -dynamic -arch ppc \ -bundle -undefined dynamic_lookup \ -fno-strict-aliasing -fPIC -fno-common -DNDEBUG `# -g` -fwrapv \ -isysroot /Developer/SDKs/MacOSX10.4u.sdk \ -I/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6 \ -I${Pysite?}/numpy/core/include \ -O2 -Wall \ "$@" \ -o $base.so # undefs: nm -gpv $base.so | egrep '^ *U _+[^P]' ! # 23 Feb 2011 13:38

Here's a tiny but complete example of passing numpy arrays to an external C function, logically

fc( int N, double* a, double* b, double* z ) # z = a + b

using Cython. (This is surely well-known to those who know it well. Comments are welcome. Last change: 23 Feb 2011, for Cython 0.14.)

First read or skim Cython build and Cython with NumPy .

2 steps:

python f-setup.py build_ext --inplace turns f.pyx and fc.cpp -> f.so, a dynamic library python test-f.py import f loads f.so; f.fpy( ... ) calls the C fc( ... ).

python f-setup.py uses distutils to run cython, compile and link: cython f.pyx -> f.cpp compile f.cpp and fc.cpp link f.o fc.o -> f.so, a dynamic lib that python import f will load.

For students, I'd suggest: make a diagram of these steps, look through the files below, then download and run them.

(distutils is a huge, convoluted package used to make Python packages for distribution, and install them. Here we're using just a small part of it to compile and link to f.so. This step has nothing to do with Cython, but it can be confusing; simple mistakes in a .pyx can cause pages of obscure error messages from g++ compile and link. See also distutils doc and/or SO questions on distutils .)

Like make, setup.py will rerun cython f.pyx and g++ -c ... f.cpp if f.pyx is newer than f.cpp. To cleanup, rm -r build/ .

An alternative to setup.py would be to run the steps separately, in a script or Makefile: cython --cplus f.pyx -> f.cpp # see cython -h g++ -c ... f.cpp -> f.o g++ -c ... fc.cpp -> fc.o cc-lib f.o fc.o -> dynamic library f.so. Modify the cc-lib-mac wrapper below for your platform and installation: it's not pretty, but small.

For real examples of Cython wrapping C, look at .pyx files in just about any SciKit .

See also: Cython for NumPy users and SO questions/tagged/cython .


To unpack the following files, cut-paste the lot to one big file, say cython-numpy-c-demo, then in Unix (in a clean new directory) run sh cython-numpy-c-demo.

#-------------------------------------------------------------------------------- cat >f.pyx <<\! # f.pyx: numpy arrays -> extern from "fc.h" # 3 steps: # cython f.pyx -> f.c # link: python f-setup.py build_ext --inplace -> f.so, a dynamic library # py test-f.py: import f gets f.so, f.fpy below calls fc() import numpy as np cimport numpy as np cdef extern from "fc.h": int fc( int N, double* a, double* b, double* z ) # z = a + b def fpy( N, np.ndarray[np.double_t,ndim=1] A, np.ndarray[np.double_t,ndim=1] B, np.ndarray[np.double_t,ndim=1] Z ): """ wrap np arrays to fc( a.data ... ) """ assert N <= len(A) == len(B) == len(Z) fcret = fc( N, <double*> A.data, <double*> B.data, <double*> Z.data ) # fcret = fc( N, A.data, B.data, Z.data ) grr char* return fcret ! #-------------------------------------------------------------------------------- cat >fc.h <<\! // fc.h: numpy arrays from cython , double* int fc( int N, const double a[], const double b[], double z[] ); ! #-------------------------------------------------------------------------------- cat >fc.cpp <<\! // fc.cpp: z = a + b, numpy arrays from cython #include "fc.h" #include <stdio.h> int fc( int N, const double a[], const double b[], double z[] ) { printf( "fc: N=%d a[0]=%f b[0]=%f \n", N, a[0], b[0] ); for( int j = 0; j < N; j ++ ){ z[j] = a[j] + b[j]; } return N; } ! #-------------------------------------------------------------------------------- cat >f-setup.py <<\! # python f-setup.py build_ext --inplace # cython f.pyx -> f.cpp # g++ -c f.cpp -> f.o # g++ -c fc.cpp -> fc.o # link f.o fc.o -> f.so # distutils uses the Makefile distutils.sysconfig.get_makefile_filename() # for compiling and linking: a sea of options. # http://docs.python.org/distutils/introduction.html # http://docs.python.org/distutils/apiref.html 20 pages ... # https://stackoverflow.com/questions/tagged/distutils+python import numpy from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext # from Cython.Build import cythonize ext_modules = [Extension( name="f", sources=["f.pyx", "fc.cpp"], # extra_objects=["fc.o"], # if you compile fc.cpp separately include_dirs = [numpy.get_include()], # .../site-packages/numpy/core/include language="c++", # libraries= # extra_compile_args = "...".split(), # extra_link_args = "...".split() )] setup( name = 'f', cmdclass = {'build_ext': build_ext}, ext_modules = ext_modules, # ext_modules = cythonize(ext_modules) ? not in 0.14.1 # version= # description= # author= # author_email= ) # test: import f ! #-------------------------------------------------------------------------------- cat >test-f.py <<\! #!/usr/bin/env python # test-f.py import numpy as np import f # loads f.so from cc-lib: f.pyx -> f.c + fc.o -> f.so N = 3 a = np.arange( N, dtype=np.float64 ) b = np.arange( N, dtype=np.float64 ) z = np.ones( N, dtype=np.float64 ) * np.NaN fret = f.fpy( N, a, b, z ) print "fpy -> fc z:", z ! #-------------------------------------------------------------------------------- cat >cc-lib-mac <<\! #!/bin/sh me=${0##*/} case $1 in "" ) set -- f.cpp fc.cpp ;; # default: g++ these -h* | --h* ) echo " $me [g++ flags] xx.c yy.cpp zz.o ... compiles .c .cpp .o files to a dynamic lib xx.so " exit 1 esac # Logically this is simple, compile and link, # but platform-dependent, layers upon layers, gloom, doom base=${1%.c*} base=${base%.o} set -x g++ -dynamic -arch ppc \ -bundle -undefined dynamic_lookup \ -fno-strict-aliasing -fPIC -fno-common -DNDEBUG `# -g` -fwrapv \ -isysroot /Developer/SDKs/MacOSX10.4u.sdk \ -I/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6 \ -I${Pysite?}/numpy/core/include \ -O2 -Wall \ "$@" \ -o $base.so # undefs: nm -gpv $base.so | egrep '^ *U _+[^P]' ! # 23 Feb 2011 13:38

更多推荐

本文发布于:2023-04-28 02:19:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1329852.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:代码   简单   cython   code   wrapping

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!