Building the C example program
The C and C++ languages do not have a standard package manager, so using a third-party library requires the programmer to come up with their own dependency management scheme.
Before we perform the first step of the guide, we'll discuss the options the user has for integrating the SDK library dependency into their project. Then we'll pick one of these options and build the example program using that method. A second method will be briefly shown at the end.
If you are not familiar with CMake, you may want to read CMake's "Using Dependencies Guide" first
Where is the SDK source code?
The execution event C SDK lives in the same source code repository as the
execution daemon (here), in the
subdirectory category/event
. It has a separate CMakeLists.txt
file that
can act as a top-level project file, so that users do not need to build the
full execution project in order to compile it.
The SDK's build system produces a library called libmonad_event.a
, or
libmonad_event.so
if you prefer shared libraries. You will also need the
public header files.
How does my project link libmonad_event.a
?
Here are three different options:
- Precompiled library - you could build the library yourself and store
the library file (and its headers) somewhere, then import it into your
build system manually. The SDK build system also creates a CMake "config"
file for use with
find_package
to help import it, if you are also using CMake
The other two options assume your project is also using CMake:
-
CMake subproject integration - your CMake project can include the SDK as a subproject. In this case, you download the source code of the execution repository as part of your own project, and call the CMake function:
add_subdirectory(<path-to-monad-repo>/category/event)This will add the SDK's library target (called
monad_event
) into your parent project. One way to add the SDK code to your project is to use a git submodule. Another way is to use CMake'sFetchContent
module. The three main differences between these approaches are:- By default,
FetchContent
will clone a git repository into your CMake build tree at build configuration time, whereas a git submodule integrates into your source tree at the repository level - With
FetchContent
, the version you check out is specified by theGIT_TAG
you specify in aCMakeLists.txt
file; forgit submodule
, it is managed via git commands - If the content you are fetching has its own CMake buildsystem (as the
C SDK does),
FetchContent
will automatically calladd_subdirectory
to add it to the current project; in the git submodule approach, you need to do this yourself
- By default,
-
CMake
ExternalProject
integration - CMake'sExternalProject
module is similar toFetchContent
, but is more isolated; this will build and install the SDK into a "staging" directory somewhere in your CMake build tree. This uses a completely separate CMake invocation, so it will not add the SDK's CMake project into your own. This means, for example, that you will not automatically have amonad_event
library target in your own CMake project -- you would need to create one as an imported target.ExternalProject
helps isolate your build system from the SDK's build system, ensuring that CMake configuration and variables from the SDK can't "leak" into your parent project
In this guide, we'll use the FetchContent
approach. This encapsulates the
entire process as a simple, all-in-one CMakeLists.txt
file, and we comment
that file to explain everything you need to know.
This is the clear best choice for our tiny "Getting started" example program,
but it might not be best for your real project. At the end of this guide, an
alternative method using find_package
is briefly shown.
Building the example program with FetchContent
Step 1: download the example program
First, create a new directory and download the example program source file
into it. We'll use the example directory ~/src/event-sdk-example-c
$ mkdir ~/src/event-sdk-example-c$ cd ~/src/event-sdk-example-c$ curl -O https://raw.githubusercontent.com/category-labs/monad/refs/heads/release/exec-events-sdk-v1.x/category/event/example/eventwatch.c
You should now have a file called eventwatch.c
in your new directory.
Step 2: add a CMakeLists.txt
build file
Create a CMakeLists.txt
file in the directory alongside eventwatch.c
and
copy these contents into it:
cmake_minimum_required(VERSION 3.21)
project(eventwatch LANGUAGES C)
## SDK setup#
include(FetchContent)
FetchContent_Declare(exec_events_c_sdk # The execution events C SDK is kept in the same git repository as the # execution daemon itself GIT_REPOSITORY git@github.com:category-labs/monad.git
# The latest version of the SDK is available on a special release branch # of the execution repository GIT_TAG release/exec-events-sdk-v1.x
# This will only download the SDK branch GIT_SHALLOW TRUE
# This will disable the checkout of all git submodules; they are needed # for the full execution daemon to build, but not the SDK GIT_SUBMODULES ""
# The top-level CMakeLists.txt builds the entire execution daemon; we don't # want that, so we specify SOURCE_SUBDIR to choose a CMakeLists.txt file # in a sudirectory to treat as the "top-level" file for the external # project; this only creates the monad_event library SOURCE_SUBDIR category/event)
# The SDK's build system also builds the same example we're building now, using# the same target name ('eventwatch'). This is done as a CI check to ensure# that the upstream project doesn't break the example program. We have to# disable it, because it will conflict with the eventwatch target we're going# to add below (CMake does not allow two targets with the same name)set(MONAD_EVENT_BUILD_EXAMPLE OFF CACHE INTERNAL "")
# This will download the source code and call add_subdirectory, which will add# the `monad_event` library target; this is the SDK target we need to linkFetchContent_MakeAvailable(exec_events_c_sdk)
## eventwatch example program target#
add_executable(eventwatch eventwatch.c)target_compile_options(eventwatch PRIVATE -Wall -Wextra -Wconversion -Werror)target_link_libraries(eventwatch PRIVATE monad_event)
Step 3: run CMake with a recent enough C compiler
The C SDK uses some recent features from C23, and requires either gcc-13 or
clang-19. If the default compiler found by CMake is too old, you will need
to specify an alternative C compiler by setting the CC
environment variable
or using a CMake toolchain file.
The default compiler chosen by CMake is usually the one reported by the output
of the command cc -v
.
CMake with make
and the default compiler:
$ cmake -S ~/src/event-sdk-example-c -B ~/src/event-sdk-example-c/build$ cd ~/src/event-sdk-example-c/build$ make
CMake with ninja
and an alternate compiler:
Here is another possible invocation, which sets an alternative C compiler using
the CC
environment variable and uses the Ninja
build tool:
$ CC=gcc-15 cmake -S ~/src/event-sdk-example-c -B ~/src/event-sdk-example-c/build -G Ninja$ cd ~/src/event-sdk-example-c/build$ ninja
The compilation should produce an executable file called eventwatch
. Try
running it with the -h
flag to print the help.
$ ./eventwatch -husage: eventwatch [-h] [<exec-event-ring>]
execution event observer example program
Options: -h | --help print this message
Positional arguments: <exec-event-ring> path of execution event ring shared memory file [default: monad-exec-events]
If all was successful, continue on to the last step in the guide or if you are also interested in Rust, build the Rust example program. You can also continue on to the next section, which shows a different way of integrating with the library.
Alternative: install locally, find with find_package
Now that you have seen the "all-in-one" tutorial, which explains the source
code organization, where the SDK's CMakeLists.txt
file is, etc., it is
easy to show an alternative kind of build system without as much commentary.
In this section we will:
-
Install the SDK to the temporary directory
/tmp/sdk-install-demo
, which will have the traditionalinclude
andlib
directory structure, but also alib/cmake/category-labs
directory containing the config files for CMake'sfind_package
-
Compile
eventwatch.c
again, this time usingfind_package
which will be instructed to look in/tmp/sdk-install-demo
Step 1: build and install libmonad_event.a
$ git clone -b release/exec-events-sdk-v1.x https://github.com/category-labs/monad.git \ ~/src/monad-exec-events-sdk$ cmake -S ~/src/monad-exec-events-sdk/category/event \ -B ~/build/monad-exec-events-sdk-v1-release -G Ninja \ -DCMAKE_INSTALL_PREFIX=/tmp/sdk-install-demo -DCMAKE_BUILD_TYPE=RelWithDebInfo$ cmake --build ~/build/monad-exec-events-sdk-v1-release$ cmake --install ~/build/monad-exec-events-sdk-v1-release
If all is successful, you should have a populated /tmp/sdk-install-demo
directory.
Step 2: create a new directory and download eventwatch.c
$ mkdir ~/src/event-sdk-example-c-find-package$ cd ~/src/event-sdk-example-c-find-package$ curl -O https://raw.githubusercontent.com/category-labs/monad/refs/heads/release/exec-events-sdk-v1.x/category/event/example/eventwatch.c
Step 3: create CMakeLists.txt
Add a CMakeLists.txt
file with this content:
cmake_minimum_required(VERSION 3.21)
project(eventwatch LANGUAGES C)
find_package(monad_exec_events_sdk REQUIRED PATHS /tmp/sdk-install-demo/lib/cmake/category-labs)
add_executable(eventwatch eventwatch.c)target_compile_options(eventwatch PRIVATE -Wall -Wextra -Wconversion -Werror)target_link_libraries(eventwatch PRIVATE monad_event)
Step 4: build and run
$ cmake -S . -B build -G Ninja$ cmake --build build$ build/eventwatch