CMake Integration
Let us consider a simple piece of C++ code:
#include "c2py/c2py.hpp"
/// A wonderful little class
class my_class {
int a, b;
public:
my_class(int a_, int b_) : a(a_), b(b_) {}
int f(int u) const { return u + a; }
};
CMake configuration
A complete CMake configuration file for this module is:
1cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
2project(clairexample VERSION 3.2.0 LANGUAGES C CXX)
3set(CMAKE_CXX_STANDARD 20)
4set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
5include(FetchContent)
6
7# Locate Python and NumPy components
8find_package(Python COMPONENTS Interpreter Development NumPy)
9
10# Fetch the c2py library
11FetchContent_Declare(
12 c2py
13 GIT_REPOSITORY https://github.com/flatironinstitute/c2py
14 GIT_TAG unstable
15 EXCLUDE_FROM_ALL
16)
17FetchContent_MakeAvailable(c2py)
18
19# Build the Python C++ extension module
20#
21Python_add_library(my_module MODULE my_module.cpp)
22target_link_libraries(my_module PRIVATE c2py::c2py)
23
24# -----------------------------------------------
25# Optionally regenerate bindings with clair-c2py
26# -----------------------------------------------
27include(${c2py_SOURCE_DIR}/share/cmake/clair_c2py_generate_bindings.cmake)
28
29option(Update_Python_Bindings "Use clair python bindings generators" ON)
30
31if (Update_Python_Bindings)
32 clair_c2py_generate_bindings(my_module)
33endif()
Brief explanation of the CMake file:
[Lines 1–19] This section provides a standard CMake configuration for building a Python C++ extension.
The
Python_add_librarycommand declares the extension using CMake’s FindPython module.Note that the
c2pylibrary is fetched and linked to the module (rather than using any installed version ofc2py). This approach is recommended, since it ensures that both the module andc2pyare built with consistent compiler options and linked against the same Python interpreter. Asc2pycompiles quickly, it does not add significant overhead to the build process.
[Line 23-end] This is the
clair-c2pyspecific part, which is triggered if the optionUpdate_Python_Bindingsis set toON:Find the
clair-c2pyexecutable.Regenerate the bindings before compiling the module.
Note
clair-c2pyautomatically uses the compile_commands.json file generated by CMake for the filemy_module.cppto detect all include flags from the project’s linked libraries (targets).The
-poption is used to specify the path to the compile_commands.json file (in the build directory).The
--generate-depfileoption is used to generate a dependency file, which ensures that the bindings are regenerated only when necessary.However the tools acts in the source directory, producing some additional
.cxxsource files.An additionnal
my_module.wrap.hxxfile is also generated, only used in multiple module situations.
Compiling
To compile the module, run the following commands:
$ mkdir build
$ cd build
$ cmake .. -DUpdate_Python_Bindings=ON
$ make -j 8
You can then use the module in Python:
>>> import my_module as M
>>> a = M.MyClass(1, 2)
>>> a.f(3)
4
Workflow
This CMakeLists.txt file is designed to be used in two different modes, depending on the value of the Update_Python_Bindings option:
User Mode (
Update_Python_Bindings == OFF) [default]:The compilation uses the bindings already present in the source, as they are included in
my_module.cpp.clair-c2pyis not required.Any C++20-compliant compiler can be used.
Developer Mode (
Update_Python_Bindings == ON):The bindings are automatically regenerated using
clair-c2pywhen the C++ code or the options TOML file are modified.At the end, the regenerated bindings should be committed along with the rest of the source (they are produced in the source directory).
Any C++20-compliant compiler can still be used to compile the module, even though
clair-c2pyitself relies on Clang and its libraries.