README.rst 9.17 KB
Newer Older
André Anjos's avatar
André Anjos committed
1 2 3 4
.. vim: set fileencoding=utf-8 :
.. Andre Anjos <andre.anjos@idiap.ch>
.. Thu 30 Jan 08:46:53 2014 CET

André Anjos's avatar
André Anjos committed
5
.. image:: https://img.shields.io/github/tag/bioidiap/xbob.extension.svg
André Anjos's avatar
André Anjos committed
6
   :target: https://github.com/bioidiap/xbob.extension
André Anjos's avatar
André Anjos committed
7 8
.. image:: https://travis-ci.org/bioidiap/xbob.extension.svg?branch=prototype
   :target: https://travis-ci.org/bioidiap/xbob.extension
André Anjos's avatar
André Anjos committed
9
.. image:: https://pypip.in/v/xbob.extension/badge.png
André Anjos's avatar
André Anjos committed
10
   :target: https://pypi.python.org/pypi/xbob.extension
André Anjos's avatar
André Anjos committed
11
.. image:: https://pypip.in/d/xbob.extension/badge.png
André Anjos's avatar
André Anjos committed
12
   :target: https://pypi.python.org/pypi/xbob.extension
André Anjos's avatar
André Anjos committed
13

14 15 16 17
===========================================
 Python/C++ Bob Extension Building Support
===========================================

18 19 20
This package provides a simple mechanims for building Python/C++ extensions for
`Bob <http://www.idiap.ch/software/bob/>`_. You use this package by including
it in your ``setup.py`` file.
21 22

Building with ``zc.buildout`` is possible using the ``develop`` recipe in
André Anjos's avatar
André Anjos committed
23
`xbob.buildout <http://pypi.python.org/pypi/xbob.buildout>`_. Follow the
24
instructions described on that package for this recipe.
25 26 27 28 29 30 31

Preparing for C++ Compilation
-----------------------------

Creating C++/Python bindings should be trivial. Firstly, edit your ``setup.py``
so that you include the following::

32 33
  from setuptools import dist
  dist.Distribution(dict(setup_requires=['xbob.extension']))
34
  from xbob.extension import Extension
35

36 37 38
  ...

  setup(
André Anjos's avatar
André Anjos committed
39

40 41 42 43 44 45
    name="xbob.myext",
    version="1.0.0",
    ...

    setup_requires=[
        'xbob.extension',
46
        'numpydoc' # see below
47 48 49 50 51 52 53 54 55 56
        ],

    ...
    ext_modules=[
      Extension("xbob.myext._myext",
        [
          "xbob/myext/ext/file1.cpp",
          "xbob/myext/ext/file2.cpp",
          "xbob/myext/ext/main.cpp",
        ],
57 58 59
        packages = [ #pkg-config modules to append
          'blitz>=0.10',
          'bob-core',
60 61 62 63
          ],
        include_dirs = [ #optionally, include directories
          "xbob/myext/ext/headers/",
          ],
64 65 66 67 68 69 70 71
        ),
      ... #add more extensions if you wish
    ],

    ...
    )

These modifications will allow you to compile extensions that are linked
72 73
against the named ``pkg-config`` modules. Other modules and options can be set
manually using `the standard options for python extensions
74 75 76 77 78 79
<http://docs.python.org/2/extending/building.html>`_. To hook-in the building
on the package through ``zc.buildout``, add the following section to your
``buildout.cfg``::

  [xbob.myext]
  recipe = xbob.buildout:develop
80 81
  verbose = true ;enables command-line verbosity
  debug = true ;compiles the module in debug mode
82 83 84 85 86 87

If you need to build multiple eggs, you will need **one entry per project** on
your ``buildout.cfg``. This includes, possibly, dependent projects. Currently,
``zc.buildout`` ignores the ``setup_requires`` entry on your ``setup.py`` file.
The recipe above creates a new interpreter that hooks that package in and
builds the project considering variables like ``prefixes`` into consideration.
André Anjos's avatar
André Anjos committed
88

89 90
Python API to pkg-config and Boost
----------------------------------
André Anjos's avatar
André Anjos committed
91 92 93 94 95 96

This package alson contains a set of Pythonic bindings to the popular
pkg-config configuration utility. It allows distutils-based setup files to
query for libraries installed on the current system through that command line
utility.  library.

97 98
Using the ``pkgconfig`` class
=============================
André Anjos's avatar
André Anjos committed
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126

To use this package at your ``setup.py`` file, you will need to let distutils
know it needs it before importing it. You can achieve this with the following
trick::

  from setuptools import dist
  dist.Distribution(dict(setup_requires='xbob.extension'))
  from xbob.extension.pkgconfig import pkgconfig

.. note::

   In this case, distutils should automatically download and install this
   package on the environment it is required to setup other package.

