优化 CMake 配置并添加操作系统检测脚本

This commit is contained in:
2025-08-12 23:03:03 +08:00
parent fa4f9720f1
commit 722a2eed5a
4 changed files with 216 additions and 12 deletions

View File

@@ -1,33 +1,99 @@
# ==============================================================================
# NinaEngine - 构建脚本
#
# 核心职责:
# 该 CMakeLists.txt 文件负责定义 "NinaEngine" 可执行文件的完整构建流程。
# 它涵盖了从项目基础配置、依赖库的查找与链接,到 Protocol Buffers
# 文件的自动代码生成等所有关键步骤。
#
# 设计思路:
# 脚本遵循模块化和声明式的原则,将不同阶段的构建逻辑清晰地分离开来。
# 通过引入外部的 cmake_script 模块将通用的配置如C++标准、文件检索)
# 与核心构建逻辑解耦,提高了可维护性和复用性。
# ==============================================================================
# --- 项目基础设置 (Basic Project Setup) ---
# 定义了项目构建所需的最低 CMake 版本和项目名称。
cmake_minimum_required(VERSION 3.14)
project(NinaEngine)
include(../cmake_script/project_cpp_standard.cmake)
include(../cmake_script/retrieve_files.cmake)
include(../cmake_script/utils.cmake)
# --- 自定义脚本与配置 (Custom Scripts & Configuration) ---
# 引入外部 CMake 脚本模块以处理通用任务,保持主脚本的整洁。
include(../cmake_script/project_cpp_standard.cmake) # 负责设置 C++ 标准。
include(../cmake_script/retrieve_files.cmake) # 负责递归查找源文件。
include(../cmake_script/utils.cmake) # 提供其他工具函数,如 compile_proto_files。
# 使用自定义函数来配置项目的编译选项。
# @param STANDARD: 指定C++语言标准,此处为 C++23。
# @param INTERFACE_TARGET: 创建一个名为 config_target 的 INTERFACE 目标,
# 用于传递编译选项、宏定义等,方便统一管理。
setup_project_options(
STANDARD 23
INTERFACE_TARGET config_target
)
# NOTE: 硬编码构建目录可能会降低灵活性。
# 通常,更推荐的做法是让用户在调用 CMake 时通过 -B <build_dir> 参数来指定构建目录,
# 以支持灵活的 out-of-source builds。
# 此处强制将构建目录设置在项目根目录的上一级中的 `build` 文件夹。
set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/../../build)
# 调用自定义函数为项目配置默认的编译器警告、输出路径等。
configure_project_defaults()
set(SRC_FILS "")
# --- 源代码文件管理 (Source File Management) ---
# 初始化一个变量用于存储所有源文件的路径。
set(SRC_FILES "")
# 调用自定义函数递归地从 'src' 目录中检索所有源文件,
# 并将文件列表追加到 SRC_FILES 变量中。
# @param CMAKE_CURRENT_SOURCE_DIR/src: 要搜索的源文件根目录。
# @param SRC_FILES: 用于接收文件列表的输出变量。
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_FILES)
# --- 依赖库查找 (Dependency Discovery) ---
# 查找项目所需的核心第三方库。`REQUIRED` 参数表示如果找不到库CMake 将会报错并停止构建。
find_package(gRPC CONFIG REQUIRED)
find_package(Protobuf CONFIG REQUIRED)
find_package(ZeroMQ CONFIG REQUIRED)
find_package(gRPC REQUIRED)
find_package(Protobuf REQUIRED)
find_package(ZeroMQ REQUIRED)
# --- 可执行文件目标定义 (Executable Target Definition) ---
# 创建一个名为 NinaEngine (与项目名相同) 的可执行文件。
# @param ${PROJECT_NAME}: 目标名称。
# @param ${SRC_FILES}: 构成该目标的所有源文件。
add_executable(${PROJECT_NAME} ${SRC_FILES})
target_link_libraries(${PROJECT_NAME} PRIVATE config_target)
target_link_libraries(${PROJECT_NAME} PRIVATE gRPC::grpc++ protobuf::libprotobuf zmq)
# 将依赖库链接到我们的可执行文件目标。
# @param ${PROJECT_NAME}: 要链接的目标。
# @param PRIVATE: 表示链接的依赖项仅对 ${PROJECT_NAME} 自身可见,
# 不会传递给链接到 ${PROJECT_NAME} 的其他目标。
# @param config_target: 链接之前创建的接口目标,以应用通用的编译设置。
# @param gRPC::grpc++: gRPC 库提供的 C++ 目标。
# @param protobuf::libprotobuf: Protobuf 运行时库目标。
# @param zmq: ZeroMQ 库目标。
target_link_libraries(${PROJECT_NAME} PRIVATE
config_target
gRPC::grpc++
protobuf::libprotobuf
libzmq
)
# --- Protocol Buffers 编译 (Protocol Buffers Compilation) ---
# 使用自定义函数编译 .proto 文件,自动生成 C++ 源代码和 gRPC 服务代码。
# 这是一个典型的代码生成步骤,需要在编译主程序源代码之前完成。
# @param TARGET_NAME: 为生成的代码创建一个内部目标名称,用于依赖管理。
# @param PROTO_PATH: 存放 .proto 定义文件的目录。
# @param OUTPUT_PATH: 生成的 .pb.h, .pb.cc, .grpc.pb.h, .grpc.pb.cc 文件的输出目录。
# @param GRPC_ENABLED: 设置为 TRUE表示同时生成 gRPC 服务相关的代码。
compile_proto_files(
TARGET_NAME ${PROJECT_NAME}_proto
PROTO_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../proto
OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/proto
GRPC_ENABLED TRUE
)
# --- 目标依赖关系 (Target Dependencies) ---
# 显式声明主目标对 proto 代码生成目标的依赖。
# 这确保了在编译 NinaEngine 之前,所有 .proto 文件都已经被成功编译和生成。
# 如果没有这个依赖关系,构建可能会因为找不到生成的头文件而失败。
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_proto)

