I am trying to create a project for an embedded device that is based on Zephyr ecosystem. The problem I struggle with is that it forces single-executable project. It uses CMake.
The way how Zephyr suggest to create the main CMakeLists.txt
(from its documentation):
cmake_minimum_required(VERSION 3.16)
# This is project-dependent
set(ZEPHYR_TOOLCHAIN_VARIANT "gnuarmemb" CACHE STRING "Informs Zephyr about the toolchain used")
set(GNUARMEMB_TOOLCHAIN_PATH ${TOOLCHAIN_PATH} CACHE PATH "Informs Zephyr where the GNU toolchain is located")
set(BOARD nucleo_l432kc CACHE STRING "Board specification for Zephyr")
find_package(Zephyr 2.4.99)
project(MyProject)
# "app" is defined within the call to "find_package(Zephyr ...)".
# This is necessary - to provide at least one source file.
target_sources(app PRIVATE dummy.cpp)
I would like to have more than one executable (for embedded-tests targets and extra executables like long running tests of sensors, etc.) in this environment. I could create multiple projects for that but that is tedious solution, because it decentralizes the build system and makes it really inconvenient in terms of use (defining multiple build directories for CMake, all that manual checking for out-of-date builds that are easy to forget).
Other solution I came into was to use ExternalProject
mixed with some CMake code to define an executable target. That kind’a works but it’s very inefficient. The function looked like that:
function(CreateFirmwareExecutableTarget name toolchain_path)
set(external_proj_name SubBuild_${name})
set(src_dir ${CMAKE_SOURCE_DIR}/zephyr)
set(install_dir ${CMAKE_CURRENT_BINARY_DIR}/zephyr_${name})
include(ExternalProject)
ExternalProject_Add(${external_proj_name}
SOURCE_DIR ${src_dir}
INSTALL_DIR ${install_dir}
CMAKE_ARGS -DTOOLCHAIN_PATH=${toolchain_path}
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
BUILD_ALWAYS YES
)
add_executable(${name} IMPORTED)
set_target_properties(${name} PROPERTIES
IMPORTED_LOCATION ${install_dir}/bin/zephyr.elf)
endfunction()
In the zephyr
directory I had then CMakeLists.txt
similar to the one in the first listing. That worked, but that is clunky. The Zephyr sources will be build from scratch for each executable. This is very ineffective.
(In the listing above, there is no custom code (like my project’s own code) linked to the executable. That is not yet solved but the solution for that is easy and is not in the scope of this question).
Zephyr doesn’t give any CMake API to create more executables, so I opt for a CMake solution.
One solution which I came up with was to scrape the properties from the app
executable (like the static library targets linked to it, sources, link flags, etc.) and create a library target to which targets created with add_executable
would link to. That is equivalent to creating a library target counterpart for an executable.
The question is whether am I missing something here? How can I accomplish the task to create a multi-executable project for that environment in non-hacky way using CMake?