1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
.. _building:
Setting up a build system
#########################
This section assumes that you have followed the instructions to :ref:`install
<installing>` nanobind. The easiest way to compile a nanobind-based extension
involves a CMake-based build system. Other build systems can likely be used as
well, but they are not officially supported.
(The first section of the :ref:`CMake API reference <api_cmake>` mentions
some alternatives.)
Here, we will create a new package from scratch. If you already have an
existing CMake build system, it should be straightforward to merge some of the
following snippets into it.
Preliminaries
-------------
Begin by creating a new file named ``CMakeLists.txt`` in the root directory of
your project. It should start with the following lines that declare a project
name and tested CMake version range. The third line line searches for Python >=
3.9 including the ``Development.Module`` component required by nanobind. The
name of this module changed across CMake versions, hence the additional
conditional check.
.. code-block:: cmake
cmake_minimum_required(VERSION 3.15...3.27)
project(my_project) # Replace 'my_project' with the name of your project
if (CMAKE_VERSION VERSION_LESS 3.18)
set(DEV_MODULE Development)
else()
set(DEV_MODULE Development.Module)
endif()
find_package(Python 3.9 COMPONENTS Interpreter ${DEV_MODULE} REQUIRED)
Add the following lines below. They configure CMake to perform an optimized
*release* build by default unless another build type is specified. Without this
addition, binding code may run slowly and produce large binaries.
.. code-block:: cmake
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
Finding nanobind
----------------
Next, we must inform CMake about the presence of nanobind so that it can load
the functionality needed to compile extension modules. The details of this
step depend on *how you installed* nanobind, in the :ref:`previous section
<installing>`.
1. If you installed nanobind as a Pip or Conda package, append the following
lines at the end of ``CMakeLists.txt``. They query the package to determine
its installation path and then import it.
.. code-block:: cmake
# Detect the installed nanobind package and import it into CMake
execute_process(
COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE nanobind_ROOT)
find_package(nanobind CONFIG REQUIRED)
2. If you installed nanobind as a `Git submodule
<https://git-scm.com/book/en/v2/Git-Tools-Submodules>`_, append the
following lines at the end of ``CMakeLists.txt`` to point CMake to the
directory where nanobind is checked out.
.. code-block:: cmake
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ext/nanobind)
Building an extension
---------------------
Finally, we are ready to build an extension! Append the following line at the end of
``CMakeLists.txt``. It will compile a new extension named ``my_ext`` from the
source code contained in the file ``my_ext.cpp``.
.. code-block:: cmake
nanobind_add_module(my_ext my_ext.cpp)
:cmake:command:`nanobind_add_module` resembles standard CMake commands like
``add_executable()`` and ``add_library()``. Any number of source code and
header files can be declared when the extension is more complex and spread out
over multiple files.
.. note::
One opinionated choice of :cmake:command:`nanobind_add_module` is that it
optimizes the *size* of the extension by default (i.e., ``-Os`` is passed to
the compiler regardless of the project-wide settings). You must specify the
``NOMINSIZE`` parameter to the command to disable this behavior and, e.g.,
optimize extension code for speed (i.e., ``-O3``):
.. code-block:: cmake
nanobind_add_module(my_ext NOMINSIZE my_ext.cpp)
The default is chosen this way since extension code usually wraps existing
C++ libraries, in which the main computation takes place. Optimizing the
bindings for speed does not measurably improve performance, but it does make
the bindings *significantly* larger.
If you observe slowdowns when porting a pybind11 extension, or if your
extension performs significant amounts of work within the binding layer,
then you may want to experiment with passing the ``NOMINSIZE`` parameter.
The :ref:`next section <basics>` will review the contents of example module
implementation in ``my_ext.cpp``.
|