View File

@@ -2,7 +2,7 @@
"dependencies": [
"grpc",
"protobuf",
"zeromq",
"cppzmq",
"gtest"
],
"version": "0.0.1",

View File

@@ -0,0 +1,131 @@
# 定义一个函数,为指定的目标添加操作系统和架构相关的预处理器定义
function(add_os_definitions target)
# 检查 target 参数是否提供
if(NOT target)
message(FATAL_ERROR "函数 add_os_definitions 需要一个 target 参数。")
return()
endif()
# --- 阶段 1: 确定宏的值 ---
# 初始化所有平台、架构和特性宏的值为 0
set(mirage_def_windows 0)
set(mirage_def_macos 0)
set(mirage_def_linux 0)
set(mirage_def_freebsd 0)
set(mirage_def_ios 0)
set(mirage_def_android 0)
set(mirage_def_cygwin 0)
set(mirage_def_unix 0)
set(mirage_def_posix 0)
set(mirage_def_mobile 0)
set(mirage_def_arch_64bit 0)
set(mirage_def_arch_32bit 0)
# -- 操作系统检测与赋值 --
# 注意检测顺序:优先检测更具体的平台
if(CYGWIN)
# Cygwin 环境比较特殊,它在 Windows 上模拟 Unix
set(mirage_def_windows 1) # 基础是 Windows
set(mirage_def_cygwin 1) # 明确是 Cygwin
set(mirage_def_unix 1) # 提供 Unix API
set(mirage_def_posix 1) # 提供 POSIX API
message(STATUS "检测到 **Cygwin** 环境 (运行于 Windows)")
elseif(WIN32)
# 非 Cygwin 的 Windows 环境 (MSVC, MinGW, etc.)
set(mirage_def_windows 1)
message(STATUS "检测到 **Windows** 操作系统 (非 Cygwin)")
elseif(ANDROID)
# Android 平台 (通常需要特定工具链设置 ANDROID 变量)
set(mirage_def_android 1)
set(mirage_def_unix 1) # Android NDK 基于 Unix
set(mirage_def_posix 1) # NDK 提供 POSIX API
set(mirage_def_mobile 1) # 移动平台
message(STATUS "检测到 **Android** 操作系统")
elseif(IOS)
# iOS 平台 (通常需要特定工具链设置 IOS 变量)
# 需要在 APPLE 之前判断,因为 iOS 下 APPLE 也为 TRUE
set(mirage_def_ios 1)
set(mirage_def_unix 1) # iOS (Darwin) 基于 Unix
set(mirage_def_posix 1) # 提供 POSIX API
set(mirage_def_mobile 1) # 移动平台
message(STATUS "检测到 **iOS** 操作系统")
elseif(APPLE)
# 此时排除了 iOS确定是 macOS
set(mirage_def_macos 1)
set(mirage_def_unix 1) # macOS (Darwin) 基于 Unix
set(mirage_def_posix 1) # 提供 POSIX API
message(STATUS "检测到 **macOS** 操作系统")
elseif(UNIX)
# 此时排除了 Apple, Android, Cygwin 的其他 Unix-like 系统
set(mirage_def_unix 1)
set(mirage_def_posix 1)
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
set(mirage_def_linux 1)
message(STATUS "检测到 **Linux** 操作系统")
elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
set(mirage_def_freebsd 1)
message(STATUS "检测到 **FreeBSD** 操作系统")
else()
message(WARNING "检测到未知的 类Unix 操作系统: ${CMAKE_SYSTEM_NAME}")
endif()
else()
message(WARNING "检测到未知的操作系统: ${CMAKE_SYSTEM_NAME}")
endif()
# -- 架构检测与赋值 --
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(mirage_def_arch_64bit 1)
set(mirage_def_arch_32bit 0) # 明确设置为 0
message(STATUS "检测到 **64-bit** 架构")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(mirage_def_arch_64bit 0) # 明确设置为 0
set(mirage_def_arch_32bit 1)
message(STATUS "检测到 **32-bit** 架构")
else()
# 对于未知或未定义的指针大小,两者都保持 0
message(WARNING "无法明确检测到 32-bit 或 64-bit 架构 (CMAKE_SIZEOF_VOID_P = ${CMAKE_SIZEOF_VOID_P})。将两者都设置为 0。")
endif()
# --- 阶段 2: 组装定义列表 ---
set(definitions_list "") # 初始化空列表
# 添加平台定义
list(APPEND definitions_list "MIRAGE_PLATFORM_WINDOWS=${mirage_def_windows}")
list(APPEND definitions_list "MIRAGE_PLATFORM_MACOS=${mirage_def_macos}")
list(APPEND definitions_list "MIRAGE_PLATFORM_LINUX=${mirage_def_linux}")
list(APPEND definitions_list "MIRAGE_PLATFORM_FREEBSD=${mirage_def_freebsd}")
list(APPEND definitions_list "MIRAGE_PLATFORM_IOS=${mirage_def_ios}")
list(APPEND definitions_list "MIRAGE_PLATFORM_ANDROID=${mirage_def_android}")
list(APPEND definitions_list "MIRAGE_PLATFORM_CYGWIN=${mirage_def_cygwin}")
# 添加架构定义
list(APPEND definitions_list "MIRAGE_PLATFORM_ARCH_64BIT=${mirage_def_arch_64bit}")
list(APPEND definitions_list "MIRAGE_PLATFORM_ARCH_32BIT=${mirage_def_arch_32bit}")
# 添加特性定义
list(APPEND definitions_list "MIRAGE_PLATFORM_UNIX=${mirage_def_unix}")
list(APPEND definitions_list "MIRAGE_PLATFORM_POSIX=${mirage_def_posix}")
list(APPEND definitions_list "MIRAGE_PLATFORM_IS_MOBILE=${mirage_def_mobile}")
# --- 阶段 3: 应用所有定义 ---
# **关键:使用一次调用将所有定义添加到目标**
if(definitions_list) # 确保列表非空
target_compile_definitions(${target} PUBLIC ${definitions_list})
endif()
# 函数作用域结束时mirage_def_* 变量会自动销毁,无需显式 unset
endfunction()
# --- 使用示例 ---
# project(MyProject)
# add_executable(my_app main.c)
#
# # 调用函数为 my_app 添加平台定义
# add_os_definitions(my_app)
#
# # 你也可以为库调用
# # add_library(my_lib STATIC my_lib.c)
# # add_os_definitions(my_lib)

View File

@@ -24,9 +24,16 @@
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1"/>
<PackageReference Include="Google.Protobuf" Version="3.32.0-rc2" />
<PackageReference Include="Grpc.Core.Api" Version="2.71.0" />
<PackageReference Include="Grpc.Tools" Version="2.72.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NetMQ" Version="4.0.2.1" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="..\proto\daw\*.proto" GrpcServices="Client" />
<Protobuf Include="..\proto\*.proto" GrpcServices="Client" />
</ItemGroup>
</Project>