239 lines
9.1 KiB
CMake
239 lines
9.1 KiB
CMake
#[=======================================================================[
|
||
平台匹配检查函数
|
||
参数:
|
||
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() |