CMake / West for Zephyr / Nordic nRF Connect SDK

In this blog, I would like to describe more details on the cmake and west which are the tools in the Nordic Connect SDK. For example, I would cover :

  • Zephyr’s Build System
  • How to configure the cmake file with difference parameter
  • How to use the West to build / flash the application

All the materials in this blog are mainly referred to zephyr project official documentation.

https://docs.zephyrproject.org/latest/application/index.html

Zephyr’s Build System

Zephyr’s build system is based on CMake.

The build system is application-centric, and requires Zephyr-based applications to initiate building the kernel source tree. The application build controls the configuration and build process of both the application and Zephyr itself, compiling them into a single binary.

Zephyr’s base directory hosts Zephyr’s own source code, its kernel configuration options, and its build definitions.

The files in the application directory link Zephyr with the application. This directory contains all application-specific files, such as configuration options and source code.

An application in its simplest form has the following contents:

<home>/app
├── CMakeLists.txt
├── prj.conf
└── src

These contents are:

  • CMakeLists.txt: This file tells the build system where to find the other application files, and links the application directory with Zephyr’s CMake build system. This link provides features supported by Zephyr’s build system, such as board-specific kernel configuration files, the ability to run and debug compiled binaries on real or emulated hardware, and more.
  • Kernel configuration files: An application typically provides a Kconfig configuration file (usually called prj.conf) that specifies application-specific values for one or more kernel configuration options. These application settings are merged with board-specific settings to produce a kernel configuration.See Kconfig Configuration below for more information.
  • Application source code files: An application typically provides one or more application-specific files, written in C or assembly language. These files are usually located in a sub-directory called src.

Once an application has been defined, you can use CMake to create project files for building it from a directory where you want to host these files. This is known as the build directory. Application build artifacts are always generated in a build directory; Zephyr does not support “in-tree” builds.

The following sections describe how to create, build, and run Zephyr applications, followed by more detailed reference material.

Creating an Application

Step 1:

Create an application directory on your workstation computer, outside of the Zephyr base directory. Usually you’ll want to create it somewhere under your user’s home directory.

For example, in a Unix shell or Windows cmd.exe prompt, navigate to where you want to create your application, then enter:

mkdir app

Step 2:

It’s recommended to place all application source code in a subdirectory named src. This makes it easier to distinguish between project files and sources.

Continuing the previous example, enter:

cd app
mkdir src

Step 3:

Place your application source code in the src sub-directory. For this example, we’ll assume you created a file named src/main.c.

Step 4:

Create a file named CMakeLists.txt in the app directory with the following contents:

# Boilerplate code, which pulls in the Zephyr build system.
cmake_minimum_required(VERSION 3.13.1)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(my_zephyr_app)

# Add your source file to the "app" target. This must come after
# the boilerplate code, which defines the target.
target_sources(app PRIVATE src/main.c)

cmake_minimum_required() is also invoked from boilerplate.cmake. The most recent of the two versions will be enforced by CMake.

Step 5:

Set Kconfig configuration options. See Kconfig Configuration.

Step 6:

Optionally, you can also configure any devicetree overlays needed by your application. See Devicetree Overlays below for details.

Building an Application

The Zephyr build system compiles and links all components of an application into a single application image that can be run on simulated hardware or real hardware.

Like any other CMake-based system, the build process takes place in two stages. First, build files (also known as a buildsystem) are generated using the cmake command-line tool while specifying a generator. This generator determines the native build tool the buildsystem will use in the second stage. The second stage runs the native build tool to actually build the source files and generate an image. To learn more about these concepts refer to the CMake introduction in the official CMake documentation.

Although the default build tool in Zephyr is west, Zephyr’s meta-tool, which invokes cmake and the underlying build tool (ninja or make) behind the scenes, you can also choose to invoke cmake directly if you prefer. On Linux and macOS you can choose between the make and ninja generators (i.e. build tools), whereas on Windows you need to use ninja, since make is not supported on this platform. For simplicity we will use ninja throughout this guide, and if you choose to use west build to build your application know that it will default to ninja under the hood.

As an example, let’s build the Hello World sample for the nrf52840_pca10056:

Using west:

west build -b nrf52840_pca10056 samples/hello_world

Using CMake and ninja:

cmake -B build -GNinja -DBOARD=nrf52840_pca10056 samples/hello_world

# Now run ninja on the generated build system:
ninja -C build

If desired, you can build the application using the configuration settings specified in an alternate .conf file using the CONF_FILE parameter. These settings will override the settings in the application’s .config file or its default .conf file. For example:

Using west:

west build -b <board> -- -DCONF_FILE=prj.alternate.conf

Using CMake and ninja:

mkdir build && cd build
cmake -GNinja -DBOARD=<board> -DCONF_FILE=prj.alternate.conf ..
ninja

Rebuilding an Application

Application development is usually fastest when changes are continually tested. Frequently rebuilding your application makes debugging less painful as the application becomes more complex. It’s usually a good idea to rebuild and test after any major changes to the application’s source files, CMakeLists.txt files, or configuration settings.

Sometimes the build system doesn’t rebuild the application correctly because it fails to recompile one or more necessary files. You can force the build system to rebuild the entire application from scratch with the following procedure:

Step 1:

Open a terminal console on your host computer, and navigate to the build directory <home>/app/build.

Step 2:

Enter one of the following commands, depending on whether you want to use west or cmake directly to delete the application’s generated files, except for the .config file that contains the application’s current configuration information.

west build -t clean

or

ninja clean

Alternatively, enter one of the following commands to delete all generated files, including the .config files that contain the application’s current configuration information for those board types.

west build -t pristine

or

ninja pristine

If you use west, you can take advantage of its capability to automatically make the build folder pristine whenever it is required.

Step 3

Rebuild the application normally following the steps specified in Building an Application above.

Important Build System Variables

You can control the Zephyr build system using many variables. This section describes the most important ones that every Zephyr developer should know about.

Note

The variables BOARDCONF_FILE, and DTC_OVERLAY_FILE can be supplied to the build system in 3 ways (in order of precedence):

  • As a parameter to the west build or cmake invocation via the -D command-line switch
  • As Environment Variables.
  • As a set(<VARIABLE> <VALUE>) statement in your CMakeLists.txt
  • ZEPHYR_BASE: Sets the path to the directory containing Zephyr, which is needed by the build system’s boilerplate file. This is an environment variable set by the zephyr-env.sh script on Linux/macOS or zephyr-env.cmd on Windows, as you learned when getting started with Zephyr in Build the Blinky Application. You can also set ZEPHYR_BASE explicitly, but then you won’t get the other features provided by those scripts.
  • BOARD: Selects the board that the application’s build will use for the default configuration. See Supported Boards for built-in boards, and Board Porting Guide for information on adding board support.
  • CONF_FILE: Indicates the name of one or more configuration fragment files. Multiple filenames can be separated with either spaces or semicolons. Each file includes Kconfig configuration values that override the default configuration values.See The Initial Configuration for more information.
  • DTC_OVERLAY_FILE: Indicates the name of one or more devicetree overlay files. Multiple filenames can be separated with either spaces or semicolons. Each file includes devicetree values that override the default DT values. See Devicetree Overlays below for details on devicetree overlays, and Devicetree for an overview on devicetree and Zephyr.
  • ZEPHYR_MODULES: A CMake list containing absolute paths of additional directories with source code, Kconfig, etc. that should be used in the application build. See Modules (External projects) for details.

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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.