> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monad.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# 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.

<Info>
  If you are not familiar with CMake, you may want to read CMake's
  ["Using Dependencies Guide"](https://cmake.org/cmake/help/latest/guide/using-dependencies/index.html)
  first
</Info>

### Where is the SDK source code?

The execution event C SDK lives in the same source code repository as the
execution daemon ([here](https://github.com/category-labs/monad)), in the
subdirectory [`category/event`](https://github.com/category-labs/monad/tree/main/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 can my code use `libmonad_event.a`?

Here are three different options:

1. **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`](https://cmake.org/cmake/help/latest/command/find_package.html)
   to help import it, if you are also using CMake

The other two options assume your project is also using CMake:

2. **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 CMake project. One way to add the SDK code to your build is to use a
   [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules).
   Another way is to use CMake's
   [`FetchContent`](https://cmake.org/cmake/help/latest/module/FetchContent.html)
   module. The three main differences between these approaches are:

   1. 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
   2. With `FetchContent`, the version you check out is specified by the
      `GIT_TAG` you specify in a `CMakeLists.txt` file; for `git submodule`,
      it is managed via git commands
   3. If the content you are fetching has its own CMake buildsystem (as the
      C SDK does), `FetchContent` will automatically call `add_subdirectory`
      to add it to the current project; in the git submodule approach, you
      need to do this manually

3. **CMake `ExternalProject` integration** - CMake's
   [`ExternalProject`](https://cmake.org/cmake/help/latest/module/ExternalProject.html)
   module is similar to `FetchContent`, 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 a `monad_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: install prerequisite development packages

In addition to CMake (at least version 3.23) and git, we will need a recent C
compiler and two third-party libraries. We will also use
[curl](https://curl.se/docs/manpage.html)
to download some files.

#### Required 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](https://cmake.org/cmake/help/latest/variable/CMAKE_TOOLCHAIN_FILE.html).

The default compiler chosen by CMake is usually the one reported by the output
of the command `cc -v`. If you need to use a different one, you can use the
bash syntax `VAR=VALUE <command>` for setting an environment variable in the
scope of the following command, e.g.:

```shell theme={null}
$ CC=gcc-15 cmake <args>
```

#### Required C++ compiler

C++ is not used in this example, but there are some optional C++ components in
the CMake project. Consequently, you must have a C++ compiler installed or the
CMake configuration step will fail.

<Info title="C++ in the SDK">
  The SDK is written in pure C, except for some C++ header files that can be used
  to "pretty-print" event types using the `<format>` library. These are not part
  of the example program, and they require full C++23 support for formatting
  ranges  (the `__cpp_lib_format_ranges` feature test macro) which were added to
  libstdc++ in gcc version 15.2. This is a recent release: the first time gcc 15.2
  appeared in the Ubuntu package repositories was in Ubuntu 25.10.

  You can also use clang with libc++, the LLVM implementation of the C++ standard
  library, which has had range formatting support since version 19. An example of
  building a C++ program with clang-19 is shown as the optional last step of the
  "Getting started" guide, when we build the `monad-event-cli` utility.
</Info>

#### Required third-party libraries

| Requirement  | Ubuntu package name | What is it used for?                                                                                        |
| ------------ | ------------------- | ----------------------------------------------------------------------------------------------------------- |
| zstd library | libzstd-dev         | Snapshot event ring files are compressed with zstd; `libzstd` is needed to decompress them                  |
| libhugetlbfs | libhugetlbfs-dev    | `libhugetlbfs` is used to locate the optimal hugetlbfs mount point to create event ring shared memory files |

`libzstd` is a hard requirement; `libhugetlbfs` is optional but is expected
by default on Linux. It can be turned off manually by setting the CMake option
`MONAD_EVENT_USE_LIBHUGETLBFS` to `OFF`.

#### macOS compatiblity

Real-time data requires a Linux host (because the execution daemon itself
does), but you can compile and run the example program on historical data
using macOS. This allows you to "try before you buy" and explore the SDK
before going through the trouble of setting up a Monad node on Linux.

In this case, you do not need `libhugetlbfs` (which is a Linux-only library),
but you will need a recent XCode toolchain, the `libzstd` compression
library, and CMake. The last two are not included in the default XCode
development tools, so you'll probably want to use
[Homebrew](https://brew.sh/) or
[MacPorts](https://www.macports.org/)
to install these onto your system. As for XCode itself, any version since
16.3 should work, but it has only been tested with version 23.2 (the real
requirement is for Apple Clang 17).[^1]

[^1]: "Apple Clang" is based on, but different than, vanilla LLVM
    [Clang](https://clang.llvm.org/). Apple Clang 17 is based on LLVM/Clang 19,
    thus the discrepancy in the requirements table.

### Step 2: 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`

```shell theme={null}
$ mkdir -p ~/src/event-sdk-example-c
$ cd ~/src/event-sdk-example-c
$ curl -O https://raw.githubusercontent.com/category-labs/monad/refs/tags/release/exec-events-sdk-v1.1/category/event/example/eventwatch.c
```

You should now have a file called `eventwatch.c` in your new directory.

### Step 3: add a `CMakeLists.txt` build file

Create a `CMakeLists.txt` file in the directory alongside `eventwatch.c` and
copy these contents into it:

```CMakeLists.txt theme={null}
cmake_minimum_required(VERSION 3.23)

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 https://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.1

    # 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 link
FetchContent_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 4: run CMake and build

#### CMake with `make` and the default compiler:

```shell theme={null}
$ 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](https://ninja-build.org/)
build tool:

```shell theme={null}
$ CC=clang-19 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.

```shell theme={null}
$ ./eventwatch -h
usage: 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 [next step in the guide](/execution-events/getting-started/snapshot)
or if you are also interested in Rust, build the
[Rust example program](/execution-events/getting-started/rust). The Rust example program prints more
interesting output than the C version, thanks to Rust's
[`#[derive(Debug)]`](https://doc.rust-lang.org/rust-by-example/hello/print/print_debug.html)
attribute, so the "Getting started" experience is better in Rust. You can do
an equivalent thing in C++ by using the aformentioned `std::formatter`
specializations, but they're not in the tutorial.

You can also continue on to the next section on this page, which shows a
different way of integrating with the C 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 traditional `include` and `lib` directory structure, but
  also a `lib/cmake/category-labs` directory containing the config files for
  CMake's `find_package`

* Compile `eventwatch.c` again, this time using `find_package` which will be
  instructed to look in `/tmp/sdk-install-demo`

### Step 1: build and install `libmonad_event.a`

```shell theme={null}
$ git clone -b release/exec-events-sdk-v1.1 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 \
  -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`

```shell theme={null}
$ mkdir -p ~/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/tags/release/exec-events-sdk-v1.1/category/event/example/eventwatch.c
```

### Step 3: create `CMakeLists.txt`

Add a `CMakeLists.txt` file with this content:

```CMakeLists.txt theme={null}
cmake_minimum_required(VERSION 3.23)

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

```shell theme={null}
$ cmake -S . -B build
$ cmake --build build
$ build/eventwatch -h
```
