CMake / West for Zephyr / Nordic nRF Connect SDK

CMake Details


CMake Tutorial

CMake is used to build your application together with the Zephyr kernel. A CMake build is done in two stages. The first stage is called configuration. During configuration, the CMakeLists.txt build scripts are executed. After configuration is finished, CMake has an internal model of the Zephyr build, and can generate build scripts that are native to the host platform.

All the CMakefile information can be found at Zephyr Project Documentation.

CMake supports generating scripts for several build systems, but only Ninja and Make are tested and supported by Zephyr. After configuration, you begin the build stage by executing the generated build scripts. These build scripts can recompile the application without involving CMake following most code changes. However, after certain changes, the configuration step must be executed again before building. The build scripts can detect some of these situations and reconfigure automatically, but there are cases when this must be done manually.

Zephyr uses CMake’s concept of a ‘target’ to organize the build. A target can be an executable, a library, or a generated file. For application developers, the library target is the most important to understand. All source code that goes into a Zephyr build does so by being included in a library target, even application code.

Library targets have source code, that is added through CMakeLists.txt build scripts like this:

target_sources(app PRIVATE src/main.c)

In the above CMakeLists.txt, an existing library target named app is configured to include the source file src/main.c. The PRIVATE keyword indicates that we are modifying the internals of how the library is being built. Using the keyword PUBLIC would modify how other libraries that link with app are built. In this case, using PUBLIC would cause libraries that link with app to also include the source file src/main.c, behavior that we surely do not want. The PUBLIC keyword could however be useful when modifying the include paths of a target library.

Application CMakeLists.txt

Every application must have a CMakeLists.txt file. This file is the entry point, or top level, of the build system. The final zephyr.elf image contains both the application and the kernel libraries.

This section describes some of what you can do in your CMakeLists.txt. Make sure to follow these steps in order.

Step 1
If you only want to build for one board, add the name of the board configuration for your application on a new line. For example:

set(BOARD nrf52840_pca10056)

Refer to Supported Boards for more information on available boards.

The Zephyr build system determines a value for BOARD by checking the following, in order (when a BOARD value is found, CMake stops looking further down the list):

  • Any previously used value as determined by the CMake cache takes highest precedence. This ensures you don’t try to run a build with a different BOARD value than you set during the build configuration step.
  • Any value given on the CMake command line (directly or indirectly via west build) using -DBOARD=YOUR_BOARD will be checked for and used next.
  • If an environment variable BOARD is set, its value will then be used.
  • Finally, if you set BOARD in your application CMakeLists.txt as described in this step, this value will be used.

Step 2:

If your application uses a configuration file or files other than the usual prj.conf (or prj_YOUR_BOARD.conf, where YOUR_BOARD is a board name), add lines setting the CONF_FILE variable to these files appropriately. If multiple filenames are given, separate them by a single space or semicolon. CMake lists can be used to build up configuration fragment files in a modular way when you want to avoid setting CONF_FILE in a single place. For example:

set(CONF_FILE "fragment_file1.conf")
list(APPEND CONF_FILE "fragment_file2.conf")

See The Initial Configuration for more information.

Step 3:

If your application uses a devicetree overlay file or files other than the usual <board>.overlay, add lines setting the DTC_OVERLAY_FILE variable to these files appropriately.

More details are available below in Devicetree Overlays.

Step 4:

If your application has its own kernel configuration options, create a Kconfig file in the same directory as your application’s CMakeLists.txt.

See the Kconfig section of the manual for detailed Kconfig documentation.

An (unlikely) advanced use case would be if your application has its own unique configuration options that are set differently depending on the build configuration.

If you just want to set application specific values for existing Zephyr configuration options, refer to the CONF_FILE description above.

Structure your Kconfig file like this:

# SPDX-License-Identifier: Apache-2.0

mainmenu "Your Application Name"

# Your application configuration options go here

# Sources Kconfig.zephyr in the Zephyr root directory.
# Note: All 'source' statements work relative to the Zephyr root directory (due
# to the $srctree environment variable being set to $ZEPHYR_BASE). If you want
# to 'source' relative to the current Kconfig file instead, use 'rsource' (or a
# path relative to the Zephyr root).
source "Kconfig.zephyr"

Step 5:

Now include the mandatory boilerplate that integrates the application with the Zephyr build system on a new line, after any lines added from the steps above:

include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)

Step 6:

Now add any application source files to the ‘app’ target library, each on their own line, like so:

target_sources(app PRIVATE src/main.c)

Below is a simple example CMakeList.txt:

set(BOARD nrf52840_pca10056)

include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)

target_sources(app PRIVATE src/main.c)

If you have used the SHIELD such as LCD screen (,

Set -DSHIELD=ssd1306_128x64 when you invoke west build. For example:

# From the root of the zephyr repository
west build -b nrf52840_pca10056 samples/gui/lvgl -- -DSHIELD=ssd1306_128x64

It can modify the CMakeLists.txt directly to add the SHIELD and OVERLAY_FILE.

Use the command line to compile the hex

west build -b nrf52840_pca10056 

Clean the compiled project folder

west build -t clean

Forcing CMake to Run Again

To force a CMake re-run, use the --cmake (or --c) option:

west build -c

To set the build directory explicitly, use --build-dir (or -d):

west build -b <BOARD> --build-dir path/to/build/directory

Setting Source and Build Directories

To set the application source directory explicitly, give its path as a positional argument:

west build -b <BOARD> path/to/source/directory

To set the build directory explicitly, use --build-dir (or -d):

west build -b <BOARD> --build-dir path/to/build/directory

To change the default build directory from build, use the build.dir-fmt configuration option. This lets you name build directories using format strings, like this:

west config build.dir-fmt "build/{board}/{app}"

With the above, running west build -b reel_board samples/hello_world will use build directory build/reel_board/hello_world. See Configuration Options for more details on this option.

Verbose Builds

To print the CMake and compiler commands run by west build, use the global west verbosity option, -v:

west -v build -b reel_board samples/hello_world

Program the compiled hex on target board

west flash

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.