ament_cmake用户文档

[需手动修复的语法]ament _ cmake是ROS 2中基于CMake的包的构建系统 (特别是,它将用于大多数 (如果不是全部的话) C/cmake项目)。它是一组增强CMake并为包作者添加便利功能的脚本。了解 CMake will be very helpful, an official tutorial can be found here 的基本知识。 [待校准@5760]

基础知识

可以在命令行上使用 ros2 pkg create <package_name> 生成基本的CMake大纲。然后将基本构建信息收集在两个文件中: package.xmlCMakeLists.txtpackage.xml 必须包含所有依赖项和一些元数据,以允许colcon为您的包找到正确的构建顺序,在CI中安装所需的依赖项,并为 bloom 版本提供信息。 CMakeLists.txt 包含构建和打包可执行文件和库的命令,并将成为本文档的主要重点。 [待校准@5763]

基本项目大纲 [待校准@5764]

基本轮廓 CMakeLists.txt 的ament包包含: [待校准@5765]

cmake_minimum_required(VERSION 3.5)
project(my_project)

ament_package()

[需手动修复的语法] project 的参数将是包装名称,并且必须与 package.xml 中的包装名称相同。 [待校准@5766]

项目设置由 ament_package() 完成,每个包必须进行一次调用。 ament_package() 安装 package.xml ,将包注册到ament索引,并为CMake安装配置 (可能还有目标) 文件,以便其他使用 find_package 的包可以找到它。因为 ament_package()CMakeLists.txt 收集了很多信息,所以它应该是你 CMakeLists.txt 的最后一次调用。虽然可调用的 ament_package() 通过调用的 install 功能复制文件和目录,简单只是保持 ament_package() 最后调用。 [待校准@5767]

