Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here's a tiny but complete example of passing numpy arrays to an external C function, logically</p> <pre><code>fc( int N, double* a, double* b, double* z ) # z = a + b </code></pre> <p>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.)</p> <p>First read or skim <a href="http://docs.cython.org/src/quickstart/build.html" rel="nofollow noreferrer">Cython build</a> and <a href="http://docs.cython.org/src/tutorial/numpy.html" rel="nofollow noreferrer">Cython with NumPy</a> .</p> <p>2 steps:</p> <ul> <li><code>python f-setup.py build_ext --inplace</code><br> turns <code>f.pyx</code> and <code>fc.cpp</code> -> <code>f.so</code>, a dynamic library</li> <li><code>python test-f.py</code><br> <code>import f</code> loads <code>f.so</code>; <code>f.fpy( ... )</code> calls the C <code>fc( ... )</code>.</li> </ul> <p><code>python f-setup.py</code> uses <code>distutils</code> to run cython, compile and link:<br> <code>cython f.pyx -&gt; f.cpp</code><br> compile <code>f.cpp</code> and <code>fc.cpp</code><br> link <code>f.o fc.o</code> -> <code>f.so</code>, a dynamic lib that python <code>import f</code> will load.</p> <p>For students, I'd suggest: make a diagram of these steps, look through the files below, then download and run them.</p> <p>(<code>distutils</code> 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 <code>f.so</code>. 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 <a href="http://docs.python.org/distutils" rel="nofollow noreferrer">distutils doc</a> and/or <a href="https://stackoverflow.com/questions/tagged/distutils+python">SO questions on distutils</a> .)</p> <p>Like <code>make</code>, <code>setup.py</code> will rerun <code>cython f.pyx</code> and <code>g++ -c ... f.cpp</code> if <code>f.pyx</code> is newer than <code>f.cpp</code>.<br> To cleanup, <code>rm -r build/</code> .</p> <p>An alternative to <code>setup.py</code> would be to run the steps separately, in a script or Makefile:<br> <code>cython --cplus f.pyx -&gt; f.cpp # see cython -h</code><br> <code>g++ -c ... f.cpp -&gt; f.o</code><br> <code>g++ -c ... fc.cpp -&gt; fc.o</code><br> <code>cc-lib f.o fc.o -&gt; dynamic library f.so</code>.<br> Modify the <code>cc-lib-mac</code> wrapper below for your platform and installation: it's not pretty, but small.</p> <p>For real examples of Cython wrapping C, look at .pyx files in just about any <a href="http://scikits.appspot.com/scikits" rel="nofollow noreferrer">SciKit</a> .</p> <p>See also: <a href="http://docs.cython.org/src/userguide/numpy_tutorial.html" rel="nofollow noreferrer">Cython for NumPy users</a> and <a href="https://stackoverflow.com/questions/tagged/cython">SO questions/tagged/cython</a> .</p> <hr> <p>To unpack the following files, cut-paste the lot to one big file, say <code>cython-numpy-c-demo</code>, then in Unix (in a clean new directory) run <code>sh cython-numpy-c-demo</code>.</p> <pre><code>#-------------------------------------------------------------------------------- cat &gt;f.pyx &lt;&lt;\! # f.pyx: numpy arrays -&gt; extern from "fc.h" # 3 steps: # cython f.pyx -&gt; f.c # link: python f-setup.py build_ext --inplace -&gt; 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 &lt;= len(A) == len(B) == len(Z) fcret = fc( N, &lt;double*&gt; A.data, &lt;double*&gt; B.data, &lt;double*&gt; Z.data ) # fcret = fc( N, A.data, B.data, Z.data ) grr char* return fcret ! #-------------------------------------------------------------------------------- cat &gt;fc.h &lt;&lt;\! // fc.h: numpy arrays from cython , double* int fc( int N, const double a[], const double b[], double z[] ); ! #-------------------------------------------------------------------------------- cat &gt;fc.cpp &lt;&lt;\! // fc.cpp: z = a + b, numpy arrays from cython #include "fc.h" #include &lt;stdio.h&gt; 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 &lt; N; j ++ ){ z[j] = a[j] + b[j]; } return N; } ! #-------------------------------------------------------------------------------- cat &gt;f-setup.py &lt;&lt;\! # python f-setup.py build_ext --inplace # cython f.pyx -&gt; f.cpp # g++ -c f.cpp -&gt; f.o # g++ -c fc.cpp -&gt; fc.o # link f.o fc.o -&gt; 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 &gt;test-f.py &lt;&lt;\! #!/usr/bin/env python # test-f.py import numpy as np import f # loads f.so from cc-lib: f.pyx -&gt; f.c + fc.o -&gt; 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 -&gt; fc z:", z ! #-------------------------------------------------------------------------------- cat &gt;cc-lib-mac &lt;&lt;\! #!/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 </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload