Python Binding Backend

Overview

The Python bindings of Choreonoid are implemented using a binding library that makes C++ classes and functions available from Python. Here we refer to this library as the binding backend.

Choreonoid currently allows you to select one of the following two backends.

Backend

Description

nanobind

An implementation using nanobind. This is the current default, and its sources are stored in the src/*/python directories. It supports the free-threaded Python described below.

pybind11

The conventional implementation using pybind11. Its sources are stored in the src/*/pybind11 directories.

nanobind is a library newly developed by the author of pybind11 based on the same design philosophy, and compared with pybind11 it reduces the binary size, the build time and the runtime overhead. It also has the advantage of supporting free-threaded Python.

Since we are currently in the middle of the migration to nanobind, both backends can be selected, but the pybind11 backend will be removed once the migration is complete. Normally you should just use the default nanobind backend.

For the modules that exist in both backends, the interfaces of the classes and functions seen from Python are implemented so that they are basically the same. Therefore, you do not need to be aware of which backend is used when writing ordinary scripts.

However, the sets of modules provided by the two backends are not completely identical. Some modules of recently added plugins are only available in the nanobind version, and as of August 2026 the modules of the Bullet plugin, the MuJoCo plugin and the PhysX plugin fall into this category. These modules are not built with the pybind11 backend.

Switching the Backend

The backend is switched with the CMake option CHOREONOID_PYTHON_BINDING_BACKEND. Specify either nanobind (the default) or pybind11 as its value.

To use the pybind11 backend, specify it in the CMake settings as follows.

cmake -DCHOREONOID_PYTHON_BINDING_BACKEND=pybind11 ..

This option is a CMake cache variable, and once set, the value is stored in the build directory. To switch the backend in an existing build directory, run CMake again with the value specified explicitly as shown above. If you run CMake without specifying the value, the previous value stored in the cache is used as it is.

Note

Switching the backend replaces the binaries of the generated Python modules. Since old modules remaining from before the switch may cause unexpected behavior, we recommend creating a new build directory when switching the backend.

Using Free-Threaded Python

What Is Free-Threaded Python

CPython has traditionally had a mutual exclusion mechanism called the Global Interpreter Lock (GIL), which prevented multiple threads from executing Python code simultaneously. For this reason, even if you wrote a multi-threaded program, there was a restriction that no speedup through parallelization could be obtained for the execution of Python code.

Since Python 3.13, a free-threaded build in which this GIL is disabled has been provided. When free-threaded Python is used, Python code can be executed truly in parallel on multiple threads. In Choreonoid as well, this makes it possible to, for example, parallelize processing for multiple robot models with threads.

The nanobind backend of Choreonoid supports this free-threaded Python. The pybind11 backend does not support it, so you must use the nanobind backend when you want to use free-threaded Python.

Note

With the pybind11 backend, the automatic detection of free-threaded Python described below is not performed either. Even if you build with a free-threaded interpreter specified explicitly, the generated modules do not declare that they do not use the GIL, so the GIL is enabled when the modules are loaded.

Installing Free-Threaded Python

The free-threaded version of Python is provided as an interpreter separate from the ordinary version. The name of its executable file has a “t” appended to the end of the version number, such as python3.13t or python3.14t, and it can coexist with the ordinary version.

Installing on Ubuntu

The standard repositories of Ubuntu do not currently provide a free-threaded version of Python. We therefore use the deadsnakes PPA. First, add this PPA to the system.

sudo add-apt-repository ppa:deadsnakes/ppa

Update the package list.

sudo apt update

The Python versions available from this PPA differ depending on the Ubuntu version. Check the available packages of the free-threaded version with the following command.

apt search nogil

The packages of the free-threaded version have “-nogil” appended to the name of the ordinary package, as in python3.13-nogil. Select the one to use from among the versions displayed here. As for which version to select, refer to “Selecting the Python Version to Use” below.

The following describes the case of using Python 3.13 as an example. When you use another version, read the “3.13” part of the commands accordingly. First, install the interpreter itself.

sudo apt install python3.13-nogil

This installs /usr/bin/python3.13t. In addition, install the development headers and libraries required for building Choreonoid, together with the package required for creating a virtual environment.

sudo apt install libpython3.13-nogil libpython3.13-dev python3.13-venv

Note

libpython3.13-nogil contains the library itself of the free-threaded version and pyconfig.h, but the common headers such as Python.h are contained in libpython3.13-dev instead. Both of them therefore need to be installed. Also, python3.13-venv contains the ensurepip module required for creating the virtual environment described below, and without it the virtual environment cannot be created.

Note that if the Ubuntu version you are using is not covered by this PPA, or if a package of the version you need is not provided, you can also build and install Python from source. In this case, specify the --disable-gil option to configure.

Selecting the Python Version to Use

When using a free-threaded version of Python, note that selecting the newest version is not necessarily the right choice. The Python features of Choreonoid use NumPy, and as described below, the availability of packages supporting the free-threaded version of NumPy differs depending on the Python version. If you select a Python version that is too new, you may end up in a situation where no corresponding NumPy exists and it cannot be used.

We therefore recommend selecting the version with the following procedure.

  1. Check the installable Python versions with apt search nogil

  2. Check on the NumPy page of PyPI whether wheels corresponding to those versions are provided (the part of the file name such as cp313t corresponds to the Python version)

  3. Select the newest version that satisfies both conditions

For reference, the situation as of August 2026 is as follows. Note, however, that these situations change from time to time, so check them with the procedure above in practice.

Ubuntu version

