CMake integration
Let us consider a simple piece of C++ code:
// my_module.cpp
#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; }
};
Compiling with clang and the clair plugin
To use the clair plugin, we can use the following CMakeLists.txt file
1cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
2project(clairexample VERSION 3.2.0 LANGUAGES C CXX)
3set(CMAKE_CXX_STANDARD 20)
4
5# Find Python, c2py and clair
6find_package(Python COMPONENTS Interpreter Development NumPy)
7find_package(c2py REQUIRED)
8find_package(clair REQUIRED)
9
10Python_add_library(my_module MODULE my_module.cpp)
11
12# Link to low level c2py and add the -fplugin option using a cmake target.
13target_link_libraries(my_module PRIVATE c2py::c2py clair::c2py_plugin)
This is a standard CMake configuration file.
Python_add_library
declares a C++ Python extension using the standard CMake
FindPython package.
The additional steps required by clair
are:
[line 7-8] Finds the required cmake packages
c2py
andclair
.[line 13] Compiles against two targets:
c2py::c2py
: compile and link againstc2py
clair::c2py_plugin
: add the -fplugin instruction to clang
A more general setup
The previous example is fine to develop the project, but needs to be generalized
if we want to deploy the code on more platforms, without clang or clair
, i.e. just using the bindings without generating them.
We assume that the bindings have already been generated and copied into the source directory.
The CMakeLists.txt reads:
1cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
2project(clairexample VERSION 3.2.0 LANGUAGES C CXX)
3set(CMAKE_CXX_STANDARD 20)
4
5find_package(Python COMPONENTS Interpreter Development NumPy)
6find_package(c2py REQUIRED)
7
8# We can compile with or without the clair plugin
9option(GENERATE_PYTHON_BINDINGS "Use clair python bindings generators" OFF)
10if (GENERATE_PYTHON_BINDINGS)
11 find_package(clair REQUIRED)
12endif()
13
14# If GENERATE_PYTHON_BINDINGS, we compile my_module.cpp else the bindings my_module.wrap.cxx
15Python_add_library(my_module MODULE my_module.$<IF:$<BOOL:${GENERATE_PYTHON_BINDINGS}>,cpp,wrap.cxx>)
16
17# Link to low level c2py.
18# Use the clair plugin if we want to generated the bindings
19target_link_libraries(my_module PRIVATE c2py::c2py $<$<BOOL:${GENERATE_PYTHON_BINDINGS}>:clair::c2py_plugin>)
We introduce an option GENERATE_PYTHON_BINDINGS
so that the code can be used in two ways:
If
GENERATE_PYTHON_BINDINGS=ON
, it is the same as before.If
GENERATE_PYTHON_BINDINGS=OFF
, it simply compiles the bindings my_module.wrap.cxx from the sources, without any plugin. This compiles with any C++20 compiler (tested actually on clang >=16, gcc >= 12), and requires only Python andc2py
.
Note
The CMake syntax $<…> are expression generators, and basically an if expression in CMake.
A variant avoiding the installation of c2py
It is often convenient to avoid the need to install the c2py
library completely.
As c2py
is a very small library, the cost of recompiling it in each project is negligible,
but it is often a good strategy to ensure it is compiled with the same compilers, standard libraries, etc.
In order to do this, we can simply modify the CMakeLists.txt file as
1cmake_minimum_required(VERSION 3.20 FATAL_ERROR)
2project(clairexample VERSION 3.2.0 LANGUAGES C CXX)
3set(CMAKE_CXX_STANDARD 20)
4
5find_package(Python COMPONENTS Interpreter Development NumPy)
6
7include(FetchContent)
8FetchContent_Declare(
9 c2py
10 GIT_REPOSITORY https://github.com/flatironinstitute/c2py
11 GIT_TAG unstable
12 EXCLUDE_FROM_ALL
13)
14FetchContent_MakeAvailable(c2py )
15
16# We can compile with or without the clair plugin
17option(GENERATE_PYTHON_BINDINGS "Use clair python bindings generators" OFF)
18if (GENERATE_PYTHON_BINDINGS)
19 find_package(clair REQUIRED)
20endif()
21
22# If GENERATE_PYTHON_BINDINGS, we compile my_module.cpp (with the plugin) else the bindings my_module.wrap.cxx
23Python_add_library(my_module MODULE my_module.$<IF:$<BOOL:${GENERATE_PYTHON_BINDINGS}>,cpp,wrap.cxx>)
24
25# Link to low level c2py.
26# Use the clair plugin if we want to generated the bindings
27target_link_libraries(my_module PRIVATE c2py::c2py $<$<BOOL:${GENERATE_PYTHON_BINDINGS}>:clair::c2py_plugin>)
In line 7-14, we use the FetchContent command of CMake
to fetch the sources of c2py
during the configuration.
The rest of the script is unchanged.