我正在尝试为基于 Zephyr 生态系统的嵌入式设备创建一个项目。我遇到的问题是它强制执行单可执行项目。它使用 CMake。
Zephyr 建议创建 main 的方式CMakeLists.txt
(来自其文档):
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)
我想在这个环境中拥有多个可执行文件(用于嵌入式测试目标和额外的可执行文件,如传感器的长时间运行测试等)。最重要的是我想拥有“app”目标在其他可执行目标中的所有符号。我可以为此创建多个项目,但这是一个乏味的解决方案,因为它分散了构建系统并使其在使用方面非常不方便(为 CMake 定义多个构建目录,所有手动检查过时的构建都很容易忘记)。
我遇到的其他解决方案是ExternalProject
与一些 CMake 代码混合使用来定义可执行目标。那种工作,但它是非常低效的。函数看起来像这样:
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()
在zephyr
目录中,我CMakeLists.txt
与第一个清单中的目录类似。那行得通,但那很笨拙。Zephyr 源代码将为每个可执行文件从头开始构建。这是非常无效的。
(在上面的清单中,没有链接到可执行文件的自定义代码(如我的项目自己的代码)。这还没有解决,但解决方案很简单,不在这个问题的范围内)。
Zephyr 没有提供任何 CMake API 来创建更多可执行文件,因此我选择了 CMake 解决方案。
理想情况下,Zephyr 应该定义静态库目标,我可以使用add_executable
命令创建的目标链接到这些目标。但不幸的是,事实并非如此。
我想出的一种解决方案是从app
可执行文件中抓取属性(如链接到它的静态库目标、源、链接标志等),并创建一个库目标,创建的目标add_executable
将链接到该库目标。这相当于为可执行文件创建对应的库目标。
问题是我是否在这里遗漏了什么?如何使用 CMake 以非 hacky 的方式完成为该环境创建多可执行项目的任务?