[需手动修复的语法]``ament_package`` can被给予额外的论据: [待校准@5768]

  • 包装的客户应该可以得到``CONFIG_EXTRAS``: a list of CMake files (.cmake or .cmake.in templates expanded by configure_file())。有关何时使用这些参数的示例,请参阅 “添加源文件 _. For more information on how to use template files, see `the official documentation ” 中的讨论。 [待校准@5769]

  • 后来包括``CONFIG_EXTRAS_POST``: same as CONFIG_EXTRAS, but the order in which the files are added differs. While CONFIG_EXTRAS files are included before the files generated for the ament_export_* calls the files from CONFIG_EXTRAS_POST are。 [待校准@5770]

除了添加到 ament_package ,您还可以添加到变量 “${PROJECT_NAME}_ CONFIG _ EXTRAS `` and `` ${PROJECT_NAME}_ CONFIG_EXTRAS_POST”,具有相同的效果。唯一的区别是文件的添加顺序,总顺序如下: [待校准@5771]

  • files added by CONFIG_EXTRAS

  • 通过附加到 “${PROJECT_NAME}_ CONFIG_EXTRAS” 来添加的文件 [待校准@5773]

  • 通过附加到 “${PROJECT_NAME}_ CONFIG_EXTRAS_POST” 来添加的文件 [待校准@5774]

  • files added by CONFIG_EXTRAS_POST

添加文件和标题 [待校准@5776]

构建的主要目标有两个: 分别由 add_libraryadd_executable 构建的库和可执行文件。 [待校准@5777]

随着头文件的分离和在C/C ++ 中的实现,并不总是需要将两个文件都添加为 add_library / add_executable 的参数。 [待校准@5778]

提出以下最佳实践: [待校准@5779]

  • 如果您正在构建一个库,请将客户端应该可以使用的所有标头放入 include 文件夹的子目录中,该文件夹的名称类似于包,而所有其他文件 (不应导出的 .c/.cpp 文件和头文件) 都在 src 文件夹中。 [待校准@5780]

  • 只有cpp文件在对 add_libraryadd_executable 的调用中被明确引用。 [待校准@5781]

  • 允许通过 [待校准@5782]

target_include_directories(my_target
  PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>)

安装时,这会添加文件夹 “${CMAKE_CURRENT_SOURCE_DIR}/包含 `` to the public interface during build time and all files in the include folder (relative to `` ${CMAKE_INSTALL_DIR}” 中的所有文件。 [待校准@5783]

原则上,使用生成器表达式不是必要如果文件夹调用ed include 和顶级关于 ''${CMAKE_CURRENT_SOURCE_DIR} `` and `` ${CMAKE_INSTALL_DIR}'', 但很普通。 [待校准@5784]

添加依赖项 [待校准@5785]

有两种方法可以将包与新的依赖项链接起来。 [待校准@5786]

第一个也是推荐的方法是使用ament宏观 ament_target_dependencies 。例如,假设我们想将 my_target 与线性代数库特征3联系起来。 [待校准@5787]

find_package(Eigen3 REQUIRED)
ament_target_dependencies(my_target Eigen3)

它包括项目要正确找到的必要的标头和库及其依赖项。它还将确保在使用覆盖工作区时正确排序所有依赖项的包含目录。 [待校准@5788]

第二种方法是使用 target_link_libraries[待校准@5789]

在现代CMake中推荐的方法是只使用目标,导出和链接目标。CMake目标是命名空间,类似于C++。例如, Eigen3 定义了目标 “本征3:: 本征”。 [待校准@5790]

至少直到 Crystal Clemmys 目标名称不支持 ament_target_dependencies 微距。有时需要调用 target_link_libaries CMake函数。在本征3的示例中,调用应该看起来像 [待校准@5791]

find_package(Eigen3 REQUIRED)
target_link_libraries(my_target Eigen3::Eigen)

这还将包括必要的标头、库及其依赖项,但与 ament_target_dependencies 相比,在使用覆盖工作区时,它可能无法正确排序依赖项。 [待校准@5792]

注解

它不应该必须 find_package 库不明确需要但依赖另一个依赖明确需要。如果是这种情况,请针对相应的包提交错误。 [待校准@5793]

构建一个库

构建可重用的库时,需要导出一些信息,以便下游包轻松使用。 [待校准@5795]

ament_export_targets(my_libraryTargets HAS_LIBRARY_TARGET)
ament_export_dependencies(some_dependency)

install(
  DIRECTORY include/
  DESTINATION include
)

install(
  TARGETS my_library
  EXPORT my_libraryTargets
  LIBRARY DESTINATION lib
  ARCHIVE DESTINATION lib
  RUNTIME DESTINATION bin
  INCLUDES DESTINATION include
)

在这里,我们假设文件夹 include 包含需要导出的标题。请注意,没有必要将所有标头放入单独的文件夹中,只需要将那些标头包含在客户端中。 [待校准@5796]

下面是上面片段中发生的事情: [待校准@5797]

  • [需手动修复的语法] ament_export_targets 宏观出口CMake的目标。这是允许库的客户端使用 “target_link_library (客户端my_library::my_library)” 语法所必需的。[需手动修复的语法] ament_export_targets 可以在安装调用中采用名为 EXPORT 的任意目标列表和一个附加选项 HAS_LIBRARY_TARGET ,这将潜在的库添加到环境变量中。 [待校准@5798]

  • [需手动修复的语法] ament_export_dependencies 将依赖项导出到下游包。这是必要的,这样库的用户也不必为这些依赖项调用 find_package[待校准@5799]

  • 第一个 install 命令安装应该对客户端可用的头文件。 [待校准@5800]

警告

从CMake子目录调用 ament_export_targetsament_export_dependencies 或其他ament命令将无法正常工作。这是因为CMake子目录无法在调用 ament_package 的父范围内设置必要的变量。 [待校准@5801]

  • 最后一个大型安装命令安装库。档案和库文件将被导出到lib文件夹,运行时二进制文件将被安装到bin文件夹,并且安装的标题的路径是 include[待校准@5802]

注解

Windows dll被视为运行时工件,并安装到 RUNTIME DESTINATION 文件夹中。因此,即使在基于Unix的系统上开发库时,也建议不要忽略 RUNTIME 安装。 [待校准@5803]

  • 关于 include directory ,安装命令只向CMake添加信息,它实际上并没有安装包含文件夹。如上所述,通过 install(DIRECTORY <dir> DESTINATION <dest>) 复制标题来完成。 [待校准@5804]

  • 安装调用的 EXPORT 符号需要额外注意: 它为 my_library 目标安装CMake文件。它的名字和 ament_export_targets 的论点一模一样,可以像图书馆一样命名。然而,这将禁止使用 ament_target_dependencies 的方式包括你的图书馆。为了实现充分的灵活性,建议在出口目标之前添加类似 <target>Targets 的内容。 [待校准@5805]

  • 所有安装路径都是相对于 CMAKE_INSTALL_PREFIX 的,它已经由colcon/ament正确设置 [待校准@5806]

有两个附加功能可以使用,但对于基于目标的安装来说是多余的: [待校准@5807]

ament_export_include_directories(include)
ament_export_libraries(my_library)

第一个宏标记导出的包含目录的目录 (这是由目标 install 调用中的 INCLUDES DESTINATION 实现的)。第二个宏标记已安装库的位置 (这是通过对 ament_export_targets 的调用中的 HAS_LIBRARY_TARGET 参数完成的)。 [待校准@5808]

对于非目标导出,有些宏可以采用不同类型的参数,但是由于现代Make推荐的方法是使用目标,因此我们在这里不介绍它们。这些选项的文档可以在源文件本身中找到。 [待校准@5809]

编译器和链接器选项 [待校准@5810]

ROS 2目标编译器符合C++ 14 C99标准直到至少 Crystal Clemmys 。较新的版本可能是未来的目标,并被引用为 here 。因此,通常设置相应的CMake标志: [待校准@5811]

if(NOT CMAKE_C_STANDARD)
  set(CMAKE_C_STANDARD 99)
endif()
if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()

为了保持代码干净,编译器应该对有问题的代码发出警告,并且这些警告应该被修复。 [待校准@5812]

建议至少覆盖以下警告级别: [待校准@5813]

  • 对于Visual Studio,保留默认的 W1 警告 [待校准@5814]

  • 对于GCC和Clang: -Wall -Wextra -Wpedantic 是必需的, -Wshadow -Werror 是可取的 (后者会出现警告错误)。 [待校准@5815]

尽管现代CMake建议在目标基础上添加编译器标志,即调用 [待校准@5816]

target_compile_options(my_target PRIVATE -Wall)

目前建议使用目录级函数 add_compile_options(-Wall) ,以免代码中包含所有可执行文件和测试的基于目标的编译选项。 [待校准@5817]

在Windows上构建库 [待校准@5818]

由于Linux、Mac和Windows都是官方支持的平台,为了产生最大的影响,任何包都应该建立在Windows上。Windows库格式强制执行符号可见性: 应从客户端使用的每个符号都必须由库显式导出 (数据符号需要隐式导入)。 [待校准@5819]

为了使其与Clang和GCC构建兼容,建议使用 the GCC wiki 中的逻辑。将其用于调用ed my_library 的包: [待校准@5820]

target_compile_definitions(my_library PRIVATE "MY_LIBRARY_BUILDING_LIBRARY")

测试和脱毛 [待校准@5825]

为了将测试与使用colcon构建库分开,将所有调用s包装到linters和测试中,条件如下: [待校准@5826]

if(BUILD_TESTING)
  find_package(ament_cmake_gtest REQUIRED)
  ament_add_gtest(<tests>)
endif()

林廷 [待校准@5827]

建议使用来自 ament_lint_auto 的组合调用: [待校准@5828]

find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()

这将运行 package.xml 中定义的林特。建议使用由 ament_lint_common 包装定义的一组短吻鳄。包括在那里的单个漆器,以及它们的功能,可以在 ament_lint_common docs 中看到。 [待校准@5829]

[需手动修复的语法]ament提供的短吻鳄也可以单独添加,而不是运行 ament_lint_auto 。如何做到这一点的一个例子可以在 ament_cmake_lint_cmake documentation 中找到。 [待校准@5830]

测试 [待校准@5831]

[需手动修复的语法]Ament包含CMake宏来简化GTests的设置。呼叫: [待校准@5832]

find_package(ament_cmake_gtest)
ament_add_gtest(some_test <test_sources>)

添加GTest。然后,这是一个常规目标,可以与其他库 (例如项目库) 链接。这些宏具有其他参数: [待校准@5833]

  • [需手动修复的语法]``APPEND_ENV``:附加环境变量。例如,您可以通过调用以下命令添加到ament前缀路径: [待校准@5834]

find_package(ament_cmake_gtest REQUIRED)
ament_add_gtest(some_test <test_sources>
  APPEND_ENV PATH=some/addtional/path/for/testing/resources)
  • [需手动修复的语法]``APPEND_LIBRARY_DIRS``: append libraries so that they can be found by the linker at runtime. This can be achieved by setting environment variables like PATH on Windows and LD_LIBRARY_PATH onLinux,但这使得调用平台特定。 [待校准@5835]

  • ENV: set environment variables (same syntax as APPEND_ENV). [待校准@5836]

  • [需手动修复的语法]``TIMEOUT``:将测试超时设置为秒。GTests的默认值为60秒。例如: [待校准@5837]

ament_add_gtest(some_test <test_sources> TIMEOUT 120)
  • [需手动修复的语法]``SKIP_TEST``:跳过此测试 (将在控制台输出中显示为 "passed" )。 [待校准@5838]

  • [需手动修复的语法]``SKIP_LINKING_MAIN_LIBRARIES``:与GTest没有联系。 [待校准@5839]

  • [需手动修复的语法]``WORKING_DIRECTORY``:设置了测试的工作目录。 [待校准@5840]

否则,默认的工作目录是 CMAKE_SOURCE_DIR ,它将被评估为顶级 CMakeLists.txt 的目录。 [待校准@5841]

同样,有一个CMake宏来设置GTest,包括GMock: [待校准@5842]

find_package(ament_gmock REQUIRED)
ament_add_gmock(some_test <test_sources>)

它具有与 ament_add_gtest 相同的附加参数。 [待校准@5843]

延伸ament [待校准@5844]

可以向 ament_cmake 注册其他宏/函数,并以多种方式扩展它。 [待校准@5845]

向ament添加函数/宏 [待校准@5846]

扩展ament通常意味着你希望有一些功能可供其他包使用。向客户包提供宏的最佳方式是向ament注册。 [待校准@5847]

这可以通过附加 “${PROJECT_NAME}_ CONFIG_EXTRAS” 变量来完成,该变量由 ament_package() 通过 [待校准@5848]

list(APPEND ${PROJECT_NAME}_CONFIG_EXTRAS
  path/to/file.cmake"
  other/pathto/file.cmake"
)

或者,您可以直接将文件添加到 ament_package() 调用中: [待校准@5849]

ament_package(CONFIG_EXTRAS
  path/to/file.cmake
  other/pathto/file.cmake
)

添加到扩展点 [待校准@5850]

除了具有可在其他包中使用的功能的简单文件之外,您还可以向ament添加扩展名。这些扩展是使用定义扩展点的函数执行的脚本。ament扩展最常见的用例可能是注册rosidl消息生成器: 当编写生成器时,您通常希望使用生成器生成所有消息和服务,而无需修改消息/服务定义包的代码。通过将发电机注册为 rosidl_generate_interfaces 的延伸,这是可能的。 [待校准@5851]

作为示例,请参见 [待校准@5852]

ament_register_extension(
  "rosidl_generate_interfaces"
  "rosidl_generator_cpp"
  "rosidl_generator_cpp_generate_interfaces.cmake")

哪个寄存器宏观 rosidl_generator_cpp_generate_interfaces.cmakerosidl_generator_cpp 的扩展点 rosidl_generate_interfaces 。当执行扩展点时,这将在此处触发脚本 rosidl_generator_cpp_generate_interfaces.cmake 的执行。特别是,每当函数 rosidl_generate_interfaces 被执行时,这将调用生成器。 [待校准@5853]

除了 rosidl_generate_interfaces 之外,发电机最重要的扩展点是 ament_package ,它将简单地用 ament_package() 调用执行脚本。在注册re源文件时,此扩展点非常有用 (见下文)。 [待校准@5854]

[需手动修复的语法]``ament_register_extension`` is函数采用三个参数: [待校准@5855]

  • extension_point: The name of the extension point (most of the time this will be one of ament_package or rosidl_generate_interfaces) [待校准@5856]

  • [需手动修复的语法]``package_name``:包含CMake文件的包的名称 (即文件写入项目的项目名称) [待校准@5857]

  • [需手动修复的语法]``cmake_filename``:CMake文件时执行扩展点运行 [待校准@5858]

注解

可以以类似于 ament_packagerosidl_generate_interfaces 的方式定义自定义扩展点,但这几乎没有必要。 [待校准@5859]

添加扩展点 [待校准@5860]

很少,定义一个新的ament延伸点可能会很有趣。 [待校准@5861]

扩展点可以在宏中注册,以便在调用相应的宏时执行所有扩展。为此: [待校准@5862]

  • 定义并记录扩展的名称 (例如 my_extension_point ),这是使用扩展点时传递给 ament_register_extension 宏的名称。 [待校准@5863]

  • 在应执行扩展调用的宏/函数中: [待校准@5864]

ament_execute_extensions(my_extension_point)

[需手动修复的语法]Ament扩展的工作原理是定义一个包含扩展点名称的变量,并用要执行的宏填充它。调用 ament_execute_extensions 后,变量中定义的脚本将一个接一个地执行。 [待校准@5865]

添加re源文件 [待校准@5866]

尤其是在开发允许插件的插件或包时,通常必须将re源文件从另一个ROS包 (例如插件) 添加到一个ROS包中。示例可以是使用pluginlib的工具插件。 [待校准@5867]

这可以通过使用的ament指数 (也调用了 "resource index" )。 [待校准@5868]

ament指数解释 [待校准@5869]

有关设计和意图的详细信息,请参见 here [待校准@5870]

原则上,ament索引包含在包的安装/共享文件夹中的一个文件夹中。它包含以不同类型的re源文件命名的浅子文件夹。在子文件夹中,每个提供所述re源文件的包都以 "marker file" 名称引用。该文件可以包含获取re源文件所需的任何内容,例如到re源文件的安装目录的相对路径,它也可以简单地为空。 [待校准@5871]

举个例子,考虑为RViz提供显示插件: 当在一个名为 my_rviz_displays 的项目中提供RViz插件时,你将提供一个 plugin_description.xml 文件,它将由pluginlib安装并用于加载插件。为此,plugin_description.xml注册为重新源文件再次源文件 _ 指数通过 [待校准@5872]

pluginlib_export_plugin_description_file(rviz_common plugins_description.xml)

运行 colcon build 时,这会将文件 my_rviz_displays 安装到re源文件 _ index的子文件夹 rviz_common__pluginlib__plugin 中。rviz_common中的Pluginlib工厂将知道从所有名为 rviz_common__pluginlib__plugin 的文件夹中收集用于导出插件的包的信息。pluginlib工厂的标记文件包含 plugins_description.xml 文件的安装文件夹相对路径 (以及作为标记文件名的库名称)。有了这些信息,pluginlib可以加载库,并知道从 plugin_description.xml 文件加载哪些插件。 [待校准@5873]

作为第二个例子,考虑让你自己的RViz插件使用你自己的自定义网格的可能性。网格在启动时加载,因此插件所有者不必处理它,但这意味着RViz必须了解网格。为了实现这一点,RViz提供了一个功能: [待校准@5874]

register_rviz_ogre_media_exports(DIRECTORIES <my_dirs>)

这将目录注册为ament索引中的ogre_media re源文件。简而言之,它将一个以调用函数的项目命名的文件安装到调用 rviz_ogre_media_exports 的子文件夹中。该文件包含安装文件夹与宏中列出的目录的相对路径。在启动时,RViz现在可以搜索所有调用 rviz_ogre_media_exports 的文件夹,并在提供的所有文件夹中加载源文件。这些搜索是使用 ament_index_cpp (或蟒蛇包的 ament_index_py ) 完成的。 [待校准@5875]

在以下各节中,我们将探讨如何将您自己的re源文件添加到ament索引中,并为此提供最佳实践。 [待校准@5876]

查询ament指数 [待校准@5877]

如有必要,可以通过CMake查询re源文件的ament索引。为此,有三个功能: [待校准@5878]

[需手动修复的语法]``ament_index_has_resource``:获得前缀路径重新源文件如果存在以下参数: [待校准@5879]

  • [需手动修复的语法]``var``:输出参数: 如果re源文件不存在,则用FALSE填充此变量,否则用re源文件的前缀路径填充 [待校准@5880]

  • resource_type: The type of the resource (e.g. rviz_common__pluginlib__plugin) [待校准@5881]

  • resource_name: The name of the resource which usually amounts to the name of the package having added the resource of type resource_type (e.g. rviz_default_plugins) [待校准@5882]

[需手动修复的语法]``ament_index_get_resource``:获得特定re源文件的内容,即ament索引中标记文件的内容。 [待校准@5883]

  • [需手动修复的语法]``var``:输出参数: 如果存在,则填充re源文件的内容。 [待校准@5884]

  • resource_type: The type of the resource (e.g. rviz_common__pluginlib__plugin) [待校准@5881]

  • resource_name: The name of the resource which usually amounts to the name of the package having added the resource of type resource_type (e.g. rviz_default_plugins) [待校准@5882]

  • PREFIX_PATH: The prefix path to search for (usually, the default ament_index_get_prefix_path() will就够了)。 [待校准@5885]

请注意,如果re源文件不存在, ament_index_get_resource 将引发错误,因此可能有必要使用 ament_index_has_resource 进行检查。 [待校准@5886]

[需手动修复的语法]``ament_index_get_resources``:从索引中获取注册特定类型的re源文件的所有包 [待校准@5887]

  • [需手动修复的语法]``var``:输出参数: 填充所有注册了re源文件类型的re源文件的包的名称列表 [待校准@5888]

  • resource_type: The type of the resource (e.g. rviz_common__pluginlib__plugin) [待校准@5881]

  • PREFIX_PATH: The prefix path to search for (usually, the default ament_index_get_prefix_path() will就够了)。 [待校准@5885]

添加到ament指数 [待校准@5889]

定义重新源文件需要两个信息: [待校准@5890]

  • re源文件的名称必须是唯一的, [待校准@5891]

  • 标记文件的布局,可以是任何东西,也可以是空的 (例如,标记ROS 2包的 "package" re源文件也是如此) [待校准@5892]

对于RViz网格re源文件,相应的选择是: [待校准@5893]

  • [需手动修复的语法]``rviz_ogre_media_exports`` asre源文件的名称, [待校准@5894]

  • 安装包含re源文件的所有文件夹的路径相对路径。这将使您能够编写在包中使用相应re源文件的逻辑。 [待校准@5895]

为了允许用户轻松注册包的re源文件,您还应该提供宏或函数,如pluginlib函数或 rviz_ogre_media_exports 函数。 [待校准@5896]

要注册re源文件,请使用ament函数 ament_index_register_resource 。这将在re源文件 _ index中创建和安装标记文件。例如,对 rviz_ogre_media_exports 的相应调用如下: [待校准@5897]

ament_index_register_resource(rviz_ogre_media_exports CONTENT ${OGRE_MEDIA_RESOURCE_FILE})

这个安装文件像 ''${PROJECT_NAME} ”到一个文件夹 rviz_ogre_media_exports 到重新源文件 _ 指数内容给出变量 ''${OGRE_MEDIA_RESOURCE_FILE}”。该宏具有许多有用的参数: [待校准@5898]

  • 第一个 (未命名) 参数是re源文件的名称,相当于re源文件 _ index中文件夹的名称 [待校准@5899]

  • CONTENT: The content of the marker file as string. This could be a list of relative paths, etc. CONTENT cannot be used together with CONTENT_FILE. [待校准@5900]

  • CONTENT_FILE: The path to a file which will be use to create the marker file. The file can be a plain file or a template file expanded with configure_file(). CONTENT_FILE cannot be used together with CONTENT. [待校准@5901]

  • PACKAGE_NAME: The name of the package/library exporting the resource, which amounts to the name of the marker file. Defaults to ${PROJECT_NAME}. [待校准@5902]

  • AMENT_INDEX_BINARY_DIR: The base path of the generated ament index. Unless really necessary, always use the default ${CMAKE_BINARY_DIR}/ament_cmake_index. [待校准@5903]

  • [需手动修复的语法]``SKIP_INSTALL``:跳过安装标记文件。 [待校准@5904]

由于每个包只存在一个标记文件,如果CMake函数/宏被同一项目调用两次通常是一个问题。但是,对于大型项目,最好拆分注册源文件的调用。 [待校准@5905]

因此,最好的做法是让注册re源文件 (如 register_rviz_ogre_media_exports.cmake ) 的宏只填充一些变量。然后,对 ament_index_register_resource 的真正调用可以添加到 ament_package 的ament扩展中。因为每个项目只能有一个对 ament_package 的调用,所以总是只有一个地方注册了re源文件。就 rviz_ogre_media_exports 而言,这相当于以下策略: [待校准@5906]

  • register_rviz_ogre_media_exports 获取文件夹列表,并将它们附加到调用ed OGRE_MEDIA_RESOURCE_FILE 的变量中。 [待校准@5907]

  • 如果 “${OGRE_MEDIA_RESOURCE_FILE}” 为非空,则另一个宏调用ed register_rviz_ogre_media_exports_hook 调用s ament_index_register_resource[待校准@5908]

  • 通过调用, register_rviz_ogre_media_exports_hook.cmake 文件在第三文件 register_rviz_ogre_media_exports_hook-extras.cmake 中注册为ament扩展名 [待校准@5909]

ament_register_extension("ament_package" "rviz_rendering"
  "register_rviz_ogre_media_exports_hook.cmake")
  • 文件 register_rviz_ogre_media_exports.cmakeregister_rviz_ogre_media_exports_hook-extra.cmakeament_package() 注册为 CONFIG_EXTRA[待校准@5910]