0

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. Most important thing is that I want to have all the symbols which the "app" target has in the other executable targets. 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.

Ideally Zephyr should define static library targets to which I could link to with my targets created with add_executable command. But unfortunately this is not the case.

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?

K. Koovalsky
  • 596
  • 4
  • 17
  • from the question title my first thought was you could simply copy the 'exe multiple times :) – StPiere Jan 15 '21 at 10:13
  • I also was thinking about that as well. But then how to link the custom static libraries to each copied executable? – K. Koovalsky Jan 15 '21 at 10:16
  • You could also use just [GNU make](https://www.gnu.org/software/make/) -read its documentation!- and write your `Makefile` by hand using [GNU emacs](https://www.gnu.org/software/emacs).... You could also use [ninja](http://ninja-build.org/) – Basile Starynkevitch Jan 15 '21 at 10:18
  • @BasileStarynkevitch I have appended "using CMake" to the last question ;) – K. Koovalsky Jan 15 '21 at 10:20
  • Indeed, but it seems that in your context, writing a simple `Makefile` could be simpler. If you want more, consider also [GNU automake](https://www.gnu.org/software/automake/) and [GNU autoconf](https://www.gnu.org/software/autoconf/). Notice that the Linux [kernel](http://kernel.org/) is using similar approaches. BTW, `cmake` has [some forum](https://discourse.cmake.org/faq) – Basile Starynkevitch Jan 15 '21 at 10:21
  • Can't you just add another `add_executable` call to your CMakeLists.txt? – arrowd Jan 15 '21 at 11:00
  • I can but I need all the symbols that are linked to the `app` target - especially the linker script, all the compilation flags for cross compiling, targets for drivers. I have updated the question to include those details. – K. Koovalsky Jan 15 '21 at 11:08

0 Answers0