mirage/cmake/retrieve_files.cmake

239 lines
9.1 KiB
CMake
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#[=======================================================================[
:
platform: 平台标识符 (windows|linux|mac|mobile|desktop)
is_match:
#]=======================================================================]
function(is_current_platform platform is_match)
# 设置默认值为TRUE用于未知平台
set(matches FALSE)
if(platform STREQUAL "windows")
if(WIN32)
set(matches TRUE)
endif()
elseif(platform STREQUAL "linux")
if(UNIX AND NOT APPLE)
set(matches TRUE)
endif()
elseif(platform STREQUAL "mac")
if(APPLE AND NOT IOS)
set(matches TRUE)
endif()
elseif(platform STREQUAL "ios")
if(IOS)
set(matches TRUE)
endif()
elseif(platform STREQUAL "android")
if(ANDROID)
set(matches TRUE)
endif()
# 添加对unix平台的支持
elseif(platform STREQUAL "unix")
if(UNIX)
set(matches TRUE)
endif()
elseif(platform STREQUAL "mobile")
if(ANDROID OR IOS)
set(matches TRUE)
endif()
elseif(platform STREQUAL "desktop")
if(WIN32 OR (UNIX AND NOT APPLE) OR (APPLE AND NOT IOS))
set(matches TRUE)
endif()
else()
# 未知平台标识,默认匹配
set(matches TRUE)
endif()
set(${is_match} ${matches} PARENT_SCOPE)
endfunction()
#[=======================================================================[
:
path:
extension:
out_files:
#]=======================================================================]
function(retrieve_files_custom path extension out_files)
# 1. 参数验证
if(NOT IS_DIRECTORY "${path}")
message(WARNING "错误:目录 '${path}' 不存在")
return()
endif()
message(STATUS "正在检索目录: ${path}")
# 2. 构建文件匹配模式
set(file_patterns "")
foreach(ext IN LISTS extension)
list(APPEND file_patterns "${path}/*.${ext}")
endforeach()
# 3. 递归查找所有匹配的文件
file(GLOB_RECURSE found_files
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
CONFIGURE_DEPENDS ${file_patterns}
)
# 4. 处理找到的文件
set(filtered_files "")
foreach(current_file IN LISTS found_files)
# 4.1 获取文件所在目录
get_filename_component(file_dir "${current_file}" DIRECTORY)
string(REPLACE "/" ";" dir_components "${file_dir}")
# 4.2 检查平台兼容性
set(should_skip_file FALSE)
set(found_platform_dir FALSE)
foreach(dir_name IN LISTS dir_components)
# 检查是否是平台相关目录
if(dir_name MATCHES "^(windows|linux|mac|ios|android|unix|mobile|desktop)$")
set(found_platform_dir TRUE)
is_current_platform(${dir_name} platform_matches)
if(NOT platform_matches)
set(should_skip_file TRUE)
break()
endif()
endif()
endforeach()
# 如果文件需要跳过,继续处理下一个文件
if(should_skip_file)
continue()
endif()
# 4.3 添加符合条件的文件
list(APPEND filtered_files "${current_file}")
# 4.4 设置IDE文件分组
# 计算相对路径作为分组名称
get_filename_component(root_abs_path "${path}" ABSOLUTE)
get_filename_component(file_dir_abs_path "${file_dir}" ABSOLUTE)
file(RELATIVE_PATH group_path "${root_abs_path}" "${file_dir_abs_path}")
# 处理根目录的特殊情况
if(group_path STREQUAL ".")
set(group_name "")
else()
string(REPLACE "/" "\\" group_name "${group_path}")
endif()
# 创建IDE分组
source_group("${group_name}" FILES "${current_file}")
endforeach()
# 5. 设置输出变量
set(${out_files} ${filtered_files} PARENT_SCOPE)
endfunction()
#[=======================================================================[
便
#]=======================================================================]
function(retrieve_files path out_files)
# 设置基础文件类型
set(file_extensions
"h" # 头文件
"hpp" # C++头文件
"ini" # 配置文件
"cpp" # C++源文件
"c" # C源文件
"ixx" # C++20模块文件
)
# 针对Mac平台添加额外文件类型
if(APPLE)
list(APPEND file_extensions "mm") # Objective-C++源文件
endif()
# 执行文件检索
set(temp_files "")
retrieve_files_custom(${path} "${file_extensions}" temp_files)
# 合并结果到输出变量
set(${out_files} ${${out_files}} ${temp_files} PARENT_SCOPE)
endfunction()
#[=======================================================================[
用于添加资源文件并在编译后复制到目标文件 (可执行文件或库)
:
TARGET_NAME: 目标 (可执行文件或库)
RESOURCE_FILE_PATHS - 一个或多个要复制的资源文件的路径 (可以是相对或绝对路径)
#]=======================================================================]
function(add_resources TARGET_NAME)
# 获取 TARGET_NAME 之后的所有参数作为资源文件列表
set(RESOURCE_FILES ${ARGN})
# 检查目标是否存在 (可选,但推荐)
if(NOT TARGET ${TARGET_NAME})
message(FATAL_ERROR "目标 '${TARGET_NAME}' 不存在,无法添加资源。")
return()
endif()
# **获取目标可执行文件的输出目录** (只需执行一次)
# 对于多配置生成器 (如 Visual Studio, Xcode),使用 $<TARGET_FILE_DIR:TARGET_NAME>
# 对于单配置生成器 (如 Makefiles, Ninja),使用 CMAKE_RUNTIME_OUTPUT_DIRECTORY 或 $<TARGET_FILE_DIR:TARGET_NAME>
if(CMAKE_CONFIGURATION_TYPES)
set(DESTINATION_DIR "$<TARGET_FILE_DIR:${TARGET_NAME}>")
else()
if(CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(DESTINATION_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
else()
# 使用 $<TARGET_FILE_DIR:TARGET_NAME> 通常更健壮
set(DESTINATION_DIR "$<TARGET_FILE_DIR:${TARGET_NAME}>")
endif()
endif()
# **遍历所有传入的资源文件**
foreach(RESOURCE_FILE ${RESOURCE_FILES})
set(ABS_RESOURCE_FILE "") # 重置/初始化
# **处理相对路径和绝对路径,并检查文件是否存在**
if(IS_ABSOLUTE "${RESOURCE_FILE}")
# 如果是绝对路径,直接检查是否存在
if(EXISTS "${RESOURCE_FILE}")
set(ABS_RESOURCE_FILE "${RESOURCE_FILE}")
else()
message(WARNING "资源文件未找到 (绝对路径,将跳过): ${RESOURCE_FILE}")
continue() # 处理下一个文件
endif()
else()
# 如果是相对路径,相对于当前 CMakeLists.txt 文件所在目录解析
set(TEMP_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${RESOURCE_FILE}")
if(EXISTS "${TEMP_PATH}")
set(ABS_RESOURCE_FILE "${TEMP_PATH}")
else()
message(WARNING "资源文件未找到 (相对路径,将跳过): ${RESOURCE_FILE} (相对于: ${CMAKE_CURRENT_SOURCE_DIR})")
continue() # 处理下一个文件
endif()
endif()
# **检查是否是文件而非目录** (copy_if_different 用于文件)
if(IS_DIRECTORY "${ABS_RESOURCE_FILE}")
message(WARNING "提供的资源是一个目录,而非文件 (将跳过): ${ABS_RESOURCE_FILE}. 请使用其他方法复制目录。")
continue()
endif()
# **获取资源文件的文件名部分**
get_filename_component(RESOURCE_FILENAME "${ABS_RESOURCE_FILE}" NAME)
# **为每个文件添加自定义构建后命令**
add_custom_command(
TARGET ${TARGET_NAME} # 关联到目标
POST_BUILD # 在目标构建完成后执行
COMMAND ${CMAKE_COMMAND} -E copy_if_different # 使用 cmake 内建命令复制文件 (仅在文件不同时复制)
"${ABS_RESOURCE_FILE}" # 源文件 (绝对路径)
"${DESTINATION_DIR}/${RESOURCE_FILENAME}" # **目标路径** (可执行文件目录 + 文件名)
COMMENT "正在复制资源 ${RESOURCE_FILENAME} 到 ${TARGET_NAME} 的输出目录" # 构建时显示的注释
VERBATIM # 确保特殊字符被正确处理
)
# (可选) 将资源文件添加到目标源文件中,以便在某些 IDE 中显示
# 注意:如果文件不在源目录树下,某些 IDE 可能不会正确显示
# target_sources(${TARGET_NAME} PRIVATE "${ABS_RESOURCE_FILE}")
endforeach()
endfunction()