根据 CMakeLists.txt 模板为平台创建列表文件 - FreeRTOS
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

根据 CMakeLists.txt 模板为平台创建列表文件

CMakeLists.txt 模板文件是随 FreeRTOS 提供的,它位于 /vendors/vendor/boards/board/CMakeLists.txt 中。

CMakeLists.txt 模板文件由以下四个部分组成:

可以按照说明编辑列表文件的这四个部分,以与平台相匹配。您可以参考 /vendors 中其他符合条件的供应商主板的 CMakeLists.txt 文件以作为示例。

整个文件中会调用以下两个主要函数:

afr_set_board_metadata(name value)

此函数为 FreeRTOS 控制台定义元数据。该函数是在 /tools/cmake/afr_metadata.cmake 中定义的。

afr_mcu_port(module_name [<DEPENDS> [targets...]])

此函数定义与 FreeRTOS 模块(即库)关联的可移植层目标。此函数采用以下名称形式创建 CMake GLOBAL INTERFACE IMPORTED 目标:AFR:module_name::mcu_port。如果使用 DEPENDS,则其他目标通过 target_link_libraries 链接在一起。该函数是在 /tools/cmake/afr_module.cmake 中定义的。

FreeRTOS 控制台元数据

模板文件的第一部分定义用于在 FreeRTOS 控制台中显示主板信息的元数据。使用函数 afr_set_board_metadata(name value) 定义模板中列出的每个字段。下表提供了每个字段的说明。

字段名称 值说明
ID 主板的唯一 ID。
DISPLAY_NAME 要显示在 FreeRTOS 控制台上的主板的名称。
DESCRIPTION 用于 FreeRTOS 控制台的主板的简短说明。
VENDOR_NAME 主板供应商的名称。
FAMILY_NAME 主板 MCU 系列的名称。
DATA_RAM_MEMORY 主板 RAM 的大小,后跟单位缩写。例如,使用 KB 表示千字节。
PROGRAM_MEMORY 主板程序内存的大小,后跟单位缩写。例如,使用 MB 表示兆字节。
CODE_SIGNER 用于 OTA 更新的代码签名平台。使用 AmazonFreeRTOS-Default 作为 SHA256 散列算法和 ECDSA 加密算法。如果要使用不同的代码签名平台,请联系我们
SUPPORTED_IDE 主板支持的 IDE 的 ID 列表,用分号分隔。
IDE_ID_NAME 支持的 IDE 的名称。用 SUPPORTED_IDE 字段中列出的 IDE 的 ID 替换 ID
IDE_ID_COMPILER 对于所支持的 IDE,支持的编译器的名称列表,用分号分隔。用 SUPPORTED_IDE 字段中列出的 IDE 的 ID 替换 ID

编译器设置

模板文件的第二部分为主板定义编译器设置。要创建具有编译器设置的目标,可调用 afr_mcu_port 函数,用 compiler 代替 module_name,以创建名为 AFR::compiler::mcu_portINTERFACE 目标。内核会公开链接到此 INTERFACE 目标,以便编译器设置能以传递的方式填充到所有模块。

在列表文件的此部分中,使用标准的内置 CMake 函数定义编译器设置。在定义编译器设置时,请遵循以下最佳实践:

  • 使用 target_compile_definitions 提供编译定义和宏。

  • 使用 target_compile_options 提供编译器标记。

  • 使用 target_include_directories 提供包含目录。

  • 使用 target_link_options 提供链接器标记。

  • 使用 target_link_directories 提供链接器搜索目录。

  • 使用 target_link_libraries 提供链接的库。

注意

如果在其他位置定义编译器设置,则不需要重复文件此部分中的信息。相反,使用 DEPENDS 调用 afr_mcu_port,可从其他位置引入目标定义。

例如:

# your_target is defined somewhere else. It does not have to be in the same file. afr_mcu_port(compiler DEPENDS your_target)

使用 DEPENDS 调用 afr_mcu_port 时,它会调用 target_link_libraries(AFR::module_name::mcu_port INTERFACE your_targets),这会填充所需 AFR::compiler::mcu_port 目标的编译器设置。

使用多个编译器

如果主板支持多个编译器,则可使用 AFR_TOOLCHAIN 变量动态选择编译器设置。该变量设置为使用的编译器的名称,该名称应该与位于 /tools/cmake/toolchains 中的工具链文件的名称相同。

例如:

if("${AFR_TOOLCHAIN}" STREQUAL "arm-gcc") afr_mcu_port(compiler DEPENDS my_gcc_settings). elseif("${AFR_TOOLCHAIN}" STREQUAL "arm-iar") afr_mcu_port(compiler DEPENDS my_iar_settings). else() message(FATAL_ERROR "Compiler ${AFR_TOOLCHAIN} not supported.") endif()

