---
title: "CMake"
canonical_url: https://developer.repebble.com/pebbleos/docs/development/build_system/cmake/
last_updated: 2026-10-21
sdk_version: 4.33.1
---
# CMake

Source: https://developer.repebble.com/pebbleos/docs/development/build_system/cmake/

The build model lives in `cmake/modules/`: every directory that contributes code declares a library, and the helpers below register what it needs. Nothing has to list the libraries; all of them end up in the single firmware image.

## Libraries

```
pbl\_library()pbl\_library\_sources(service.c util.c)
```

`pbl_library()`

Declare the library the following `pbl_library_*()` calls apply to, named after its directory (`fw/services/timeline` → `fw __services__ timeline`). The target is only created once it gets its first source, so a directory whose sources are all configured out contributes nothing.

`pbl_library_named(name)`

The same, with a name of its own, for a library something else refers to or a directory that builds more than one.

`pbl_library_kind(kind)`

`objects` (the default) links every object file. `stlib` builds a static library the linker pulls objects from on demand; use it for third-party code that ships more than the firmware references. Call it before the first source.

`pbl_library_sources(src...)`

Add sources. Each object is compiled with ` __FILE_NAME_LEGACY__ ` set to its source’s name, which asserts and log messages report.

`pbl_library_sources_ifdef(SYMBOL src...)`, `pbl_library_sources_ifndef(SYMBOL src...)`

Add sources when a Kconfig symbol is, or is not, set.

`pbl_library_sources_glob(pattern... [RECURSE] [EXCLUDE pattern...])`

Add the sources matching glob patterns, re-evaluated when the build regenerates. An `EXCLUDE` pattern is a glob relative to the directory (`voice/*.c`, `**/system_nrf*.c`) or a directory whose whole subtree is dropped (`vendor`, `ble_hrm/**`).

`pbl_library_include_directories(dir...)`, `pbl_library_compile_definitions(def...)`, `pbl_library_compile_options(opt...)`

Compile settings private to the current library.

`pbl_library_import(name path...)`

Link a prebuilt vendor archive, `lib<name>.a` found under one of the paths.

Dependencies between firmware libraries are not declared: they resolve at the final link.

## Global settings

Headers and defines are visible to every library, registered once next to what they expose:

```
pbl\_include\_directories(include)pbl\_compile\_definitions(FOO\_ENABLED=1)
```

`pbl_include_directories(dir...)`

Add header directories for every library. Relative paths resolve against the calling directory, and the matching build directory is added too, so generated headers are found next to their hand-written neighbours.

`pbl_compile_definitions(def...)`, `pbl_compile_options(opt...)`

Defines and compiler options for every library.

`pbl_include_directories_ifdef(SYMBOL dir...)`, `pbl_compile_definitions_ifdef(SYMBOL def...)`

The same, when a Kconfig symbol is set.

`pbl_link_options(opt...)`

Options for the firmware link, from anywhere in the tree.

Headers are global; there is no per-consumer opt-in. A library that is not always needed is gated behind a Kconfig symbol instead, and consumers `select` (or `imply`) it; see [Kconfig](https://developer.repebble.com/pebbleos/docs/development/build_system/kconfig.md).

## Conditional directories

Kconfig symbols are ordinary CMake variables, so directories and sources follow the configuration:

```
pbl\_add\_subdirectory\_ifdef(CONFIG\_MIC mic)pbl\_library\_sources\_ifdef(CONFIG\_ACCEL\_LSM6DSO lsm6dso/lsm6dso.c)
```

`pbl_add_subdirectory_ifdef(SYMBOL dir...)`

`add_subdirectory()` when a Kconfig symbol is set.

## Linker script

The master script, `kernel/pebbleos.ld`, includes the common sections in `kernel/linker/` and the fragments the architecture provides, such as the vector table. It goes through the C preprocessor with `autoconf.h`, so it can use Kconfig symbols, `#include` and `#if`. Libraries add to it at fixed hook points:

```
pbl\_linker\_sources(rom-start shell.ld)pbl\_library\_ramfunc(${ramfunc\_sources})
```

`pbl_linker_include_directories(dir...)`

Add directories to the master script’s include path. The architecture uses it for the fragments the master script includes by name.

`pbl_linker_sources(location file... [SORT_KEY key])`

Include linker script fragments at a hook point: `memory`, `rom-start`, `ram-sections`, `ramfunc` or `footer`. Fragments are included sorted by sort key, then by registration order.

`pbl_library_ramfunc(src...)`

Place the code and read-only data of some of the current library’s sources in `.ramfunc`, to run from RAM; see [Memory](https://developer.repebble.com/pebbleos/docs/kernel/memory.md). A no-op without `CONFIG_RAMFUNC`.

## Generated sources
`pbl_library_nanopb_sources(schema.proto...)`

Compile protobuf schemas with nanopb into the current library. A `<name>.options` file next to a schema tunes its generated C types.

`pbl_dynamic_resource(path ...)`

Add a resource produced by another build step to the system resource pack, after the ones the board’s resource maps declare.

Generated headers are produced by custom commands attached to the `pbl_generated_headers` target, which every library waits for. The generators live in `tools/cmake/`:

- `kconfig.py`: runs Kconfig and writes `.config`, `autoconf.h` and `config.cmake`.

- `resources.py`: turns the board’s resource maps into build rules, in batches so a few hundred resources do not cost a few hundred interpreter start-ups, and builds the resource pack and its tables.

- `generate.py`: the other source generators (version header, app registry, protocol endpoint table, applib allocator tables, log string hashing, stored apps).

- `firmware.py`: image steps, such as size checks, bundling and QEMU flash images.

## Native builds

The [native simulator](https://developer.repebble.com/pebbleos/docs/development/emulation/native_simulator.md) runs the firmware as a host program. The bottom halves of its drivers talk to the host and see none of the firmware’s headers:

`pbl_host_sources(src...)`, `pbl_host_include_directories(dir...)`, `pbl_host_compile_options(opt...)`

Sources, header directories and compile options of the host side.

## Unit tests

The unit tests are a separate CMake project, built for the host. Tests are declared with `pbl_clar_test()`; see [Unit tests](https://developer.repebble.com/pebbleos/docs/development/tests/unit.md).

Generated from PebbleOS [3a7b71785](https://github.com/coredevices/pebbleos/commit/3a7b71785fd439666c4a8bc116f561140e8dec01). This page is maintained in the pebbleos repository: [docs/development/build\_system/cmake.md](https://github.com/coredevices/pebbleos/blob/3a7b71785fd439666c4a8bc116f561140e8dec01/docs/development/build_system/cmake.md).
