.. _building-c-or-cython-extensions: ====================== C or Cython Extensions ====================== Astropy supports using C extensions for wrapping C libraries and Cython for speeding up computationally-intensive calculations. Both Cython and C extension building can be customized using the ``get_extensions`` function of the ``setup_package.py`` file. If defined, this function must return a list of `distutils.core.Extension` objects. The creation process is left to the subpackage designer, and can be customized however is relevant for the extensions in the subpackage. While C extensions must always be defined through the ``get_extensions`` mechanism, Cython files (ending in ``.pyx``) are automatically located and loaded in separate extensions if they are not in ``get_extensions``. For Cython extensions located in this way, headers for numpy C functions are included in the build, but no other external headers are included. ``.pyx`` files present in the extensions returned by ``get_extensions`` are not included in the list of extensions automatically generated extensions. Note that this allows disabling a Cython file by providing an extension that includes the Cython file, but giving it the special ``name`` 'cython_skip'. Any extension with this package name will not be built by ``setup.py``. .. note:: If an :class:`~distutils.core.Extension` object is provided for Cython source files using the ``get_extensions`` mechanism, it is very important that the ``.pyx`` files be given as the ``source``, rather than the ``.c`` files generated by Cython. Using Numpy C headers --------------------- If your C or Cython extensions uses `numpy` at the C level, you probably need access to the numpy C headers. A common idiom you can find in the numpy docs or other examples involves getting the include directory by calling ``numpy.get_include()``. However, using this in ``setup_package.py`` will *not* work, because ``setup_package.py`` needs to be able to import even when none of the dependencies are present. To work around this need, simply include the string ``'numpy'`` in the list that is passed to the ``include_dirs`` argument of `distutils.core.Extension`. The astropy setup helpers will then use ``numpy.get_include()`` downstream once it is certain that the dependencies have actually been processed. For example:: from distutils.extension import Extension def get_extensions(): return Extension(name='myextension', sources=['myext.pyx'], include_dirs=['numpy']) Installing C header files ------------------------- If your C extension needs to be linked from other third-party C code, you probably want to install its header files along side the Python module. 1) Create an ``include`` directory inside of your package for all of the header files. 2) Use the ``get_package_data`` hook in ``setup_package.py`` to install those header files. For example, the `astropy.wcs` package has this:: def get_package_data(): return {'astropy.wcs': ['include/*.h']} Preventing importing at build time ---------------------------------- In rare cases, some packages may need to be imported at build time. Unfortunately, anything that requires a C or Cython extension will fail to import until the build phase has completed. In this cases, the ``_ASTROPY_SETUP_`` variable can be used to determine if the package is being imported as part of the build and choose to not import problematic modules. ``_ASTROPY_SETUP_`` is inserted into the builtins, and is `True` when inside of astropy's ``setup.py`` script, and `False` otherwise. For example, suppose there is a subpackage ``foo`` that needs to import a module called ``version.py`` at build time in order to set some version information, and also has a C extension, ``process``, that will not be available in the source tree. In this case, ``astropy/foo/__init__.py`` would probably want to check the value of ``_ASTROPY_SETUP_`` before importing the C extension:: try: from . import process except ImportError: if not _ASTROPY_SETUP_: raise from . import version