Skip to content

Using nRF5 CMake

Borys Jeleński edited this page Jul 9, 2020 · 8 revisions

This section provides a more in-depth insight into the inner workings of nRF5 CMake. It's supposed to help you understand how it works so you can make the best use of it. Before proceeding, make sure to read the Getting started section.

The subjects covered in this section are not meant to be read in any particular order. Feel free to learn only what you think is important for you at the moment.

nRF5 SDK libraries

As we already mentioned in the Getting started section, every library found in the nRF5 SDK is represented as a CMake target. This allows us to model dependecies between libraries by taking advantage of CMake property propagation system. Each library target defines its source files, include directories required to build it and use it, compile defines and other libraries it depends on.

We currently use two types of CMake targets:

  • OBJECT - for libraries that consists of at least one source file
  • INTERFACE - for libraries that are header-only

You can read about different CMake target types in CMake documentation: cmake-buildsystem(7).

Here is a sample library definition of the widely-used Application Timer found in the nrf5_app.cmake script in the cmake directory:

# Application Timer
add_library(nrf5_app_timer OBJECT EXCLUDE_FROM_ALL
  "${NRF5_SDK_PATH}/components/libraries/timer/app_timer.c"
)
target_include_directories(nrf5_app_timer PUBLIC
  "${NRF5_SDK_PATH}/components/libraries/timer"
)
target_link_libraries(nrf5_app_timer PUBLIC
  nrf5_app_scheduler
  nrf5_app_util_platform
  nrf5_delay
  nrf5_nrfx_hal
)

Using nRF5 libraries in your project

Being CMake targets, the nRF5 SDK libraries can be linked to your executable target by using the standard target_link_libraries() clause. However, you might remember that in our BSP Example in the Getting started section we used the nrf5_target_link_libraries() function that is provided with the nRF5 CMake like this:

nrf5_target_link_libraries(nrf5_example_bsp PRIVATE
  nrf5_app_error
  nrf5_log
  nrf5_log_backend_serial
  nrf5_log_backend_uart
  nrf5_log_default_backends
  nrf5_bsp
)

If you simply replace the nrf5_target_link_libraries() with the target_link_libraries() here, you will notice that you can still successfully generate input files for the build system, but upon running the build system you'll see a staggering number of undefined reference linker errors.

The reason for that is due to the fact that in the nRF5 CMake, many of the nRF5 libraries are represented as CMake OBJECT libraries and the CMake documentation on Object Libraries states that when linking a target that uses object libraries as dependencies (directly or inderectly), only object files from the object libraries that this target directly depends upon are linked. The nrf5_target_link_libraries() function works in this case because as part of the nRF5 CMake, we track the dependecies between nRF5 SDK libraries and whenever a library is specified within nrf5_target_link_libraries(), the other libraries it depends on are automatically added as if they were specified directly. In case of duplicates, they are removed.

This provides a convenient mechanism for adding libraries to the project. In a way, it attempts to overcome the limitations of CMake itself. However, when compared to the standard target_link_libraries(), the nrf5_target_link_libraries() function has some drawbacks. The problem is that in nRF5 SDK, whether a library actually depends on some other library is determined by the project configuration - the SDK configuration file (sdk_config.h) more specifically. For instance, the app_timer library only depends on the app_scheduler library if the following definitions is present in the sdk_config.h:

#define APP_TIMER_CONFIG_USE_SCHEDULER 1

A drawback of using the nrf5_target_link_libraries() function for adding a library X is that it will add all the other libraries the library X possibly depends on regardless of the current project configration and whether those libraries are actually used. This may seem harmless and it often is but in some cases, it might cause you trouble compiling the project. That is because such unused libraries will still be compiled and if their configuration is missing in the SDK configuration file, the compilation may fail. As a rule of thumb, in order to mitigate this, we recommend that you use the SDK configuration files found in the config/<nrf52_target>/config directory of the nRF5 SDK as your starting point when configuring a new project. They are supposed to contain all the configuration entries for all the libraries available in the current version of the SDK.

On the other hand, using the standard CMake target_link_libraries() clause allow for a fine control over which libraries are pulled into the project so your specify only those libraries that are actually used. We generally recommend using the nrf5_target_link_libraries() for nRF52 beginners. More experienced nRF52 developers may prefer using the standard target_link_libraries() to have more control over the libraries added to the project.

Clone this wiki locally