1. 跨平台工程开发导论
跨平台工程开发,并不是“写一份代码,到处都能跑”这么简单。更准确地说,它是在多个目标平台之间,用一套可维护的工程方法,让同一份核心逻辑尽可能复用,同时把不可避免的平台差异隔离在清晰、可控的边界内。理解这个定义,是后续所有工具链、构建系统、抽象层设计的前提。
跨平台的定义与边界
跨平台通常包含三个层次:源码级跨平台、构建级跨平台和运行级跨平台。源码级指同一份 C++ 源码能在不同平台编译通过;构建级指同一套构建脚本能驱动不同平台的编译器和链接器;运行级指产物在目标平台上行为一致。三者难度递增,边界也各不相同。
边界在哪里?边界就在“平台相关”与“平台无关”的分界线上。文件路径分隔符、字节序、线程模型、系统 API、图形接口、动态库加载方式,这些都属于平台相关部分。而算法、数据结构、业务规则、协议解析,通常可以做到平台无关。跨平台工程的核心工作,就是尽量扩大平台无关区域,把平台相关代码压缩到少数适配层中。
需要特别说明的是,跨平台不等于“零平台代码”。一个健康的跨平台项目,通常会有 70%~90% 的代码完全共享,剩余部分通过条件编译、接口抽象或独立适配模块处理。追求 100% 共享往往会导致过度抽象,反而增加维护成本。
C++ 在跨平台场景中的优势与代价
C++ 之所以长期占据跨平台开发的核心位置,主要优势有三点。第一,编译型语言使其能直接生成各平台原生机器码,不依赖虚拟机或运行时解释器,性能可控。第二,标准库与语言标准提供了跨平台的基础抽象,如 std::thread、std::filesystem、std::chrono,减少了直接调用系统 API 的需求。第三,成熟的工具链生态,如 CMake、Conan、vcpkg、Clang/GCC/MSVC,使多平台构建成为可能。
但代价同样明显。首先是编译器差异:MSVC、GCC、Clang 对标准支持程度、扩展语法、警告级别各不相同。其次是ABI 不兼容:不同编译器、不同标准库版本生成的二进制接口可能无法混用。第三是平台 API 差异:Windows 的 Win32、Linux 的 POSIX、macOS 的 Cocoa 在文件、网络、线程、图形上差异巨大。第四是构建与依赖管理复杂:同一份第三方库在不同平台可能需要不同编译选项甚至不同版本。
主流平台差异概览
课程涉及的主要目标平台包括 Windows、Linux、macOS,以及可选的 Android/iOS 移动端。它们在以下维度存在显著差异:
| 维度 | Windows | Linux | macOS |
|---|---|---|---|
| 编译器 | MSVC / Clang-cl | GCC / Clang | Apple Clang |
| 可执行文件 | .exe / .dll | ELF / .so | Mach-O / .dylib |
| 路径分隔符 | \ | / | / |
| 换行符 | \r\n | \n | \n |
| 线程库 | Win32 Thread | pthread | pthread |
| 包管理 | vcpkg / Conan | apt / Conan | Homebrew / Conan |
这些差异决定了跨平台工程必须建立统一的抽象层和构建规范。例如,路径拼接不能硬编码 "\\",而应使用 std::filesystem::path;动态库加载不能直接调用 LoadLibrary 或 dlopen,而应封装成统一接口。
课程工具链与项目目标
本课程统一采用以下工具链:CMake 3.20+ 作为构建系统,Conan 2.x 或 vcpkg 作为依赖管理,GCC 11+ / Clang 14+ / MSVC 2022 作为编译器,Git 作为版本控制,GoogleTest 作为单元测试框架。项目目标是一个可跨 Windows、Linux、macOS 构建和运行的 C++ 工程模板,包含核心库、平台适配层、测试用例和 CI 配置。
下面这张图展示了跨平台工程的整体结构关系:核心逻辑位于中心,平台适配层包裹在外,构建系统与依赖管理贯穿所有平台。它帮助你在后续章节中始终看清“哪些代码该共享、哪些代码该隔离”。
从图中可以看到,跨平台工程不是把所有代码混在一起,而是分层组织:核心逻辑层保持平台无关,平台适配层负责对接各系统 API,构建与依赖管理层统一驱动三个平台。后续章节将围绕这个结构,逐步展开 CMake 配置、条件编译、抽象接口设计、依赖管理和持续集成等具体实践。