Commit 8a5206ff authored by Stefan Behnel's avatar Stefan Behnel

some cleanup and updating in C++ tutorial

parent abed5162
...@@ -9,17 +9,22 @@ Using C++ in Cython ...@@ -9,17 +9,22 @@ Using C++ in Cython
Overview Overview
========= =========
Cython v0.13 introduces native support for most of the C++ language. This means that the previous tricks that were used to wrap C++ classes (as described in http://wiki.cython.org/WrappingCPlusPlus_ForCython012AndLower) are no longer needed. Cython v0.13 introduces native support for most of the C++ language.
This means that the previous tricks that were used to wrap C++ classes
(as described in http://wiki.cython.org/WrappingCPlusPlus_ForCython012AndLower)
are no longer needed.
Wrapping C++ classes with Cython is now much more straightforward. This document describe in details the new way of wrapping C++ code. Wrapping C++ classes with Cython is now much more straightforward.
This document describe in details the new way of wrapping C++ code.
What's new in Cython v0.13 about C++ What's new in Cython v0.13 about C++
--------------------------------------------------- ---------------------------------------------------
For users of previous Cython versions, here is a brief overview of the main new features of Cython v0.13 regarding C++ support: For users of previous Cython versions, here is a brief overview of the
main new features of Cython v0.13 regarding C++ support:
* C++ objects can now be dynamically allocated with ``new`` and ``del`` keywords. * C++ objects can now be dynamically allocated with ``new`` and ``del`` keywords.
* C++ objects can now be stack-allocated. * C++ objects can be stack-allocated.
* C++ classes can be declared with the new keyword ``cppclass``. * C++ classes can be declared with the new keyword ``cppclass``.
* Templated classes are supported. * Templated classes are supported.
* Overloaded functions are supported. * Overloaded functions are supported.
...@@ -107,29 +112,50 @@ This is pretty dumb, but should suffice to demonstrate the steps involved. ...@@ -107,29 +112,50 @@ This is pretty dumb, but should suffice to demonstrate the steps involved.
Specify C++ language in setup.py Specify C++ language in setup.py
--------------------------------- ---------------------------------
In Cython :file:`setup.py` scripts, one normally instantiates an Extension The best way to build Cython code from :file:`setup.py` scripts is the
object. To make Cython generate and compile a C++ source, you just need ``cythonize()`` function. To make Cython generate and compile C++ code
to add the keyword ``language="c++"`` to your Extension construction statement, as in:: with distutils, you just need to pass the option ``language="c++"``::
from distutils.core import setup from distutils.core import setup
from distutils.extension import Extension from Cython.Build import cythonize
from Cython.Distutils import build_ext
setup(ext_modules=[Extension( setup(ext_modules = cythonize(
"rectangle", # name of extension "rect.pyx", # our Cython source
["rectangle.pyx", "Rectangle.cpp"], # our Cython source sources=["Rectangle.cpp"], # additional source file(s)
language="c++")], # causes Cython to create C++ source language="c++", # generate C++ code
cmdclass={'build_ext': build_ext}) ))
Cython will generate and compile the :file:`rectangle.cpp` file (from the Cython will generate and compile the :file:`rect.cpp` file (from the
:file:`rectangle.pyx`), then it will compile :file:`Rectangle.cpp` :file:`rect.pyx`), then it will compile :file:`Rectangle.cpp`
(implementation of the ``Rectangle`` class) and link both objects files (implementation of the ``Rectangle`` class) and link both objects files
together into :file:`rectangle.so`, which you can then import in Python using together into :file:`rect.so`, which you can then import in Python using
``import rectangle`` (if you forget to link the :file:`Rectangle.o`, you will ``import rect`` (if you forget to link the :file:`Rectangle.o`, you will
get missing symbols while importing the library in Python). get missing symbols while importing the library in Python).
The options can also be passed directly from the source file, which is
often preferable. Starting with version 0.17, Cython also allows to
pass external source files into the ``cythonize()`` command this way.
Here is a simplified setup.py file::
Alternatively, one can also use the ``cython`` command-line utility to generate a C++ ``.cpp`` file, and then compile it into a python extension. C++ mode for the ``cython`` command is turned on with the ``--cplus`` option. from distutils.core import setup
from Cython.Build import cythonize
setup(
name = "rectangleapp",
ext_modules = cythonize('*.pyx'),
)
And in the .pyx source file, write this into the first comment block, before
any source code, to compile it in C++ mode and link it statically against the
:file:`Rectange.cpp` code file::
# distutils: language = c++
# distutils: sources = Rectangle.cpp
To compile manually (e.g. using ``make``), the ``cython`` command-line
utility can be used to generate a C++ ``.cpp`` file, and then compile it
into a python extension. C++ mode for the ``cython`` command is turned
on with the ``--cplus`` option.
Declaring a C++ class interface Declaring a C++ class interface
-------------------------------- --------------------------------
...@@ -145,7 +171,8 @@ This will make the C++ class def for Rectangle available. Note the namespace dec ...@@ -145,7 +171,8 @@ This will make the C++ class def for Rectangle available. Note the namespace dec
Declare class with cdef cppclass Declare class with cdef cppclass
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Now, let's add the Rectangle class to this extern from block - just copy the class name from Rectangle.h and adjust for Cython syntax, so now it becomes:: Now, let's add the Rectangle class to this extern from block - just copy the
class name from Rectangle.h and adjust for Cython syntax, so now it becomes::
cdef extern from "Rectangle.h" namespace "shapes": cdef extern from "Rectangle.h" namespace "shapes":
cdef cppclass Rectangle: cdef cppclass Rectangle:
...@@ -170,25 +197,32 @@ Declare a var with the wrapped C++ class ...@@ -170,25 +197,32 @@ Declare a var with the wrapped C++ class
Now, we use cdef to declare a var of the class with the C++ ``new`` statement:: Now, we use cdef to declare a var of the class with the C++ ``new`` statement::
cdef Rectangle *rec = new Rectangle(1, 2, 3, 4) cdef Rectangle *rec = new Rectangle(1, 2, 3, 4)
cdef int recLength = rec.getLength() try:
recLength = rec.getLength()
... ...
del rec #delete heap allocated object finally:
del rec # delete heap allocated object
It's also possible to declare a stack allocated object, but it's necessary to have a "default" constructor:: It's also possible to declare a stack allocated object, as long as it has
a "default" constructor::
cdef extern from "Foo.h": cdef extern from "Foo.h":
cdef cppclass Foo: cdef cppclass Foo:
Foo() Foo()
def func():
cdef Foo foo cdef Foo foo
...
Note that, like C++, if the class has only one constructor and it is a default one, it's not necessary to declare it. Note that, like C++, if the class has only one constructor and it
is a default one, it's not necessary to declare it.
Create Cython wrapper class Create Cython wrapper class
---------------------------- ----------------------------
At this point, we have exposed into our pyx file's namespace the interface of the C++ Rectangle type. Now, we need to make At this point, we have exposed into our pyx file's namespace the interface
this accessible from external Python code (which is our whole point). of the C++ Rectangle type. Now, we need to make this accessible from
external Python code (which is our whole point).
Common programming practice is to create a Cython extension type which Common programming practice is to create a Cython extension type which
holds a C++ instance pointer as an attribute ``thisptr``, and create a bunch of holds a C++ instance pointer as an attribute ``thisptr``, and create a bunch of
...@@ -227,7 +261,8 @@ We describe here all the C++ features that were not discussed in the above tutor ...@@ -227,7 +261,8 @@ We describe here all the C++ features that were not discussed in the above tutor
Overloading Overloading
------------ ------------
Overloading is very simple. Just declare the method with different parameters and use any of them:: Overloading is very simple. Just declare the method with different parameters
and use any of them::
cdef extern from "Foo.h": cdef extern from "Foo.h":
cdef cppclass Foo: cdef cppclass Foo:
...@@ -266,8 +301,8 @@ Cython uses C++ for overloading operators:: ...@@ -266,8 +301,8 @@ Cython uses C++ for overloading operators::
Nested class declarations Nested class declarations
-------------------------- --------------------------
C++ allows nested class declaration. Class declarations can also be nested in Cython:: C++ allows nested class declaration. Class declarations can also be
nested in Cython::
cdef extern from "<vector>" namespace "std": cdef extern from "<vector>" namespace "std":
cdef cppclass vector[T]: cdef cppclass vector[T]:
...@@ -290,20 +325,29 @@ Note that the nested class is declared with a ``cppclass`` but without a ``cdef` ...@@ -290,20 +325,29 @@ Note that the nested class is declared with a ``cppclass`` but without a ``cdef`
C++ operators not compatible with Python syntax C++ operators not compatible with Python syntax
------------------------------------------------ ------------------------------------------------
Cython try to keep a syntax as close as possible to standard Python. Because of this, certain C++ operators, like the preincrement ``++foo`` or the dereferencing operator ``*foo`` cannot be used with the same syntax as C++. Cython provides functions replacing these operators in a special module ``cython.operator``. The functions provided are: Cython try to keep a syntax as close as possible to standard Python.
Because of this, certain C++ operators, like the preincrement ``++foo``
or the dereferencing operator ``*foo`` cannot be used with the same
syntax as C++. Cython provides functions replacing these operators in
a special module ``cython.operator``. The functions provided are:
* ``cython.operator.dereference`` for dereferencing. ``dereference(foo)`` will produce the C++ code ``*foo`` * ``cython.operator.dereference`` for dereferencing. ``dereference(foo)``
* ``cython.operator.preincrement`` for pre-incrementation. ``preincrement(foo)`` will produce the C++ code ``++foo`` will produce the C++ code ``*foo``
* ``cython.operator.preincrement`` for pre-incrementation. ``preincrement(foo)``
will produce the C++ code ``++foo``
* ... * ...
These functions need to be cimported. Of course, one can use a ``from ... cimport ... as`` to have shorter and more readable functions. For example: ``from cython.operator cimport dereference as deref``. These functions need to be cimported. Of course, one can use a
``from ... cimport ... as`` to have shorter and more readable functions.
For example: ``from cython.operator cimport dereference as deref``.
Templates Templates
---------- ----------
Cython uses a bracket syntax for templating. A simple example for wrapping C++ vector:: Cython uses a bracket syntax for templating. A simple example for wrapping C++ vector::
from cython.operator cimport dereference as deref, preincrement as inc #dereference and increment operators # import dereference and increment operators
from cython.operator cimport dereference as deref, preincrement as inc
cdef extern from "<vector>" namespace "std": cdef extern from "<vector>" namespace "std":
cdef cppclass vector[T]: cdef cppclass vector[T]:
...@@ -331,12 +375,15 @@ Cython uses a bracket syntax for templating. A simple example for wrapping C++ v ...@@ -331,12 +375,15 @@ Cython uses a bracket syntax for templating. A simple example for wrapping C++ v
del v del v
Multiple template parameters can be defined as a list, such as [T, U, V] or [int, bool, char]. Multiple template parameters can be defined as a list, such as [T, U, V]
or [int, bool, char].
Standard library Standard library
----------------- -----------------
Most of the containers of the C++ Standard Library have been declared in pxd files located in ``/Cython/Includes/libcpp``. These containers are: deque, list, map, pair, queue, set, stack, vector. Most of the containers of the C++ Standard Library have been declared
in pxd files located in ``/Cython/Includes/libcpp``. These containers
are: deque, list, map, pair, queue, set, stack, vector.
For example:: For example::
...@@ -349,7 +396,8 @@ For example:: ...@@ -349,7 +396,8 @@ For example::
for i in range(10): for i in range(10):
print vect[i] print vect[i]
The pxd files in ``/Cython/Includes/libcpp`` also work as good examples on how to declare C++ classes. The pxd files in ``/Cython/Includes/libcpp`` also work as good examples on
how to declare C++ classes.
Exceptions Exceptions
----------- -----------
...@@ -472,6 +520,8 @@ Question: How do you declare and call a function that takes a reference as an ar ...@@ -472,6 +520,8 @@ Question: How do you declare and call a function that takes a reference as an ar
C++ left-values C++ left-values
---------------- ----------------
C++ allows functions returning a reference to be left-values. This is currently not supported in Cython. ``cython.operator.dereference(foo)`` is also not considered a left-value. C++ allows functions returning a reference to be left-values. This is currently
not supported in Cython. ``cython.operator.dereference(foo)`` is also not
considered a left-value.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment