651 lines
39 KiB
CMake
651 lines
39 KiB
CMake
include("${CMAKE_CURRENT_LIST_DIR}/../cmake_library/export.cmake")
|
||
set(__rcl_register_module_dir "${CMAKE_CURRENT_LIST_DIR}")
|
||
get_filename_component(__rcl_register_package_root "${__rcl_register_module_dir}/.." ABSOLUTE)
|
||
# INTERNAL: __rcl_namespace_storage_id(<namespace_name> <output_variable>)
|
||
# 作用: 将命名空间转换成可用于目录名和属性名的安全标识。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收结果的变量名。
|
||
function(__rcl_namespace_storage_id namespace_name output_variable)
|
||
string(REGEX REPLACE "[^A-Za-z0-9_]" "_" _namespace_storage_id "${namespace_name}")
|
||
set(${output_variable} "${_namespace_storage_id}" PARENT_SCOPE)
|
||
endfunction()
|
||
# INTERNAL: __rcl_default_root_dir(<namespace_name> <output_variable>)
|
||
# 作用: 根据当前工程环境生成命名空间默认根目录。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收目录的变量名。
|
||
function(__rcl_default_root_dir namespace_name output_variable)
|
||
__rcl_namespace_storage_id("${namespace_name}" _namespace_storage_id)
|
||
if (DEFINED EXTERNAL_DIR AND NOT "${EXTERNAL_DIR}" STREQUAL "" AND DEFINED G_Architecture_Name AND NOT "${G_Architecture_Name}" STREQUAL "")
|
||
set(_root_dir "${EXTERNAL_DIR}/${G_Architecture_Name}_${_namespace_storage_id}")
|
||
elseif (DEFINED EXTERNAL_DIR AND NOT "${EXTERNAL_DIR}" STREQUAL "")
|
||
set(_root_dir "${EXTERNAL_DIR}/_rcl_external_${_namespace_storage_id}")
|
||
else ()
|
||
set(_root_dir "${CMAKE_BINARY_DIR}/_rcl_external_${_namespace_storage_id}")
|
||
endif ()
|
||
set(${output_variable} "${_root_dir}" PARENT_SCOPE)
|
||
endfunction()
|
||
# INTERNAL: __rcl_split_library_name(<library_name> <namespace_output> <id_output>)
|
||
# 作用: 将 namespace::id 格式的完整库名拆分为命名空间和库 ID。
|
||
# 参数: library_name 是完整库名;namespace_output 和 id_output 是接收结果的变量名。
|
||
function(__rcl_split_library_name library_name namespace_output id_output)
|
||
__library_split_full_name("${library_name}" _namespace_name _library_id)
|
||
set(${namespace_output} "${_namespace_name}" PARENT_SCOPE)
|
||
set(${id_output} "${_library_id}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_init(<namespace_name> [root_dir])
|
||
# 作用: 初始化命名空间,并把其安装目录加入当前作用域的包搜索路径。
|
||
# 参数: namespace_name 是命名空间;可选 root_dir 是命名空间根目录。
|
||
function(rcl_init namespace_name)
|
||
set(_root_dir "${ARGV1}")
|
||
if ("${_root_dir}" STREQUAL "")
|
||
__rcl_default_root_dir("${namespace_name}" _root_dir)
|
||
endif ()
|
||
library_create("${namespace_name}" "${_root_dir}")
|
||
library_get_global("${namespace_name}" INSTALL_CACHE_ROOT _install_cache_root)
|
||
list(APPEND CMAKE_PREFIX_PATH "${_install_cache_root}")
|
||
list(APPEND CMAKE_FIND_ROOT_PATH "${_install_cache_root}")
|
||
list(REMOVE_DUPLICATES CMAKE_PREFIX_PATH)
|
||
list(REMOVE_DUPLICATES CMAKE_FIND_ROOT_PATH)
|
||
set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH}" PARENT_SCOPE)
|
||
set(CMAKE_FIND_ROOT_PATH "${CMAKE_FIND_ROOT_PATH}" PARENT_SCOPE)
|
||
message(STATUS "rcl_init CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}")
|
||
message(STATUS "rcl_init CMAKE_FIND_ROOT_PATH: ${CMAKE_FIND_ROOT_PATH}")
|
||
endfunction()
|
||
# API: rcl_set_root_dir(<namespace_name> <root_dir>)
|
||
# 作用: 设置命名空间根目录并刷新其派生目录。
|
||
# 参数: namespace_name 是命名空间;root_dir 是根目录。
|
||
function(rcl_set_root_dir namespace_name root_dir)
|
||
library_set_root_dir("${namespace_name}" "${root_dir}")
|
||
endfunction()
|
||
# API: rcl_get_root_dir(<namespace_name> <output_variable>)
|
||
# 作用: 读取命名空间根目录。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收目录的变量名。
|
||
function(rcl_get_root_dir namespace_name output_variable)
|
||
library_get_global("${namespace_name}" ROOT_DIR _root_dir)
|
||
set(${output_variable} "${_root_dir}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_set_cache_root(<namespace_name> <cache_root>)
|
||
# 作用: 设置命名空间缓存根目录。
|
||
# 参数: namespace_name 是命名空间;cache_root 是缓存根目录。
|
||
function(rcl_set_cache_root namespace_name cache_root)
|
||
library_set_global("${namespace_name}" CACHE_ROOT "${cache_root}")
|
||
endfunction()
|
||
# API: rcl_get_cache_root(<namespace_name> <output_variable>)
|
||
# 作用: 读取命名空间缓存根目录。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收目录的变量名。
|
||
function(rcl_get_cache_root namespace_name output_variable)
|
||
library_get_global("${namespace_name}" CACHE_ROOT _cache_root)
|
||
set(${output_variable} "${_cache_root}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_set_source_cache_root(<namespace_name> <source_cache_root>)
|
||
# 作用: 设置源码缓存根目录。
|
||
# 参数: namespace_name 是命名空间;source_cache_root 是源码缓存根目录。
|
||
function(rcl_set_source_cache_root namespace_name source_cache_root)
|
||
library_set_global("${namespace_name}" SOURCE_CACHE_ROOT "${source_cache_root}")
|
||
endfunction()
|
||
# API: rcl_get_source_cache_root(<namespace_name> <output_variable>)
|
||
# 作用: 读取源码缓存根目录。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收目录的变量名。
|
||
function(rcl_get_source_cache_root namespace_name output_variable)
|
||
library_get_global("${namespace_name}" SOURCE_CACHE_ROOT _source_cache_root)
|
||
set(${output_variable} "${_source_cache_root}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_set_build_cache_root(<namespace_name> <build_cache_root>)
|
||
# 作用: 设置构建缓存根目录。
|
||
# 参数: namespace_name 是命名空间;build_cache_root 是构建缓存根目录。
|
||
function(rcl_set_build_cache_root namespace_name build_cache_root)
|
||
library_set_global("${namespace_name}" BUILD_CACHE_ROOT "${build_cache_root}")
|
||
endfunction()
|
||
# API: rcl_get_build_cache_root(<namespace_name> <output_variable>)
|
||
# 作用: 读取构建缓存根目录。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收目录的变量名。
|
||
function(rcl_get_build_cache_root namespace_name output_variable)
|
||
library_get_global("${namespace_name}" BUILD_CACHE_ROOT _build_cache_root)
|
||
set(${output_variable} "${_build_cache_root}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_set_install_cache_root(<namespace_name> <install_cache_root>)
|
||
# 作用: 设置安装缓存根目录,并在未显式配置时同步数据导出目录。
|
||
# 参数: namespace_name 是命名空间;install_cache_root 是安装缓存根目录。
|
||
function(rcl_set_install_cache_root namespace_name install_cache_root)
|
||
library_set_global("${namespace_name}" INSTALL_CACHE_ROOT "${install_cache_root}")
|
||
library_get_global("${namespace_name}" DATA_EXPORT_DIR_EXPLICIT _data_export_dir_explicit)
|
||
if (NOT _data_export_dir_explicit)
|
||
get_filename_component(_context_root "${install_cache_root}" DIRECTORY)
|
||
library_set_global("${namespace_name}" DATA_EXPORT_DIR "${_context_root}/library_data")
|
||
endif ()
|
||
endfunction()
|
||
# API: rcl_get_install_cache_root(<namespace_name> <output_variable>)
|
||
# 作用: 读取安装缓存根目录。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收目录的变量名。
|
||
function(rcl_get_install_cache_root namespace_name output_variable)
|
||
library_get_global("${namespace_name}" INSTALL_CACHE_ROOT _install_cache_root)
|
||
set(${output_variable} "${_install_cache_root}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_set_patch_cache_root(<namespace_name> <patch_cache_root>)
|
||
# 作用: 设置补丁缓存根目录。
|
||
# 参数: namespace_name 是命名空间;patch_cache_root 是补丁缓存根目录。
|
||
function(rcl_set_patch_cache_root namespace_name patch_cache_root)
|
||
library_set_global("${namespace_name}" PATCH_CACHE_ROOT "${patch_cache_root}")
|
||
endfunction()
|
||
# API: rcl_get_patch_cache_root(<namespace_name> <output_variable>)
|
||
# 作用: 读取补丁缓存根目录。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收目录的变量名。
|
||
function(rcl_get_patch_cache_root namespace_name output_variable)
|
||
library_get_global("${namespace_name}" PATCH_CACHE_ROOT _patch_cache_root)
|
||
set(${output_variable} "${_patch_cache_root}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_set_log_cache_root(<namespace_name> <log_cache_root>)
|
||
# 作用: 设置日志缓存根目录。
|
||
# 参数: namespace_name 是命名空间;log_cache_root 是日志缓存根目录。
|
||
function(rcl_set_log_cache_root namespace_name log_cache_root)
|
||
library_set_global("${namespace_name}" LOG_CACHE_ROOT "${log_cache_root}")
|
||
endfunction()
|
||
# API: rcl_get_log_cache_root(<namespace_name> <output_variable>)
|
||
# 作用: 读取日志缓存根目录。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收目录的变量名。
|
||
function(rcl_get_log_cache_root namespace_name output_variable)
|
||
library_get_global("${namespace_name}" LOG_CACHE_ROOT _log_cache_root)
|
||
set(${output_variable} "${_log_cache_root}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_set_data_export_dir(<namespace_name> <data_export_dir>)
|
||
# 作用: 显式设置命名空间数据导出目录。
|
||
# 参数: namespace_name 是命名空间;data_export_dir 是导出目录。
|
||
function(rcl_set_data_export_dir namespace_name data_export_dir)
|
||
library_set_global("${namespace_name}" DATA_EXPORT_DIR "${data_export_dir}")
|
||
library_set_global("${namespace_name}" DATA_EXPORT_DIR_EXPLICIT TRUE)
|
||
endfunction()
|
||
# API: rcl_get_data_export_dir(<namespace_name> <output_variable>)
|
||
# 作用: 读取命名空间当前生效的数据导出目录。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收目录的变量名。
|
||
function(rcl_get_data_export_dir namespace_name output_variable)
|
||
library_get_effective_data_export_dir("${namespace_name}" _data_export_dir)
|
||
set(${output_variable} "${_data_export_dir}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_export_configuration(<namespace_name>)
|
||
# 作用: 将命名空间当前注册配置完整刷新到磁盘,供后续动作目标加载。
|
||
# 参数: namespace_name 是已经初始化并完成注册的命名空间。
|
||
# 返回: 无。
|
||
# 设计契约:
|
||
# 1. 当前 configure 过程中,内存 registry 是配置编辑态的唯一权威来源。
|
||
# 2. namespace 的全部注册和属性设置完成后调用本函数;随后才能创建动作目标。
|
||
# 3. 每次 configure 都必须无条件覆盖磁盘快照。禁止用 EXISTS、时间戳或旧 map.txt 跳过刷新,
|
||
# 否则 CMakeLists 中修改过的版本、选项、依赖和初始化脚本不会进入本轮动作目标。
|
||
# 4. library_export_dir 负责整批导出,禁止逐文件修补 registry,避免产生不同步的状态源。
|
||
function(rcl_export_configuration namespace_name)
|
||
rcl_get_data_export_dir("${namespace_name}" _namespace_data_dir)
|
||
library_cache_operations("${namespace_name}" _operations)
|
||
library_export_dir("${namespace_name}" "${_namespace_data_dir}")
|
||
endfunction()
|
||
# INTERNAL: __rcl_export_namespace_libraries_configuration(<namespace_name> [library_names...])
|
||
# 作用: 将一组库及其递归依赖整批刷新到指定命名空间的配置目录。
|
||
# 参数: namespace_name 决定导出目录和公共配置;ARGN 是 namespace::id 格式的完整库名列表。
|
||
function(__rcl_export_namespace_libraries_configuration namespace_name)
|
||
rcl_get_data_export_dir("${namespace_name}" _namespace_data_dir)
|
||
library_cache_operations("${namespace_name}" _operations)
|
||
string(SHA256 _registry_hash "rcl-export-libraries:${namespace_name}:${ARGN}")
|
||
set(_registry "__rcl_export_libraries_registry_${_registry_hash}")
|
||
__library_populate_registry("${_registry}" ${ARGN})
|
||
__library_export_registry_dir("${namespace_name}" "${_registry}" "${_namespace_data_dir}")
|
||
endfunction()
|
||
# API: rcl_export_libraries_configuration([library_names...])
|
||
# 作用: 将 ARGN 指定库及其递归依赖按各自所属命名空间刷新到配置目录,不导出无关库。
|
||
# 参数: ARGN 全部使用 namespace::id 格式的完整库名;不单独传 namespace_name。
|
||
# 返回: 无;未传入库时终止配置。
|
||
# 设计契约: 内存 registry 是本轮 configure 的唯一权威来源;先统一计算依赖闭包,再按命名空间整批导出,禁止逐库修补磁盘配置。
|
||
function(rcl_export_libraries_configuration)
|
||
if (NOT ARGN)
|
||
message(FATAL_ERROR "rcl_export_libraries_configuration requires at least one library")
|
||
endif ()
|
||
library_dependency_order(_library_names ${ARGN})
|
||
set(_namespace_names)
|
||
foreach (_library_name IN LISTS _library_names)
|
||
__rcl_split_library_name("${_library_name}" _namespace_name _library_id)
|
||
list(APPEND _namespace_names "${_namespace_name}")
|
||
endforeach ()
|
||
list(REMOVE_DUPLICATES _namespace_names)
|
||
foreach (_namespace_name IN LISTS _namespace_names)
|
||
set(_namespace_libraries)
|
||
foreach (_library_name IN LISTS _library_names)
|
||
__rcl_split_library_name("${_library_name}" _library_namespace _library_id)
|
||
if ("${_library_namespace}" STREQUAL "${_namespace_name}")
|
||
list(APPEND _namespace_libraries "${_library_name}")
|
||
endif ()
|
||
endforeach ()
|
||
__rcl_export_namespace_libraries_configuration("${_namespace_name}" ${_namespace_libraries})
|
||
endforeach ()
|
||
endfunction()
|
||
# API: rcl_set_script_root(<namespace_name> <script_root>)
|
||
# 作用: 设置命名空间脚本根目录。
|
||
# 参数: namespace_name 是命名空间;script_root 是脚本根目录。
|
||
function(rcl_set_script_root namespace_name script_root)
|
||
library_set_global("${namespace_name}" SCRIPT_ROOT "${script_root}")
|
||
endfunction()
|
||
# API: rcl_get_script_root(<namespace_name> <output_variable>)
|
||
# 作用: 读取命名空间脚本根目录。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收目录的变量名。
|
||
function(rcl_get_script_root namespace_name output_variable)
|
||
library_get_global("${namespace_name}" SCRIPT_ROOT _script_root)
|
||
set(${output_variable} "${_script_root}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_set_bash_script(<namespace_name> <bash_script>)
|
||
# 作用: 设置命名空间使用的 Bash 业务脚本。
|
||
# 参数: namespace_name 是命名空间;bash_script 是脚本路径。
|
||
function(rcl_set_bash_script namespace_name bash_script)
|
||
library_set_global("${namespace_name}" BASH_SCRIPT "${bash_script}")
|
||
endfunction()
|
||
# API: rcl_get_bash_script(<namespace_name> <output_variable>)
|
||
# 作用: 读取命名空间使用的 Bash 业务脚本。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收路径的变量名。
|
||
function(rcl_get_bash_script namespace_name output_variable)
|
||
library_get_global("${namespace_name}" BASH_SCRIPT _bash_script)
|
||
set(${output_variable} "${_bash_script}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_set_bash_executable(<namespace_name> <bash_executable>)
|
||
# 作用: 设置命名空间调用的 Bash 可执行文件。
|
||
# 参数: namespace_name 是命名空间;bash_executable 是可执行文件路径或命令名。
|
||
function(rcl_set_bash_executable namespace_name bash_executable)
|
||
library_set_global("${namespace_name}" BASH_EXECUTABLE "${bash_executable}")
|
||
endfunction()
|
||
# API: rcl_get_bash_executable(<namespace_name> <output_variable>)
|
||
# 作用: 读取命名空间调用的 Bash 可执行文件。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收路径的变量名。
|
||
function(rcl_get_bash_executable namespace_name output_variable)
|
||
library_get_global("${namespace_name}" BASH_EXECUTABLE _bash_executable)
|
||
set(${output_variable} "${_bash_executable}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_set_target_folder_root(<namespace_name> <target_folder_root>)
|
||
# 作用: 设置该命名空间生成的 CMake target 在 IDE 中的 Folder 根路径。
|
||
# 参数: namespace_name 是命名空间;target_folder_root 是 Folder 根路径。
|
||
function(rcl_set_target_folder_root namespace_name target_folder_root)
|
||
library_set_global("${namespace_name}" TARGET_FOLDER_ROOT "${target_folder_root}")
|
||
endfunction()
|
||
# API: rcl_get_target_folder_root(<namespace_name> <output_variable>)
|
||
# 作用: 读取命名空间 target 的 Folder 根路径。
|
||
# 参数: namespace_name 是命名空间;output_variable 是接收路径的变量名。
|
||
function(rcl_get_target_folder_root namespace_name output_variable)
|
||
library_get_global("${namespace_name}" TARGET_FOLDER_ROOT _target_folder_root)
|
||
set(${output_variable} "${_target_folder_root}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_set_source_dir(<library_name> <source_dir>)
|
||
# 作用: 为指定库设置源码目录。
|
||
# 参数: library_name 使用 namespace::id;source_dir 是源码目录。
|
||
function(rcl_set_source_dir library_name source_dir)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_set_source_dir("${_namespace_name}" "${library_name}" "${source_dir}")
|
||
endfunction()
|
||
# API: rcl_set_build_dir(<library_name> <build_dir>)
|
||
# 作用: 为指定库设置构建目录。
|
||
# 参数: library_name 使用 namespace::id;build_dir 是构建目录。
|
||
function(rcl_set_build_dir library_name build_dir)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_set_build_dir("${_namespace_name}" "${library_name}" "${build_dir}")
|
||
endfunction()
|
||
# API: rcl_set_install_dir(<library_name> <install_dir>)
|
||
# 作用: 为指定库设置安装目录。
|
||
# 参数: library_name 使用 namespace::id;install_dir 是安装目录。
|
||
function(rcl_set_install_dir library_name install_dir)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_set_install_dir("${_namespace_name}" "${library_name}" "${install_dir}")
|
||
endfunction()
|
||
# API: rcl_set_patch_cache_dir(<library_name> <patch_cache_dir>)
|
||
# 作用: 为指定库设置补丁缓存目录。
|
||
# 参数: library_name 使用 namespace::id;patch_cache_dir 是补丁缓存目录。
|
||
function(rcl_set_patch_cache_dir library_name patch_cache_dir)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_set_patch_cache_dir("${_namespace_name}" "${library_name}" "${patch_cache_dir}")
|
||
endfunction()
|
||
# API: rcl_set_log_dir(<library_name> <log_dir>)
|
||
# 作用: 为指定库设置日志目录。
|
||
# 参数: library_name 使用 namespace::id;log_dir 是日志目录。
|
||
function(rcl_set_log_dir library_name log_dir)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_set_log_dir("${_namespace_name}" "${library_name}" "${log_dir}")
|
||
endfunction()
|
||
# API: rcl_set_local_source_dir(<library_name> <local_source_dir>)
|
||
# 作用: 为指定库设置本地源码覆盖目录。
|
||
# 参数: library_name 使用 namespace::id;local_source_dir 是本地源码目录。
|
||
function(rcl_set_local_source_dir library_name local_source_dir)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_set_local_source_dir("${_namespace_name}" "${library_name}" "${local_source_dir}")
|
||
endfunction()
|
||
# API: rcl_get_effective_source_dir(<library_name> <output_variable>)
|
||
# 作用: 读取指定库当前生效的源码目录。
|
||
# 参数: library_name 使用 namespace::id;output_variable 是接收目录的变量名。
|
||
function(rcl_get_effective_source_dir library_name output_variable)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_get_effective_source_dir("${_namespace_name}" "${library_name}" _source_dir)
|
||
set(${output_variable} "${_source_dir}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_get_effective_build_dir(<library_name> <output_variable>)
|
||
# 作用: 读取指定库当前生效的构建目录。
|
||
# 参数: library_name 使用 namespace::id;output_variable 是接收目录的变量名。
|
||
function(rcl_get_effective_build_dir library_name output_variable)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_get_effective_build_dir("${_namespace_name}" "${library_name}" _build_dir)
|
||
set(${output_variable} "${_build_dir}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_get_effective_install_dir(<library_name> <output_variable>)
|
||
# 作用: 读取指定库当前生效的安装目录。
|
||
# 参数: library_name 使用 namespace::id;output_variable 是接收目录的变量名。
|
||
function(rcl_get_effective_install_dir library_name output_variable)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_get_effective_install_dir("${_namespace_name}" "${library_name}" _install_dir)
|
||
set(${output_variable} "${_install_dir}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_get_effective_patch_cache_dir(<library_name> <output_variable>)
|
||
# 作用: 读取指定库当前生效的补丁缓存目录。
|
||
# 参数: library_name 使用 namespace::id;output_variable 是接收目录的变量名。
|
||
function(rcl_get_effective_patch_cache_dir library_name output_variable)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_get_effective_patch_cache_dir("${_namespace_name}" "${library_name}" _patch_cache_dir)
|
||
set(${output_variable} "${_patch_cache_dir}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_get_effective_log_dir(<library_name> <output_variable>)
|
||
# 作用: 读取指定库当前生效的日志目录。
|
||
# 参数: library_name 使用 namespace::id;output_variable 是接收目录的变量名。
|
||
function(rcl_get_effective_log_dir library_name output_variable)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_get_effective_log_dir("${_namespace_name}" "${library_name}" _log_dir)
|
||
set(${output_variable} "${_log_dir}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: rcl_get_effective_cmake_cache_dir(<library_name> <output_variable>)
|
||
# 作用: 读取指定库当前生效的 CMake 缓存目录。
|
||
# 参数: library_name 使用 namespace::id;output_variable 是接收目录的变量名。
|
||
function(rcl_get_effective_cmake_cache_dir library_name output_variable)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_get_effective_cmake_cache_dir("${_namespace_name}" "${library_name}" _cmake_cache_dir)
|
||
set(${output_variable} "${_cmake_cache_dir}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API: _register_git_cmake_library(<library_name> <git_url> <git_version>)
|
||
# 作用: 注册一个 Git CMake 库并设置仓库地址和分支或版本。
|
||
# 参数: library_name 使用 namespace::id;git_url 是仓库地址;git_version 是分支、标签或提交标识。
|
||
function(_register_git_cmake_library library_name git_url git_version)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_register("${_namespace_name}" "${_library_id}")
|
||
library_set("${_namespace_name}" "${library_name}" GIT_URL "${git_url}")
|
||
library_set("${_namespace_name}" "${library_name}" GIT_BRANCH "${git_version}")
|
||
endfunction()
|
||
# API: rcl_cmake_library_set_cmake_options(<library_name> [options...])
|
||
# 作用: 设置指定库传给 CMake 的配置参数。
|
||
# 参数: library_name 使用 namespace::id;ARGN 是配置参数列表。
|
||
function(rcl_cmake_library_set_cmake_options library_name)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
string(REPLACE ";" " " _content "${ARGN}")
|
||
library_set("${_namespace_name}" "${library_name}" CMAKE_OPTIONS "${_content}")
|
||
endfunction()
|
||
# API: rcl_cmake_library_set_other_use_opt(<library_name> [options...])
|
||
# 作用: 设置指定库的其他业务参数。
|
||
# 参数: library_name 使用 namespace::id;ARGN 是业务参数列表。
|
||
function(rcl_cmake_library_set_other_use_opt library_name)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
string(REPLACE ";" " " _content "${ARGN}")
|
||
library_set("${_namespace_name}" "${library_name}" OTHER_USE_OPT "${_content}")
|
||
endfunction()
|
||
# API: rcl_cmake_library_set_init_script(<library_name> [script_lines...])
|
||
# 作用: 设置指定库在 find_package 前执行的初始化脚本。
|
||
# 参数: library_name 使用 namespace::id;ARGN 是按行传入的 CMake 脚本内容。
|
||
function(rcl_cmake_library_set_init_script library_name)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
string(REPLACE ";" "\n" _content "${ARGN}")
|
||
library_set_init_scripts("${_namespace_name}" "${library_name}" "${_content}")
|
||
endfunction()
|
||
# API: rcl_cmake_library_set_clear_script(<library_name> [script_lines...])
|
||
# 作用: 设置指定库卸载依赖环境时执行的清理脚本。
|
||
# 参数: library_name 使用 namespace::id;ARGN 是按行传入的 CMake 脚本内容。
|
||
function(rcl_cmake_library_set_clear_script library_name)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
string(REPLACE ";" "\n" _content "${ARGN}")
|
||
library_set_clear_scripts("${_namespace_name}" "${library_name}" "${_content}")
|
||
endfunction()
|
||
# API: rcl_cmake_library_set_cmake_source_relative_dir(<library_name> <relative_dir>)
|
||
# 作用: 设置指定库源码树内 CMake 工程入口的相对目录。
|
||
# 参数: library_name 使用 namespace::id;relative_dir 相对于该库源码目录。
|
||
function(rcl_cmake_library_set_cmake_source_relative_dir library_name relative_dir)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_set_cmake_source_subdir("${_namespace_name}" "${library_name}" "${relative_dir}")
|
||
endfunction()
|
||
# API: rcl_cmake_library_set_patches(<library_name> [patch_files...])
|
||
# 作用: 替换指定库的本地补丁文件列表。
|
||
# 参数: library_name 使用 namespace::id;ARGN 是补丁文件列表。
|
||
function(rcl_cmake_library_set_patches library_name)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_set_patch_files("${_namespace_name}" "${library_name}" ${ARGN})
|
||
endfunction()
|
||
# API: rcl_cmake_library_add_patch_file(<library_name> [patch_files...])
|
||
# 作用: 向指定库追加本地补丁文件。
|
||
# 参数: library_name 使用 namespace::id;ARGN 是要追加的补丁文件列表。
|
||
function(rcl_cmake_library_add_patch_file library_name)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_add_patch_file("${_namespace_name}" "${library_name}" ${ARGN})
|
||
endfunction()
|
||
# API: rcl_cmake_library_add_patch_url(<library_name> <url> <filename> [sha256])
|
||
# 作用: 向指定库追加一个需要下载的补丁文件。
|
||
# 参数: library_name 使用 namespace::id;url、filename 和可选 sha256 描述远程补丁。
|
||
function(rcl_cmake_library_add_patch_url library_name url filename)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_add_patch_url("${_namespace_name}" "${library_name}" "${url}" "${filename}" ${ARGN})
|
||
endfunction()
|
||
# API: rcl_cmake_library_set_deps(<library_name> [dependency_references...])
|
||
# 作用: 为指定库追加依赖关系。
|
||
# 参数: library_name 使用 namespace::id;ARGN 是完整库名或当前可见命名空间中的库 ID。
|
||
function(rcl_cmake_library_set_deps library_name)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
library_depends("${_namespace_name}" "${library_name}" ${ARGN})
|
||
endfunction()
|
||
# API: rcl_namespace_depends(<namespace_name> [dependency_namespaces...])
|
||
# 作用: 为命名空间追加可见依赖命名空间。
|
||
# 参数: namespace_name 是当前命名空间;ARGN 是依赖命名空间列表。
|
||
function(rcl_namespace_depends namespace_name)
|
||
library_namespace_depends("${namespace_name}" ${ARGN})
|
||
endfunction()
|
||
# INTERNAL: __rcl_read_library_map(<library_name> <map_output> <data_dir_output>)
|
||
# 作用: 从磁盘读取一个库的自包含配置,不导出 namespace,也不写文件。
|
||
# 参数: library_name 使用 namespace::id;两个输出参数分别接收临时 map ID 和配置记录的数据目录。
|
||
# 返回: 通过 PARENT_SCOPE 返回输出;单库配置文件不存在时终止配置。
|
||
# 设计契约: 本函数只读取由 rcl_export_configuration 在本轮 configure 中刷新的快照;
|
||
# 禁止在这里从旧文件恢复、按缺失补写或回退到内存 registry。
|
||
function(__rcl_read_library_map library_name map_output data_dir_output)
|
||
__rcl_split_library_name("${library_name}" _namespace_name _library_id)
|
||
rcl_get_data_export_dir("${_namespace_name}" _namespace_data_dir)
|
||
__library_storage_path("${library_name}" _library_storage_path)
|
||
set(_map_file "${_namespace_data_dir}/registry/nodes/${_library_storage_path}/map.txt")
|
||
if (NOT EXISTS "${_map_file}")
|
||
message(FATAL_ERROR "registered library configuration does not exist: ${_map_file}")
|
||
endif ()
|
||
string(SHA256 _map_hash "rcl-disk-library:${_map_file}")
|
||
set(_map "__rcl_disk_library_${_map_hash}")
|
||
map_deserialize_file("${_map}" "${_map_file}")
|
||
map_get("${_map}" DATA_EXPORT_DIR _data_export_dir)
|
||
if ("${_data_export_dir}" STREQUAL "")
|
||
set(_data_export_dir "${_namespace_data_dir}")
|
||
endif ()
|
||
set(${map_output} "${_map}" PARENT_SCOPE)
|
||
set(${data_dir_output} "${_data_export_dir}" PARENT_SCOPE)
|
||
endfunction()
|
||
# API GROUP: dependency environment loading
|
||
# API: rcl_load_dependency_environment_with_depth(<dependency_depth> [library_names...])
|
||
# 作用: 按指定依赖深度加载库环境,所有依赖解析、去重和顺序计算统一由基础实现完成。
|
||
# 参数: dependency_depth 为 0 时加载全部间接依赖,为 1 时只加载显式传入库,其他正数表示最大层数;ARGN 是 namespace::id 格式的完整库名列表。
|
||
macro(rcl_load_dependency_environment_with_depth dependency_depth)
|
||
library_init_environment_with_depth("${dependency_depth}" ${ARGN})
|
||
endmacro()
|
||
# API: rcl_load_dependency_environment([library_names...])
|
||
# 作用: 加载显式库及其全部递归依赖的初始化脚本,保持原有递归语义。
|
||
# 参数: ARGN 是 namespace::id 格式的完整库名列表。
|
||
macro(rcl_load_dependency_environment)
|
||
rcl_load_dependency_environment_with_depth(0 ${ARGN})
|
||
endmacro()
|
||
# API: rcl_load_direct_dependency_environment([library_names...])
|
||
# 作用: 只加载显式传入的直接依赖,不展开这些库的间接依赖。
|
||
# 参数: ARGN 是 namespace::id 格式的完整库名列表。
|
||
macro(rcl_load_direct_dependency_environment)
|
||
rcl_load_dependency_environment_with_depth(1 ${ARGN})
|
||
endmacro()
|
||
# API: rcl_unload_dependency_environment_with_depth(<dependency_depth> [library_names...])
|
||
# 作用: 按指定依赖深度逆序清理库环境,深度语义与加载接口一致。
|
||
# 参数: dependency_depth 为 0 时清理全部间接依赖,为 1 时只清理显式传入库,其他正数表示最大层数;ARGN 是 namespace::id 格式的完整库名列表。
|
||
macro(rcl_unload_dependency_environment_with_depth dependency_depth)
|
||
library_clear_environment_with_depth("${dependency_depth}" ${ARGN})
|
||
endmacro()
|
||
# API: rcl_unload_dependency_environment([library_names...])
|
||
# 作用: 逆序清理显式库及其全部递归依赖设置的环境,保持原有递归语义。
|
||
# 参数: ARGN 是 namespace::id 格式的完整库名列表。
|
||
macro(rcl_unload_dependency_environment)
|
||
rcl_unload_dependency_environment_with_depth(0 ${ARGN})
|
||
endmacro()
|
||
# API: rcl_unload_direct_dependency_environment([library_names...])
|
||
# 作用: 只清理显式传入的直接依赖,不展开这些库的间接依赖。
|
||
# 参数: ARGN 是 namespace::id 格式的完整库名列表。
|
||
macro(rcl_unload_direct_dependency_environment)
|
||
rcl_unload_dependency_environment_with_depth(1 ${ARGN})
|
||
endmacro()
|
||
# INTERNAL: __rcl_library_action_target_name(<library_name> <action_name> <output_variable>)
|
||
# 作用: 计算指定库单库 action 对应的 CMake target 名称。
|
||
# 参数: library_name 使用 namespace::id;action_name 是不带 with_rely_ 前缀的单库 action;output_variable 是接收 target 名称的变量名。
|
||
# 返回: 通过 PARENT_SCOPE 设置 output_variable。
|
||
function(__rcl_library_action_target_name library_name action_name output_variable)
|
||
action_target_name("${library_name}" _library_target_name)
|
||
action_target_name("${action_name}" _action_target_name)
|
||
set(${output_variable} "pfx_${_library_target_name}_${_action_target_name}" PARENT_SCOPE)
|
||
endfunction()
|
||
# INTERNAL: __rcl_add_unique_target_dependencies(<target_name> [dependency_targets...])
|
||
# 作用: 向现有 CMake target 追加尚未存在的 target 依赖,避免重复调用产生重复依赖项。
|
||
# 参数: target_name 是被追加依赖的 target;ARGN 是待追加的 dependency target 列表。
|
||
# 返回: 无。
|
||
function(__rcl_add_unique_target_dependencies target_name)
|
||
get_property(_existing_dependencies TARGET "${target_name}" PROPERTY MANUALLY_ADDED_DEPENDENCIES)
|
||
set(_new_dependencies)
|
||
foreach (_dependency_target IN LISTS ARGN)
|
||
list(FIND _existing_dependencies "${_dependency_target}" _existing_index)
|
||
list(FIND _new_dependencies "${_dependency_target}" _new_index)
|
||
if (_existing_index EQUAL -1 AND _new_index EQUAL -1)
|
||
list(APPEND _new_dependencies "${_dependency_target}")
|
||
endif ()
|
||
endforeach ()
|
||
if (_new_dependencies)
|
||
add_dependencies("${target_name}" ${_new_dependencies})
|
||
endif ()
|
||
endfunction()
|
||
# API GROUP: dependency target loading
|
||
# INTERNAL: __rcl_load_library_action_targets_with_depth(<library_name> <dependency_depth> <visited_libraries> <dependency_order> <loading_stack> <visited_output> <order_output>)
|
||
# 作用: 从单库磁盘 map 读取直接依赖并递归注册闭包内每个库的全部 action target。
|
||
# 参数: dependency_depth 为 0 时无限递归,为 1 时只处理当前库;其余列表用于本次递归的去重、依赖优先顺序和环检测。
|
||
# 返回: 通过最后两个输出参数返回本次递归更新后的已访问库和依赖优先顺序。
|
||
# 注意: 磁盘 map 是该加载路径的唯一配置来源;函数不导出、不刷新、不写入任何配置文件。
|
||
function(__rcl_load_library_action_targets_with_depth library_name dependency_depth visited_libraries dependency_order loading_stack visited_output order_output)
|
||
list(FIND visited_libraries "${library_name}" _visited_index)
|
||
if (NOT _visited_index EQUAL -1)
|
||
set(${visited_output} "${visited_libraries}" PARENT_SCOPE)
|
||
set(${order_output} "${dependency_order}" PARENT_SCOPE)
|
||
return()
|
||
endif ()
|
||
list(FIND loading_stack "${library_name}" _loading_index)
|
||
if (NOT _loading_index EQUAL -1)
|
||
list(APPEND loading_stack "${library_name}")
|
||
string(JOIN " -> " _cycle ${loading_stack})
|
||
message(FATAL_ERROR "registered library dependency cycle: ${_cycle}")
|
||
endif ()
|
||
|
||
__rcl_read_library_map("${library_name}" _library_map _data_export_dir)
|
||
map_get("${_library_map}" RESOLVED_DEPENDENCIES _direct_dependencies)
|
||
list(APPEND loading_stack "${library_name}")
|
||
set(_loaded_direct_dependencies)
|
||
if (dependency_depth EQUAL 0 OR dependency_depth GREATER 1)
|
||
if (dependency_depth EQUAL 0)
|
||
set(_next_depth 0)
|
||
else ()
|
||
math(EXPR _next_depth "${dependency_depth} - 1")
|
||
endif ()
|
||
foreach (_dependency_name IN LISTS _direct_dependencies)
|
||
__rcl_load_library_action_targets_with_depth(
|
||
"${_dependency_name}" "${_next_depth}"
|
||
"${visited_libraries}" "${dependency_order}" "${loading_stack}"
|
||
visited_libraries dependency_order)
|
||
list(APPEND _loaded_direct_dependencies "${_dependency_name}")
|
||
endforeach ()
|
||
endif ()
|
||
|
||
__rcl_library_action_target_name("${library_name}" auto _library_action_target)
|
||
if (NOT TARGET "${_library_action_target}")
|
||
map_get("${_library_map}" BASH_EXECUTABLE _bash_executable)
|
||
map_get("${_library_map}" BASH_SCRIPT _bash_script)
|
||
map_get("${_library_map}" TARGET_FOLDER_ROOT _target_folder_root)
|
||
action_cache_operations("${_bash_executable}" "${_bash_script}" _operations)
|
||
action_add_item_operation_targets(
|
||
pfx "${_data_export_dir}" "${_bash_executable}" "${_bash_script}"
|
||
"${library_name}" "${_operations}" "${_target_folder_root}")
|
||
endif ()
|
||
if (NOT TARGET "${_library_action_target}")
|
||
message(FATAL_ERROR "registered library does not provide the auto action: ${library_name}")
|
||
endif ()
|
||
|
||
set(_direct_dependency_targets)
|
||
foreach (_dependency_name IN LISTS _loaded_direct_dependencies)
|
||
__rcl_library_action_target_name("${_dependency_name}" auto _dependency_action_target)
|
||
list(APPEND _direct_dependency_targets "${_dependency_action_target}")
|
||
endforeach ()
|
||
__rcl_add_unique_target_dependencies("${_library_action_target}" ${_direct_dependency_targets})
|
||
list(APPEND visited_libraries "${library_name}")
|
||
list(APPEND dependency_order "${library_name}")
|
||
set(${visited_output} "${visited_libraries}" PARENT_SCOPE)
|
||
set(${order_output} "${dependency_order}" PARENT_SCOPE)
|
||
endfunction()
|
||
|
||
# API: rcl_add_dependency_action_targets_with_depth(<target_name> <dependency_depth> [library_names...])
|
||
# 作用: 按指定深度从磁盘递归加载依赖库,为每个库注册全部 action target,并把直接库依赖映射成 CMake auto target 依赖图。
|
||
# 参数: target_name 是聚合 target;dependency_depth 为 0 时无限递归,为 1 时只包含显式传入库,其他正整数表示最大层数;ARGN 是 namespace::id 格式的起始库列表。
|
||
# 返回: 无。
|
||
function(rcl_add_dependency_action_targets_with_depth target_name dependency_depth)
|
||
if (NOT "${dependency_depth}" MATCHES "^[0-9]+$")
|
||
message(FATAL_ERROR "dependency_depth must be a non-negative integer: ${dependency_depth}")
|
||
endif ()
|
||
set(_visited_libraries)
|
||
set(_dependency_order)
|
||
foreach (_library_name IN LISTS ARGN)
|
||
__rcl_load_library_action_targets_with_depth(
|
||
"${_library_name}" "${dependency_depth}"
|
||
"${_visited_libraries}" "${_dependency_order}" ""
|
||
_visited_libraries _dependency_order)
|
||
endforeach ()
|
||
set(_dependency_action_targets)
|
||
foreach (_library_name IN LISTS _dependency_order)
|
||
__rcl_library_action_target_name("${_library_name}" auto _library_action_target)
|
||
list(APPEND _dependency_action_targets "${_library_action_target}")
|
||
endforeach ()
|
||
if (NOT TARGET "${target_name}")
|
||
add_custom_target("${target_name}")
|
||
endif ()
|
||
__rcl_add_unique_target_dependencies("${target_name}" ${_dependency_action_targets})
|
||
message("${B}__rcl_add_unique_target_dependencies${E} ${target_name} -> ${_dependency_action_targets}")
|
||
endfunction()
|
||
# API: rcl_add_dependency_action_targets(<target_name> [library_names...])
|
||
# 作用: 递归加载指定库及全部间接依赖的单库 auto target,并创建去重后的 CMake target 依赖图。
|
||
# 参数: target_name 是聚合 target;ARGN 是 namespace::id 格式的起始库列表。
|
||
# 返回: 无。
|
||
function(rcl_add_dependency_action_targets target_name)
|
||
rcl_add_dependency_action_targets_with_depth("${target_name}" 0 ${ARGN})
|
||
endfunction()
|
||
set_property(GLOBAL PROPERTY rcl_log_list "")
|
||
macro(rcl_log_append line text)
|
||
set(rcl_log_location "${CMAKE_CURRENT_LIST_FILE}:${line}")
|
||
if (NOT "${CMAKE_CURRENT_FUNCTION}" STREQUAL "")
|
||
string(APPEND rcl_log_location " -> ${CMAKE_CURRENT_FUNCTION}()")
|
||
endif ()
|
||
set_property(GLOBAL APPEND PROPERTY rcl_log_list "${rcl_log_location}|${text}")
|
||
endmacro()
|
||
function(rcl_log_print)
|
||
get_property(rcl_log_list GLOBAL PROPERTY rcl_log_list)
|
||
if ("${rcl_log_list}" STREQUAL "")
|
||
message("${B}全部加载完成!${E}")
|
||
return()
|
||
endif ()
|
||
set(rcl_log_output "")
|
||
foreach (rcl_log IN LISTS rcl_log_list)
|
||
string(FIND "${rcl_log}" "|" split_pos)
|
||
string(SUBSTRING "${rcl_log}" 0 ${split_pos} location)
|
||
math(EXPR text_pos "${split_pos} + 1")
|
||
string(SUBSTRING "${rcl_log}" ${text_pos} -1 text)
|
||
string(APPEND rcl_log_output "${R}严重错误${E} ${R}${text}${E}\n")
|
||
string(APPEND rcl_log_output "${P}调用位置 ${E} file:///${location}\n")
|
||
endforeach ()
|
||
message("${rcl_log_output}")
|
||
endfunction()
|