Files
SunnyLand/cmake/Dependencies.cmake
T

256 lines
10 KiB
CMake
Raw Normal View History

2025-10-10 07:54:19 +08:00
# ============================================
# 依赖管理模块
# ============================================
# 功能:智能依赖获取和管理
# 包含FetchContent模块
include(FetchContent)
# 设置FetchContent配置
set(FETCHCONTENT_QUIET OFF)
set(FETCHCONTENT_UPDATES_DISCONNECTED ON)
# ============================================
# 辅助宏:查找或获取依赖(智能浅克隆 + 链接类型控制)
# 用法如下:
#
# 参数说明:
# DEP_NAME - 依赖的内部名称(用于FetchContent和add_subdirectory等)
# PACKAGE_NAME - 依赖的包名(用于find_package查找本地已安装的包)
# GIT_REPO - 依赖的Git仓库地址(用于FetchContent在线获取源码)
# GIT_TAG - 依赖的Git分支、标签或commit hash(用于指定获取源码的版本)
# LOCAL_PATH - 本地源码路径(如 external/SDL),用于本地源码方式
# LINK_TYPE - 链接类型:STATIC(静态) / SHARED(动态) / AUTO(使用全局BUILD_SHARED_LIBS)
# ============================================
macro(find_or_fetch_dependency DEP_NAME PACKAGE_NAME GIT_REPO GIT_TAG LOCAL_PATH LINK_TYPE)
message(STATUS "正在处理依赖: ${DEP_NAME}")
# 确定该库的链接类型
if("${LINK_TYPE}" STREQUAL "STATIC")
set(_LIB_IS_SHARED OFF)
set(_LINK_TYPE_STR "静态")
elseif("${LINK_TYPE}" STREQUAL "SHARED")
set(_LIB_IS_SHARED ON)
set(_LINK_TYPE_STR "动态")
else() # AUTO 或其他值,使用全局设置
set(_LIB_IS_SHARED ${BUILD_SHARED_LIBS})
if(BUILD_SHARED_LIBS)
set(_LINK_TYPE_STR "动态(全局)")
else()
set(_LINK_TYPE_STR "静态(全局)")
endif()
endif()
# 首先尝试查找本地已安装的包
find_package(${PACKAGE_NAME} QUIET)
if(${PACKAGE_NAME}_FOUND OR ${DEP_NAME}_FOUND)
message(STATUS " ✓ 找到本地安装的 ${PACKAGE_NAME}")
# 打印包的路径信息(尝试多种可能的变量)
if(DEFINED ${PACKAGE_NAME}_DIR)
message(STATUS " 路径: ${${PACKAGE_NAME}_DIR}")
elseif(DEFINED ${DEP_NAME}_DIR)
message(STATUS " 路径: ${${DEP_NAME}_DIR}")
elseif(DEFINED ${PACKAGE_NAME}_ROOT)
message(STATUS " 根目录: ${${PACKAGE_NAME}_ROOT}")
elseif(DEFINED ${DEP_NAME}_ROOT)
message(STATUS " 根目录: ${${DEP_NAME}_ROOT}")
elseif(DEFINED ${PACKAGE_NAME}_INCLUDE_DIRS)
message(STATUS " 头文件: ${${PACKAGE_NAME}_INCLUDE_DIRS}")
elseif(DEFINED ${DEP_NAME}_INCLUDE_DIRS)
message(STATUS " 头文件: ${${DEP_NAME}_INCLUDE_DIRS}")
endif()
else()
message(STATUS " ✗ 未找到本地安装,准备从源码构建 [${_LINK_TYPE_STR}]")
# 配置库特定的编译选项(在add_subdirectory/FetchContent之前)
# SDL系列库的特定选项
if("${DEP_NAME}" MATCHES "^SDL" OR "${PACKAGE_NAME}" MATCHES "^SDL")
if(_LIB_IS_SHARED)
set(SDL_SHARED ON CACHE BOOL "" FORCE)
set(SDL_STATIC OFF CACHE BOOL "" FORCE)
else()
set(SDL_SHARED OFF CACHE BOOL "" FORCE)
set(SDL_STATIC ON CACHE BOOL "" FORCE)
endif()
# 禁用SDL测试
set(SDL_TEST_LIBRARY OFF CACHE BOOL "" FORCE)
set(SDL_TESTS OFF CACHE BOOL "" FORCE)
set(SDL_INSTALL_TESTS OFF CACHE BOOL "" FORCE)
endif()
# 其他库的通用选项
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(BUILD_DOCS OFF CACHE BOOL "" FORCE)
# SDL_image特定选项:禁用可能导致构建问题的格式支持
if("${DEP_NAME}" STREQUAL "SDL3_image")
# 禁用AVIF格式(需要NASM、Meson等复杂工具链)
set(SDLIMAGE_AVIF OFF CACHE BOOL "" FORCE)
set(SDLIMAGE_AVIF_SHARED OFF CACHE BOOL "" FORCE)
set(SDLIMAGE_AVIF_SAVE OFF CACHE BOOL "" FORCE)
# 禁用AVIF的依赖库
set(SDLIMAGE_AVIF_VENDORED OFF CACHE BOOL "" FORCE)
set(SDLIMAGE_DAV1D OFF CACHE BOOL "" FORCE)
set(SDLIMAGE_AOM OFF CACHE BOOL "" FORCE)
# 可选:禁用其他可能有构建问题的格式
# set(SDLIMAGE_JXL OFF CACHE BOOL "" FORCE) # JPEG XL
endif()
# 智能选择:优先本地源码,否则在线获取
set(LOCAL_SOURCE_DIR ${CMAKE_SOURCE_DIR}/${LOCAL_PATH})
if(EXISTS ${LOCAL_SOURCE_DIR})
# 检测到本地源码,使用本地编译
message(STATUS " → 使用本地源码: ${LOCAL_SOURCE_DIR}")
# 临时设置BUILD_SHARED_LIBS影响该库
set(_SAVED_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS ${_LIB_IS_SHARED} CACHE BOOL "" FORCE)
# add_subdirectory参数说明:
# 1.源码目录(${LOCAL_SOURCE_DIR}),即依赖库的本地源码路径;
# 2.二进制输出目录(${CMAKE_BINARY_DIR}/_deps/${DEP_NAME}-build),即该依赖库的构建输出会放到这里,避免污染主项目的build目录。
add_subdirectory(${LOCAL_SOURCE_DIR} ${CMAKE_BINARY_DIR}/_deps/${DEP_NAME}-build)
# 恢复全局设置
set(BUILD_SHARED_LIBS ${_SAVED_BUILD_SHARED_LIBS} CACHE BOOL "" FORCE)
# 确保命名空间别名存在(兼容性处理)
# 某些库从源码编译时可能不会自动创建带命名空间的ALIAS target
# 这里统一创建 PACKAGE_NAME::PACKAGE_NAME 格式的别名
if(TARGET ${DEP_NAME} AND NOT TARGET ${PACKAGE_NAME}::${PACKAGE_NAME})
message(STATUS " 创建别名: ${PACKAGE_NAME}::${PACKAGE_NAME} -> ${DEP_NAME}")
add_library(${PACKAGE_NAME}::${PACKAGE_NAME} ALIAS ${DEP_NAME})
elseif(TARGET ${PACKAGE_NAME} AND NOT TARGET ${PACKAGE_NAME}::${PACKAGE_NAME})
message(STATUS " 创建别名: ${PACKAGE_NAME}::${PACKAGE_NAME} -> ${PACKAGE_NAME}")
add_library(${PACKAGE_NAME}::${PACKAGE_NAME} ALIAS ${PACKAGE_NAME})
endif()
else()
# 本地源码不存在,使用FetchContent在线获取
message(STATUS " → 本地源码不存在,在线获取: ${GIT_REPO}")
# 智能检测GIT_TAG类型,决定是否使用浅克隆
string(LENGTH "${GIT_TAG}" TAG_LENGTH)
string(REGEX MATCH "^[0-9a-f]+$" IS_HEX "${GIT_TAG}")
# 判断是否为commit hash(40位十六进制字符串)
if(TAG_LENGTH EQUAL 40 AND IS_HEX)
message(STATUS " 版本: commit hash [${GIT_TAG}],完整克隆")
set(USE_SHALLOW FALSE)
else()
message(STATUS " 版本: ${GIT_TAG},浅克隆")
set(USE_SHALLOW TRUE)
endif()
# FetchContent_Declare用于声明一个FetchContent对象,用于在线获取依赖库源码。
# 参数说明:
# DEP_NAME - 依赖的内部名称(用于FetchContent和add_subdirectory等)
# GIT_REPOSITORY - 依赖的Git仓库地址
# GIT_TAG - 依赖的Git分支、标签或commit hash
# GIT_SHALLOW - 是否使用浅克隆(TRUE/FALSE),根据GIT_TAG类型自动判断
# GIT_PROGRESS - 是否显示Git进度(TRUE/FALSE)
# 临时设置BUILD_SHARED_LIBS影响该库
set(_SAVED_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS ${_LIB_IS_SHARED} CACHE BOOL "" FORCE)
FetchContent_Declare(
${DEP_NAME}
GIT_REPOSITORY ${GIT_REPO}
GIT_TAG ${GIT_TAG}
GIT_SHALLOW ${USE_SHALLOW}
GIT_PROGRESS TRUE
)
FetchContent_MakeAvailable(${DEP_NAME})
# 恢复全局设置
set(BUILD_SHARED_LIBS ${_SAVED_BUILD_SHARED_LIBS} CACHE BOOL "" FORCE)
endif()
endif()
endmacro()
# ============================================
# 设置所有项目依赖
# ============================================
function(setup_project_dependencies)
# SDL3
find_or_fetch_dependency(
SDL3
SDL3
"https://github.com/libsdl-org/SDL.git"
"release-3.2.24"
"external/SDL-release-3.2.24"
AUTO # 使用全局BUILD_SHARED_LIBS设置
)
# SDL3_image
# 注意:已自动禁用AVIF格式支持(需要NASM、Meson等复杂工具链)
# 如需启用AVIF,请修改宏中的SDLIMAGE_AVIF选项,并安装所需工具:
# - NASM: https://www.nasm.us/
# - Meson: pip install meson ninja
# - Perl: https://strawberryperl.com/
find_or_fetch_dependency(
SDL3_image
SDL3_image
"https://github.com/libsdl-org/SDL_image.git"
"release-3.2.4"
"external/SDL_image-release-3.2.4"
AUTO # 使用全局BUILD_SHARED_LIBS设置
)
# SDL3_mixer
find_or_fetch_dependency(
SDL3_mixer
SDL3_mixer
"https://github.com/libsdl-org/SDL_mixer.git"
"30c1301055a35ee87b8679279b6fc88e10d28fa3"
"external/SDL_mixer-30c1301"
AUTO # 使用全局BUILD_SHARED_LIBS设置
)
# SDL3_ttf
find_or_fetch_dependency(
SDL3_ttf
SDL3_ttf
"https://github.com/libsdl-org/SDL_ttf.git"
"release-3.2.2"
"external/SDL_ttf-release-3.2.2"
AUTO # 使用全局BUILD_SHARED_LIBS设置
)
# GLM
find_or_fetch_dependency(
glm
glm
"https://github.com/g-truc/glm.git"
"1.0.1"
"external/glm-1.0.1"
STATIC # GLM通常使用静态链接,动态很可能出错
)
# nlohmann-json (header-only库)
# 注意:FetchContent内部名称用json,但find_package用nlohmann_json
find_or_fetch_dependency(
json
nlohmann_json
"https://github.com/nlohmann/json.git"
"v3.12.0"
"external/json-3.12.0"
STATIC # header-only库,实际不影响
)
# spdlog
find_or_fetch_dependency(
spdlog
spdlog
"https://github.com/gabime/spdlog.git"
"v1.15.3"
"external/spdlog-1.15.3"
STATIC # 推荐静态链接,避免运行时依赖
)
endfunction()