Python provided by the PPA

Versions supported by NumPy

24.04

3.13 / 3.14 / 3.15

3.13 / 3.14

25.04 / 25.10

Not provided

26.04

3.13 / 3.15

3.13

For example, on Ubuntu 26.04 both Python 3.13 and Python 3.15 can be installed, but since a NumPy wheel corresponding to Python 3.15 is not yet provided, Python 3.13 is the one to select.

Installing on Windows

Run the installer from the official Python site and select the item for installing the free-threaded binaries on the screen for customizing the installation options. Since the presence and the name of this item differ depending on the Python version, refer to the official Python documentation for the details.

Building with Free-Threaded Python

When the nanobind backend is selected, CMake automatically detects free-threaded Python and uses it for the build if it is found. The detection targets executable files named python3.*t in the /usr/local/bin, /usr/bin and /bin directories, and when there are multiple candidates, the one that comes later in name order (usually the one with the largest version number) takes precedence. A candidate is adopted after confirming, by querying it, that it really is a free-threaded build.

Interpreters installed in locations other than these are not subject to the automatic detection, so in that case specify one explicitly with Python_EXECUTABLE described below.

The result of the detection is output as a message like the following when CMake is run. When free-threaded Python is used, it is displayed as follows.

-- Using a free-threaded (no-GIL) Python: /usr/bin/python3.13t (3.13.14)

When free-threaded Python is not found and the ordinary Python is used, it is displayed as follows.

-- Using a standard (GIL-enabled) Python: /usr/bin/python3 (3.14.4)

If you want to explicitly specify the interpreter used for the build, set its path to the CMake variable Python_EXECUTABLE.

cmake -DPython_EXECUTABLE=/usr/bin/python3.13t ..

When this variable is set, the automatic detection is not performed and the specified interpreter is used as it is.

Conversely, if you want to deliberately use the ordinary Python in an environment where free-threaded Python is installed, turn on the option DISABLE_FREE_THREADED_PYTHON.

cmake -DDISABLE_FREE_THREADED_PYTHON=ON ..

This option makes the automatic detection above not be performed, and as a result the interpreter selected by the ordinary Python detection process of CMake is used. Therefore, in an environment where the standard Python of the system is the free-threaded version, the free-threaded version is used even if this option is turned on. Similarly, if this option and Python_EXECUTABLE are specified at the same time, the specified interpreter takes precedence.

Note

Choreonoid itself and the Python bindings are built against the ABI of the interpreter selected here. Since the ABIs of the free-threaded version and the ordinary version differ, the modules cannot be loaded from an interpreter of a different kind than the one used for the build. When you change the interpreter to use, create a new build directory and build again.

Running with Free-Threaded Python

When you build with free-threaded Python, the Python interpreter built into Choreonoid also becomes the free-threaded version and works with the GIL disabled. Scripts executed from the Python Console or from Python script items are also executed on this built-in interpreter.

In CPython, when an extension module that does not declare that it does not use the GIL is loaded, the GIL is automatically enabled at runtime. Since the Python modules of Choreonoid declare that they do not use the GIL through a feature of nanobind, the GIL is kept disabled even when these modules are loaded.

However, external Python libraries such as NumPy each need to support free-threaded Python. If you load a library that does not support it, the GIL is enabled at that point and the effect of parallel execution is no longer obtained. Even in this case, the script itself works without problems.

Preparing a Virtual Environment and NumPy

The Python features of Choreonoid use NumPy, but the python3-numpy package of Ubuntu is built for the ordinary version of Python and therefore cannot be used from the free-threaded version of Python. Install a NumPy that supports the free-threaded version with pip, from the wheels distributed on PyPI.

Create a Python virtual environment (venv) for this purpose from the free-threaded interpreter.

python3.13t -m venv ~/python-ft

Activate the created virtual environment.

source ~/python-ft/bin/activate

Install NumPy in this state.

pip install numpy

Note

The availability of the free-threaded wheels of NumPy differs depending on the Python version. If the latest version of NumPy has no wheel corresponding to the Python version you are using, pip automatically goes back to the version that has one and installs it. For example, as of August 2026, the wheels corresponding to Python 3.13 are provided up to NumPy 2.4.6, so 2.4.6 is installed instead of the latest version 2.5.1. If no corresponding wheel exists at all, pip tries to build from source and fails. In that case, refer to “Selecting the Python Version to Use” above and select a corresponding Python version instead.

You can check whether the installation has been done correctly with the following script.

python -c "import sys, numpy; print(numpy.__version__, sys._is_gil_enabled())"

If False is displayed following the version of NumPy, the GIL is kept disabled even with NumPy loaded, which means it works correctly. If True is displayed, the installed NumPy does not support the free-threaded version.

Using It from Choreonoid

If you start Choreonoid with the above virtual environment activated, the Python interpreter built into Choreonoid also recognizes it and can use the libraries installed there (this feature is available on UNIX-like operating systems such as Ubuntu).

Note

The built-in interpreter uses a virtual environment only when the virtual environment contains a library directory corresponding to the version and the kind of Python that Choreonoid is linked with (such as lib/python3.13t). If it does not exist, a warning stating that the virtual environment is not for the Python that Choreonoid is linked with is output, and the virtual environment is not used. This is a specification for preventing crashes caused by loading native extension modules built for a different ABI.

As described in “Using the Modules from Python Outside Choreonoid” of Overview of Python Scripting, the modules can also be used from an external Python without starting Choreonoid. In this case as well, run them with the above virtual environment activated.

python script.py