ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

F´ 飞控软件框架 CMake 构建系统设计与实践指南

F´ 飞控软件框架 CMake 构建系统设计与实践指南 F´ 飞控软件框架 CMake 构建系统设计与实践指南【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址: https://gitcode.com/GitHub_Trending/fpr/fprime本指南以 F´F Prime开源仓库中的 CMake Build System 软件设计文档SDD 为核心系统讲解该飞行软件与嵌入式系统框架基于 CMake 的新一代构建系统从设计需求、操作概念、文件组织到核心函数架构。结合仓库源码你将掌握如何在项目中接入 F´ CMake 构建、以 out-of-source 方式构建部署与单个组件、注册新模块与可执行程序、编写单元测试目标以及为交叉编译添加新平台与工具链。1 引言为什么 F´ 需要一套新构建系统F´F Prime是一套面向飞行软件与嵌入式系统的开源框架其构建系统基于广受欢迎的开源工具 CMake。本篇 SDD 呈现了该构建系统的一组需求、操作概念operational concepts与候选设计candidate design。这套 CMake 构建系统的直接目的是取代 F´ 遗留的构建系统。遗留系统继承自 JPL 火星科学实验室Mars Science Laboratory任务创建至今已超过十年难以增强和维护。新的构建系统在设计之初即把易于扩展、易于使用、便于冻结与升级 F´ 核心作为核心诉求使 F´ 可以被当作只读的第三方输入sub-repo / sub-directory嵌入到各类任务项目中。从仓库看这套系统的实现分布在 cmake/ 目录下入口文件 FPrime.cmake 与 FPrime-Code.cmake、对外 API 定义于 cmake/API.cmake、模块构建核心函数位于 cmake/module.cmake平台与工具链支持分别位于 cmake/platform/ 与 cmake/toolchain/。1.1 术语定义这些术语在本文档中具有特定含义下表供读者快速参考术语含义Host用于构建代码的机器或体系结构。Target代码为之构建的机器或体系结构。Build Commands通过 make 系统运行的命令。Out-Of-Source Build在与源代码分离的目录中生成构建产物。Build Configurations不同的构建设置如不同目标、调试标志、不同部署通常彼此隔离。F´ ModuleF´ 组件Components与端口Ports的超集。Deployments包含框架、旨在作为 F´ 运行的二进制/可执行程序。Executable由构建系统构建的二进制不旨在作为 F´ deployment 运行。2 构建系统需求SDD 为 F´ 的 CMake 构建系统定义了一组可验证的顶层需求BUILD-01 ~ BUILD-24它们是理解系统各项设计决策的钥匙需求描述理由验证方法BUILD-01构建系统应支持在 Linux 和 Mac OS 上进行原生 F´ 构建。JPL 的 F´ 开发在 Linux 和 Mac OS 机器上进行单元测试BUILD-02构建系统应提供用于支持各种目标的模板。模板使添加新目标更容易。检查BUILD-03构建系统应提供一个交叉编译目标示例。交叉编译在 JPL 很常见必须作为示例提供。检查BUILD-04构建系统应支持自定义构建命令。自定义构建命令允许扩展构建系统。单元测试BUILD-05构建系统应支持单个组件、端口和拓扑的构建。编译特定组件可加快开发速度。单元测试BUILD-06构建系统应支持单元测试构建与运行系统检查。单元测试对正确的开发至关重要。单元测试BUILD-07构建系统应支持构建部署。部署必须能正确构建。单元测试BUILD-08构建系统不应要求所有模块按特定顺序构建。在必须显式排序时对 F´ 所有模块排序很困难。注意部署除外。单元测试BUILD-09构建系统应支持 F´ 的独立 out-of-source 构建。构建产物通常与源代码分离存放。检查BUILD-10构建系统应支持可执行程序和工具构建。并非所有 F´ 内容都是 deployment。检查BUILD-11构建系统应支持输出、头文件和库的安装与分发。二进制输出的交付对项目很重要。检查BUILD-12构建系统应支持用户可配置的构建如 debug、release 等。F´ 可能需要不同的构建变体用于调试。检查BUILD-13构建系统应易于使用包括添加新组件。F´ 现有构建系统学习曲线陡峭。检查BUILD-14构建系统不应明显缓慢。编译时间不可忽视。检查BUILD_15部署应独立配置依赖。当前 F´ 存在全局 make 配置目录问题。检查BUILD_16构建系统不应难以设置和配置。将现有 F´ 部署移植到新 make 系统不应耗费大量精力。检查BUILD_17构建系统应支持将 F´ 作为子仓库和子目录使用即使 F´ 是只读的。未来 F´ 使用应将核心视为输入。检查BUILD_18构建系统应支持将 F´ 核心构建为一组共享库。未来某些任务可能受益于共享的 F´ 核心。单元测试BUILD_19构建系统应支持执行单个、一组或全部基于 gtest 的单元测试。BUILD_20构建系统应支持执行 F´ Autocoder。单元测试BUILD_21构建系统应验证构建主机上是否安装了所需的编译器、链接器、库等。单元测试BUILD_22构建系统应支持执行单个、一组或全部 F´ Autocoder 及相关工具测试。BUILD_24构建系统应支持执行自定义 Autocoder。单元测试这些需求在实现中均有对应落点例如 BUILD-05 对应 cmake/API.cmake 中add_fprime_subdirectory与register_fprime_module的能力BUILD-06 / BUILD-19 对应register_fprime_ut与 cmake/target/ut.cmakeBUILD-20 / BUILD-24 对应 cmake/autocoder/ 目录下的 Autocoder 注册机制register_fprime_build_autocoderBUILD-21 对应 cmake/required.cmake 的依赖校验BUILD-18 则由BUILD_SHARED_LIBS选项配合配置库的-fPIC处理见 cmake/API.cmake 中register_fprime_config予以支持。3 操作概念在构建系统中F´ 作为项目的一个子目录被包含。所有适配adaptations都保持在 F´ 目录之外从而可以顺畅地对 F´ 核心进行更新、打补丁和版本冻结。这种模式也很容易扩展为把 F´ 当作库来链接。构建在用户提供的目录中执行用户创建一个命名目录用于构建然后向 cmake 提供配置参数以正确设置构建。F´ 作为子仓库的推荐操作模式如图所示适配层adapt与核心顶层目录fprime并排存在每次构建进入各自的独立构建目录每个配置一个目录。可通过以下命令完成设置。每种构建类型只需设置一次之后即可反复调用 makecd project mkdir build_config1 cd build_config1 cmake ../path-to-deployment -Dconfiguration settings当代码或 make 文件发生变化时可以随时通过以下命令重建该配置开发迭代期间可无限次执行cd project/build_config1 make3.1 单个组件的 out-of-source 构建在 out-of-source 构建中构建 F´ 内部的单个组件时需要进入平行构建结构中找到该组件的构建目录F´ 核心组件位于build/F-Prime/path-to-component适配组件通常位于build/adaptation/path-to-component。随后在该目录中执行 make 即可构建该组件。参考应用示例单独构建 F´ Svc 组件cd build_config1/F-Prime/Svc/FatalHandler make单独构建 Ref 组件cd build_config1/Ref/PingReceiver/ make这一布局由 cmake/API.cmake 中的add_fprime_subdirectory实现它自动把源码目录映射到指定的二进制目录binary_dir从而保证F-Prime/前缀下不会发生目标冲突并保持标准的 F´#include路径以仓库根为起点。核心包的二进制路径在 cmake/FPrime.cmake 的fprime_setup_included_code中被固定为${CMAKE_BINARY_DIR}/F-Prime/包名。3.2 添加新组件与拓扑新组件通过在组件所在目录创建CMakeLists.txt文件添加。该文件必须调用register_fprime_*系列函数之一并传入控制源列表的指令模块 CMakeLists.txtregister_fprime_module( AUTOCODER_INPUTS ${CMAKE_CURRENT_LIST_DIR}/PingReceiver.fpp SOURCES ${CMAKE_CURRENT_LIST_DIR}/PingReceiver.cpp )该文件必须通过add_subdirectory被加入某个父级 CMakeLists.txt。如果是新 F´ 组件通常加入该组件所在顶层的CMakeLists.txt例如fprime/Svc/CMakeLists.txt。这些子 CMakeLists.txt 作为便利层存在其本身被包含在FPrime.cmake中实际由 cmake/FPrime-Code.cmake 调用的fprime_setup_included_code统一处理。添加子目录示例add_fprime_subdirectory(${CMAKE_CURRENT_LIST_DIR}/PingReceiver/)注意这里推荐使用add_fprime_subdirectory而非原生add_subdirectory前者会自动推导二进制目录、维护FPRIME_CURRENT_MODULE上下文并注册模块元数据保证构建产物被干净地组织进各自命名前缀的目录见 cmake/API.cmake。从仓库的真实模块看一个带平台分支的完整组件示例位于 Svc/FatalHandler/CMakeLists.txt它依据FPRIME_USE_BAREMETAL_SCHEDULER与CMAKE_SYSTEM_NAME选择不同的实现源文件展示了AUTOCODER_INPUTSFPP 模型、SOURCESC 源码、HEADERS与DEPENDS如Os、Fw_Logger的实际用法。4 CMake 构建组织整个 CMake 系统由三部分组织而成由部署或可执行程序提供的入口文件Entry-point filesF´ 核心 CMake 支持文件用于构建核心与适配组件、拓扑的 CMakeLists.txt 文件。这三部分在下图中分别以黄色、绿色和蓝/橙色表示。F´ CMake 文件组织4.1 部署与可执行程序 CMake 文件这些文件由被构建的部署或可执行程序提供通常来自 F´ 的适配项目承担两个关键职能提供构建系统的入口包含标准 CMake 头cmake_minimum_required、project并包含 F´ CMake 支持文件FPrime.cmake同时还应包含FPrime-Code.cmake以引入 F´ 核心代码从而确保 CMake 就绪、所有 F´ 设置均被包含。示例CMake 头与 F´ 构建系统## # Section 1: Basic Project Setup # # This contains the basic project information. Specifically, a cmake version and # project definition. ## cmake_minimum_required(VERSION 3.18) project(FPrime-Ref C CXX) ## # Section 2: F´ Core # # This includes all of the F´ core components, and imports the make-system. F´ core # components will be placed in the F-Prime binary subdirectory to keep them from # colliding with deployment specific items. ## include(${CMAKE_CURRENT_LIST_DIR}/../cmake/FPrime.cmake) include(${CMAKE_CURRENT_LIST_DIR}/../cmake/FPrime-Code.cmake)包含所有含适配特定 F´ 组件的子目录这与下文描述的 F´ 核心子目录包含方式一致但代表适配特定组件。包含子目录## # Section 3: Components and Topology # # This section includes deployment specific directories. This allows use of non- # core components in the topology, which is also added here. ## # Add component subdirectories add_fprime_subdirectory(${CMAKE_CURRENT_LIST_DIR}/PingReceiver/) add_fprime_subdirectory(${CMAKE_CURRENT_LIST_DIR}/RecvBuffApp/) add_fprime_subdirectory(${CMAKE_CURRENT_LIST_DIR}/SendBuffApp/) add_fprime_subdirectory(${CMAKE_CURRENT_LIST_DIR}/SignalGen/)注意组件的输出被路由到构建目录中带命名前缀的子目录例如Ref前缀。仓库中 TestDeploymentsProject/Ref/CMakeLists.txt 正是这一模式的真实落地它先用多个add_fprime_subdirectory引入PingReceiver、RecvBuffApp、SendBuffApp、SignalGen、TypeDemo、DpDemo、BlockDriver、Top等自定义组件目录再通过register_fprime_deployment(SOURCES Main.cpp DEPENDS ${PROJECT_NAME}_Top)注册部署可执行文件最后用target_compile_options为部署可执行文件单独施加-Wall -Wextra -Werror -Wconversion等严格告警选项。4.2 F´ 核心 CMake 支持文件这些文件提供了用于制作组件、部署和模块的核心 CMake 函数。此外FPrime-Code.cmake包含组成 F´ 核心组件的子目录这样部署只需包含这一个 CMake 文件即可导入全部 F´。同时还包括自动化 Autocoder 功能、模块依赖管理以及其他各种实用工具的函数。因此部署和可执行程序在添加自定义组件时可以遵循与 F´ 核心组件相同的模式。从实现看cmake/FPrime.cmake 作为构建系统初始化入口依次包含utilities、options、sanitizers、flags、required、global_interface、config_assembler、fprime-util等模块随后加载platform、module、autocoder、target、API、sub-build、settingscmake/FPrime-Code.cmake 则调用fprime_setup_included_code()按Fpp default Fw Svc Os Drv CFDP Utils顺序把 F´ 核心包逐一加入构建树并挂载googletest仅当BUILD_TESTINGON时与STest测试支持库。4.3 F´ 核心与适配层 CMakeLists.txt 文件这些文件用于指定 F´ 组件、端口和拓扑的构建布局按如下层级结构组织。它们调用 F´ 的模块与部署函数来生成预期构建文件文件格式已在第 3.2 节描述将源文件与 Autocoder 输入链接到生成函数由这些函数把 F´ 组装起来。F´ CMakeLists 层级结构5 CMake 架构如前所述F´ 构建的大部分魔法被封装在 CMake 实用函数中。本节描述主要函数及其如何搭建 F´ 构建。该架构中有两个主要函数集合每个集合包含执行生成的原始函数generate_*与包裹它的 API 包装函数register_*register_fprime_module/generate_module生成库/模块构建文件与依赖。register_fprime_executable/generate_executable生成可执行程序构建与依赖。F´ CMake 架构注意颜色继承自上面各图——红色项为输出产物紫色项代表执行步骤。5.1 模块函数register_fprime_module 与 generate_module模块函数旨在由 F´ 目录创建库静态或共享。模块名由目录相对仓库根目录的路径决定例如Fw/Comp变为Fw_Comp并产出libFw_Comp.a该库被注册为 CMake 系统的输出。该库由SOURCES与AUTOCODER_INPUTS构建。可以使用DEPENDS指令提供特定依赖但仅在依赖无法通过模型依赖树自动检测到时才需要。系统为每个 Autocoder 输入文件注册对应的 Autocoder 生成步骤这些输入文件同时用于检测模块的全部依赖。普通源文件被提供给构建目录。这些步骤完成后CMake 生成宿主特定构建文件封装该模块的 Autocoder 调用、模块依赖与模块源文件。运行这些构建文件将生成模块库供部署链接阶段使用并注册到 CMake 中从而参与全局依赖汇总dependency roll-up。结合源码register_fprime_module实际委托给 cmake/API.cmake 中的register_fprime_library最终落入 cmake/module.cmake 的fprime__internal_add_build_target目标类型为Library时调用add_library并把AUTOCODER_INPUTS、SUPPLIED_SOURCES、SUPPLIED_DEPENDENCIES、FPRIME_TYPE等属性挂到目标上同时把目标追加到全局FPRIME_MODULES列表。它还支持旧式变量SOURCE_FILES、MOD_DEPS、HEADER_FILES的向后兼容传递方式。5.2 可执行程序函数register_fprime_executable 与 generate_executable可执行程序函数旨在创建可执行程序。这些可执行程序拥有具体源文件并自动把所有依赖汇总为一个全局有序依赖列表。可执行程序名取自创建 CMake 项目时定义的${PROJECT_NAME}或者必须显式提供单独名称。可执行程序可以提供SOURCES与DEPENDS、使用 Autocoding其他方面与上述模块类似唯一区别是构建产出为可执行程序。注意部署指定一个或多个可执行程序这些可执行程序成为依赖树的根。因此只生成所需的可执行程序、库与输出不会显式构建完整的 F´ 系统这使构建更高效。源码层面cmake/API.cmake 还提供了register_fprime_deployment——它构建的是依赖树根节点可执行目标可对其整体运行跨依赖树的 target例如为部署所用组件运行全部单元测试。Ref 部署即用${PROJECT_NAME}_Top作为其拓扑依赖。5.3 单元测试函数register_fprime_ut注册单元测试使用与上述相同的过程区别在于使用UT_SOURCE_FILES与UT_MOD_DEPS变量新式写法为SOURCES与DEPENDS。这使得同一文件既能定义模块/可执行程序又能定义单元测试而不会覆盖先前使用的变量。UT 构建示例mkdir build_ut cd build_ut cmake .. -DBUILD_TESTINGON make -j32实现上cmake/API.cmake 的register_fprime_ut仅在BUILD_TESTINGON且未关闭框架级 UT__FPRIME_NO_UT_GEN__时才创建目标类型为Unit Test最终映射到add_executable并支持INCLUDE_GTEST、UT_AUTO_HELPERS、TESTED_MODULE等扩展指令UT_AUTO_HELPERS会为目标设置FPRIME_UT_AUTO_HELPERS属性。框架在 cmake/FPrime.cmake 中通过FPRIME_ENABLE_FRAMEWORK_UTS开关控制是否生成框架自身的 UT各库还可通过FPRIME_ENABLE_LIB_UTS选项单独禁用。5.4 添加新平台CMake 允许在初始 CMake 步骤中指定工具链因此编译到新目标 OS 的核心操作简单如下cmake path to deployment -DCMAKE_TOOLCHAIN_FILEpath/to/toolchain_file然而仅以这种方式添加工具链会忽略 F´ 为编译平台特定代码提供的一些便利设置。因此用户还必须注册一个平台文件。在fprime/cmake/platform/目录中创建platform.cmake文件即可添加新平台具体步骤见 cmake/platform/README.md。工具链文件也可以添加到fprime/cmake/toolchain/目录以便随 F´ 一起提供简化新工具链的编译。仓库目前内置了 cmake/toolchain/ 下的aarch64-linux.cmake、arm-hf-linux.cmake、arm-sf-linux.cmake、raspberrypi.cmake、aarch64-clang-linux.cmake等交叉编译工具链以及用于指导新工具链编写的toolchain.cmake.template。从 cmake/platform/platform.cmake.template 可以清晰看到新建平台文件的五个步骤删除失败保护行模板开头的message(FATAL_ERROR ...)用于防止未填写的模板被当作有效平台文件使用复制后必须删除指定 OS 类型编译宏如add_definitions(-DTGT_OS_TYPE_PLATFORM-NAME)设置 C/CXX 编译标志set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} ...)切勿清空已有标志声明线程包通过FIND_PACKAGE(Threads REQUIRED)查找线程库使用裸机调度器FPRIME_USE_BAREMETAL_SCHEDULER时移除该行指定平台头文件目录包含PlatformTypes.h等系统头文件的目录Unix 系通常直接引入cmake/platform/unix/Platform/。平台文件的加载遵循明确规则若用户指定了工具链文件则使用${CMAKE_SYSTEM_NAME}.cmake由工具链设置通常为Linux、Darwin等否则 CMake 自动将${CMAKE_SYSTEM_NAME}设为主机系统名并加载对应平台文件如在 Linux 上构建使用Linux.cmake。6 将 F´ 构建系统接入你的项目结合上述设计一个典型的部署项目接入方式如下保持 F´ 只读将 F´ 作为子目录/子模块放入项目所有适配代码放在 F´ 目录之外对应 BUILD-17编写入口 CMakeLists.txtcmake_minimum_required(VERSION 3.18)project(...)随后includeF´ 的FPrime.cmake与FPrime-Code.cmake注册项目与组件调用register_fprime_project()可在 cmake/API.cmake 中查看其定义再用add_fprime_subdirectory引入组件目录组件目录内用register_fprime_module声明模块注册部署/可执行程序用register_fprime_deployment或register_fprime_executable声明依赖树根节点配置与构建为每种配置平台/调试/单元测试创建一个构建目录执行一次 cmake 配置之后反复make即可。# 部署构建示例 mkdir build_linux cd build_linux cmake .. make # 单元测试构建示例 mkdir build_ut cd build_ut cmake .. -DBUILD_TESTINGON make -j32 ctestF´ 还提供了fprime-util便捷封装见 cmake/fprime-util.cmake与settings.ini配置参考 TestDeploymentsProject/settings.ini其中通过default_cmake_options设置FPRIME_ENABLE_FRAMEWORK_UTSOFF等选项可进一步简化日常开发流程。7 小结F´ 的 CMake 构建系统以入口文件 核心支持文件 模块 CMakeLists.txt三层结构为骨架通过register_fprime_module/register_fprime_executable/register_fprime_ut等 API 封装把 Autocoder 代码生成、依赖检测与全局依赖汇总、out-of-source 构建、单元测试与跨平台交叉编译统一到一套易于扩展的机制中。它既满足了 JPL 任务对 Linux/macOS 原生构建与交叉编译的实际需求也通过平台文件与工具链模板让第三方项目可以低成本地把 F´ 作为只读核心嵌入自己的构建体系。对开发者而言掌握 cmake/API.cmake 中公开的register_*系列接口即可熟练地为 F´ 添加组件、部署与新平台。【免费下载链接】fprimeF´ - A flight software and embedded systems framework项目地址: https://gitcode.com/GitHub_Trending/fpr/fprime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表