高级编译器设置

如果要设置更高级的编译器设置,如设置基于编程语言的编译器标记,或更改不同版本的设置及调试配置,则可使用 CMake 生成器表达式。

例如:

set(common_flags "-foo") set(c_flags "-foo-c") set(asm_flags "-foo-asm") target_compile_options( my_compiler_settings INTERFACE $<$<COMPILE_LANGUAGE:C>:${common_flags} ${c_flags}> # This only have effect on C files. $<$<COMPILE_LANGUAGE:ASM>:${common_flags} ${asm_flags}> # This only have effect on ASM files. )

CMake 在读取列表文件时,不会在配置阶段评估 CMake 生成器表达式。它们会在生成阶段进行评估,当 CMake 完成列表文件的读取,并为目标构建系统生成构建文件时。

FreeRTOS 可移植层

模板文件的第三部分为 FreeRTOS(即库)定义所有可移植层目标。

必须使用 afr_mcu_port(module_name) 函数,为计划实施的每个 FreeRTOS 模块定义可移植层目标。

只要 afr_mcu_port 调用所创建目标的名称提供了构建相应 FreeRTOS 模板所需的信息,即可使用任何所需的 CMake 函数。

afr_mcu_port 函数采用以下名称形式创建 GLOBAL INTERFACE 库目标AFR::module_name::mcu_port。作为 GLOBAL 目标时,可以在 CMake 列表文件中进行引用。作为 INTERFACE 目标时,不能构建为独立的目标或库,但可以编译到相应的 FreeRTOS 模块。作为 IMPORTED 目标时,其名称在目标名称中包含命名空间 (::),例如,AFR::kernel::mcu_port

默认情况下,无相应可移植层目标的模块处于禁用状态。如果运行 CMake 配置 FreeRTOS,而未定义任何可移植层目标,那么应该看到以下输出:

FreeRTOS modules: Modules to build: Disabled by user: Disabled by dependency: kernel, posix, pkcs11, secure_sockets, mqtt, ... Available demos: Available tests:

使用移植层目标更新 CMakeLists.txt 文件时,将启用相应的 FreeRTOS 模块。您还应该能构建其依赖性要求随后得以满足的任何 FreeRTOS 模块。例如,如果已启用 MQTT 库,则 Device Shadow 库也会启用,因为它唯一的依赖项是 MQTT 库。

注意

FreeRTOS 内核依赖性是最低要求。如果 FreeRTOS 内核依赖性未满足,CMake 配置将失败。

设置内核移植目标

要创建内核移植目标 AFR::kernel::mcu_port,可使用模块名称 kernel 调用 afr_mcu_port。调用 afr_mcu_port 时,为 FreeRTOS 可移植层和驱动程序代码指定目标。创建目标后,可以提供依赖性信息以及 FreeRTOS 可移植层和驱动程序代码信息,供目标使用。

按照说明设置内核移植目标。

设置内核移植目标

  1. 为驱动程序代码创建目标。

    例如,可以为驱动程序代码创建 STATIC 库目标:

    add_library(my_board_driver STATIC ${driver_sources}) # Use your compiler settings target_link_libraries( my_board_driver PRIVATE AFR::compiler::mcu_port # Or use your own target if you already have it. # PRIVATE ${compiler_settings_target} ) target_include_directories( my_board_driver PRIVATE "include_dirs_for_private_usage" PUBLIC "include_dirs_for_public_interface" )

    或者,可以为驱动程序代码创建 INTERFACE 库目标:

    # No need to specify compiler settings since kernel target has them. add_library(my_board_driver INTERFACE ${driver_sources})
    注意

    INTERFACE 库目标无构建输出。如果使用的是 INTERFACE 库目标,则驱动程序代码将编译到内核库。

  2. 配置 FreeRTOS 可移植层:

    add_library(freertos_port INTERFACE) target_sources( freertos_port INTERFACE "${AFR_MODULES_DIR}/freertos_kernel/portable/GCC/ARM_CM4F/port.c" "${AFR_MODULES_DIR}/freertos_kernel/portable/GCC/ARM_CM4F/portmacro.h" "${AFR_MODULES_DIR}/freertos_kernel/portable/MemMang/heap_4.c" ) target_include_directories( freertos_port INTERFACE "${AFR_MODULES_DIR}/freertos_kernel/portable/GCC/ARM_CM4F" "${include_path_to_FreeRTOSConfig_h} )
    注意

    要配置 FreeRTOS 可移植层,也可以在 AFR::kernel::mcu_port 目标中直接指定这些源文件及其包含目录。

  3. 创建内核可移植层目标:

    # Bring in driver code and freertos portable layer dependency. afr_mcu_port(kernel DEPENDS my_board_driver freertos_port) # If you need to specify additional configurations, use standard CMake functions with # AFR::kernel::mcu_port as the target name. target_include_directories( AFR::kernel::mcu_port INTERFACE "${additional_includes}" # e.g. board configuration files ) target_link_libraries( AFR::kernel::mcu_port INTERFACE "${additional_dependencies}" )
  4. 要测试列表文件和配置,可以编写一个简单的应用程序以使用 FreeRTOS 内核移植。有关使用 CMake 开发和构建 FreeRTOS 应用程序的更多信息,请参阅 使用 CMake 构建 FreeRTOS

  5. 创建演示之后,将 add_executabletarget_link_libraries 调用添加到列表文件,并将内核编译为静态库,以检验内核可移植层的配置是否正确。

    add_executable( my_demo main.c ) target_link_libraries( my_demo PRIVATE AFR::kernel )

设置 FreeRTOS 模块的移植目标

为内核添加可移植层目标之后,可以为其他 FreeRTOS 模块添加可移植层目标。

例如,为 Wi-Fi 模块添加可移植层:

afr_mcu_port(wifi) target_sources( AFR::wifi::mcu_port INTERFACE "${AFR_MODULES_DIR}/vendors/vendor/boards/board/ports/wifi/iot_wifi.c" )

此 Wi-Fi 模块可移植层示例只有一个基于驱动程序代码的实施文件。

如果要为 FreeRTOS 安全套接字模块添加可移植层,则该模块依赖于 TLS。这会使其可移植层目标较 Wi-Fi 模块的可移植层目标略微复杂。FreeRTOS 提供了基于 mbedTLS 的默认 TLS 实施,您可以与之链接:

afr_mcu_port(secure_sockets) target_sources( AFR::secure_sockets::mcu_port INTERFACE ${portable_layer_sources} ) target_link_libraries( AFR::secure_sockets::mcu_port AFR::tls )

在此示例代码中,标准 CMake 函数 target_link_libraries 声明安全套接字可移植层依赖于 AFR::tls

可以通过使用目标名称 AFR::module_name 来引用所有 FreeRTOS 模块。例如,可以使用相同的语法声明对 FreeRTOS-Plus-TCP 的依赖性:

target_link_libraries( AFR::secure_sockets::mcu_port AFR::freertos_plus_tcp AFR::tls )
注意

如果平台自己处理 TLS,则可直接使用驱动程序代码。如果将驱动程序代码直接用于 TLS,则无需调用 target_link_libraries,因为所有 FreeRTOS 模块隐式依赖于包含驱动程序代码的内核。

由于所有非内核 FreeRTOS 模块隐式依赖于内核,因此其移植层不需要将内核指定为依赖项。不过,POSIX 模块定义为可选的内核模块。如果要使用 POSIX,则必须将其显式包括在内核可移植层中。例如:

# By default, AFR::posix target does not expose standard POSIX headers in its public # interface, i.e., You need to use "freertos_plus_posix/source/FreeRTOS_POSIX_pthread.c" instead of "pthread.h". # Link to AFR::use_posix instead if you need to use those headers directly. target_link_libraries( AFR::kernel::mcu_port INTERFACE AFR::use_posix )

FreeRTOS 演示和测试

模板文件的最后一个部分定义 FreeRTOS 的演示和测试目标。对于满足依赖性要求的每个演示和测试,会自动创建 CMake 目标。

在本节中,使用 add_executable 函数定义可执行目标。如果要编译测试,则使用 aws_tests 作为目标名称。如果要编译演示,则使用 aws_demos。可能还需要提供其他项目设置,如链接器脚本和构建后命令。例如:

if(AFR_IS_TESTING) set(exe_target aws_tests) else() set(exe_target aws_demos) endif() set(CMAKE_EXECUTABLE_SUFFIX ".elf") add_executable(${exe_target} "${board_dir}/application_code/main.c")

随后调用 target_link_libraries,将可用的 CMake 演示或测试目标链接到可执行目标。

注意

仍需要修改 aws_demos/config_files/aws_demo_config.haws_tests/config_files/aws_test_runner_config.h,以启用演示和测试。

运行构建后命令

有关运行构建后命令的信息,请参阅 add_custom_command。使用第二个签名。例如:

# This should run an external command "command --arg1 --arg2". add_custom_command( TARGET ${exe_target} POST_BUILD COMMAND "command" "--arg1" "--arg2" )
注意

CMake 支持许多常见的、独立于平台的操作,如创建目录、复制文件等。有关 CMake 命令行操作的更多信息,请参阅 CMake 命令行工具参考。可以使用内置变量 ${CMAKE_COMMAND},从 CMake 列表文件引用 CMake 命令行工具。