After inclusion, you can just instantiate an object of type ``pkgconfig``::

  >>> zlib = pkgconfig('zlib')
  >>> zlib.version # doctest: SKIP
  1.2.8
  >>> zlib.include_directories() # doctest: SKIP
  ['/usr/include']
  >>> zlib.library_dirs # doctest: SKIP
  ['/usr/lib']
  >>> zlib > '1.2.6'
  True
  >>> zlib > '1.2.10'
  False

127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
Documenting your Python extension
---------------------------------
One part of this package are some functions that makes it easy to generate a proper python documentation for your bound C++ functions.
This documentation can be used after::

  #include <xbob.extension/documentation.h>

The generated documentation relies on the ``numpydoc`` sphinx extension http://pypi.python.org/pypi/numpydoc, which is documented `here <http://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt>`_.
To use this package, please add the following lines in the ``conf.py`` file of your documentation (which is usually located in ``doc/conf.py``)::

  extensions = [
    ...
    'numpydoc',
  ]
  # Removes some warnings, see: https://github.com/phn/pytpm/issues/3
  numpydoc_show_class_members = False


Function documentation
======================
To generate a properly aligned function documentation, you can use::

  static xbob::extension::FunctionDoc description(
    "function_name",
    "Short function description",
    "Optional long function description"
  );

.. note::
  Please assure that you define this variable as ``static``.

Using this object, you can add several parts of the function that need documentation:

1. ``description.add_prototype("variable1, variable2", "return1, return2");`` can be used to add function definitions (i.e., ways how to use your function).
   This function needs to be called at least once.
   If the function does not define a return value, it can be left out (in which case the default ``"None"`` is used).
   
2. ``description.add_parameter("variable1, variable2", "datatype", "Variable description");`` should be defined for each variable that you have used in the prototypes.

3. ``description.add_return("return1", "datatype", "Return value description");`` should be defined for each return value that you have used in the prototypes.

Finally, when binding you function, you can use:

a) ``description.name()`` to get the name of the function

b) ``description.doc()`` to get the aligned documentation of the function, properly indented and broken at 80 characters (by default).
   By default, this call will check that all parameters and return values are documented, and add a ``.. todo`` directive if not.
   You can call ``description.doc(false)`` to disable the checks.

Sphinx directives like ``.. note::``, ``.. warning::`` or ``.. math::`` will be automatically detected and aligned, when they are used as one-line directive, e.g.:

  "(more text)\n.. note:: This is a note\n(more text)"

.. note::
  The ``.. todo::`` directive seems not to like being broken at 80 characters.
  If you want to use ``.. todo::``, please call ``description.doc(true, 10000)`` to avoid line breaking.


Class documentation
===================
To document a bound C++ class, you can use the ``xbob::extension::ClassDoc("class_name", "Short class description", "Optional long class description")`` function to align and wrap your documentation.
Again, during binding you can use the functions``description.name()`` and ``description.doc()`` as above.

Additionally, the class documentation has a function to add constructor definitions, which takes an ``xbob::extension::FunctionDoc`` object.
The shortest way to get a proper class documentation is::

  static auto my_class_doc =
      xbob::extension::ClassDoc("class_name", "Short description", "Long Description")
        .add_constructor(
          xbob::extension::FunctionDoc("class_name", "Constructor Description")
           .add_prototype("param1", "")
           .add_parameter("param1", "type1", "Description of param1")
        )
  ;

.. note:: The second ``""`` in ``add_prototype`` prevents the output type (which otherwise defaults to ``"None"``) to be written.

Possible speed issues
=====================

In order to speed up the loading time of the modules, you might want to reduce the amount of documentation that is generated (though I haven't experienced any speed differences).
For this purpose, just compile your bindings using the "-DXBOB_SHORT_DOCSTRINGS" compiler option, e.g. by adding it to the setup.py as follows (see also above)::

  ...
  ext_modules=[
    Extension("xbob.myext._myext",
      [
        ...
      ],
      ...
      define_macros = [('XBOB_SHORT_DOCSTRINGS',1)],
      ),
  ],
  ...

or simply define an environment variable ``XBOB_SHORT_DOCSTRINGS=1`` before invoking buildout.

In any of these cases, only the short descriptions will be returned as the doc string.


227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
Using the ``boost`` class
=========================

To use this package at your ``setup.py`` file, you will also need the same
trick as with ``pkgconfig``::

  from setuptools import dist
  dist.Distribution(dict(setup_requires='xbob.extension'))
  from xbob.extension.boost import boost

After inclusion, you can just instantiate an object of type ``boost``::

  >>> boost_pkg = boost('>= 1.47')
  >>> boost.version # doctest: SKIP
  1.50.0
  >>> boost.include_directory # doctest: SKIP
  '/usr/include'
244 245 246
  >>> libpaths, libnames = boost.libconfig(['system', 'python'])
  >>> print(libpaths) # doctest: SKIP
  ['/usr/lib']
247 248
  >>> print(libnames) # doctest: SKIP
  ['boost_system-mt', 'boost_python-mt-py27']