From 722a2eed5aa9951137b6c875fb38b7069fd7da14 Mon Sep 17 00:00:00 2001 From: nanako <469449812@qq.com> Date: Tue, 12 Aug 2025 23:03:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20CMake=20=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=B9=B6=E6=B7=BB=E5=8A=A0=E6=93=8D=E4=BD=9C=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/CMakeLists.txt | 86 +++++++++++++++++--- src/backend/vcpkg.json | 2 +- src/cmake_script/detect_os.cmake | 131 +++++++++++++++++++++++++++++++ src/frontend/frontend.csproj | 9 ++- 4 files changed, 216 insertions(+), 12 deletions(-) create mode 100644 src/cmake_script/detect_os.cmake diff --git a/src/backend/CMakeLists.txt b/src/backend/CMakeLists.txt index f9f69b6..12a1ddc 100644 --- a/src/backend/CMakeLists.txt +++ b/src/backend/CMakeLists.txt @@ -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 参数来指定构建目录, +# 以支持灵活的 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) \ No newline at end of file diff --git a/src/backend/vcpkg.json b/src/backend/vcpkg.json index 5324f2b..deb3dcf 100644 --- a/src/backend/vcpkg.json +++ b/src/backend/vcpkg.json @@ -2,7 +2,7 @@ "dependencies": [ "grpc", "protobuf", - "zeromq", + "cppzmq", "gtest" ], "version": "0.0.1", diff --git a/src/cmake_script/detect_os.cmake b/src/cmake_script/detect_os.cmake new file mode 100644 index 0000000..7ff84be --- /dev/null +++ b/src/cmake_script/detect_os.cmake @@ -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) diff --git a/src/frontend/frontend.csproj b/src/frontend/frontend.csproj index 974ea02..56c95da 100644 --- a/src/frontend/frontend.csproj +++ b/src/frontend/frontend.csproj @@ -24,9 +24,16 @@ All + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + - +