Unity集成C++库:用vcpkg+CMake告别插件集成噩梦
1. 项目概述:为什么我们需要告别插件集成噩梦?
如果你是一名Unity开发者,同时又需要深度使用C++库——无论是为了追求极限性能、复用成熟的算法库,还是为了接入特定的硬件SDK——那么你大概率经历过我所说的“插件集成噩梦”。这个噩梦通常由几个场景构成:好不容易找到一个功能强大的C++库,却发现它的编译环境要求(比如特定的Visual Studio版本、Windows SDK版本)和你的Unity项目不匹配;手动编译出一堆.dll、.lib文件,却因为运行时库(MSVCRT)版本冲突导致Unity编辑器崩溃;或者,当你尝试为不同平台(Windows、Android、iOS)编译时,发现每个平台都需要一套完全不同的构建脚本和依赖项,维护成本呈指数级上升。
传统的解决方案,比如手动下载源码编译、使用预编译的二进制包,或者依赖一些不那么活跃的第三方Unity Asset Store插件,都充满了不确定性。一个库的更新可能意味着你需要重新经历一遍整个繁琐的配置过程。这正是vcpkg这个由微软维护的开源C/C++包管理器所要解决的问题。它不是一个新概念,但在Unity工作流中,它的价值被严重低估了。简单来说,vcpkg能帮你自动解决C++库的下载、编译、依赖管理和跨平台构建问题。而我们的目标,就是通过一套清晰的流程,将vcpkg与Unity引擎无缝对接,让你能够像引用一个普通的C#脚本一样,稳定、可重复地使用任何vcpkg仓库中超过2800个C++库。
这不仅仅是“安装一个库”那么简单。这是一套工程化解决方案,它关乎项目的长期可维护性、团队协作的一致性,以及作为技术决策者的你,能否从无穷尽的环境配置中解放出来,专注于真正的业务逻辑开发。接下来,我将以一个真实的集成场景为例,带你走通这七个关键步骤。
2. 核心思路与工具选型解析
在深入实操之前,我们必须理解为什么是vcpkg+CMake+Unity这个组合,以及它们各自扮演的角色。这决定了整个方案的稳定性和扩展性。
2.1 为什么是vcpkg,而不是Conan或手动管理?
C++的依赖管理一直是个历史难题。vcpkg的核心优势在于它的“集成”和“稳定”。
- 开箱即用的Visual Studio集成:对于Windows平台开发,
vcpkg与Visual Studio的MSBuild系统深度集成。通过vcpkg integrate install命令,它能将自身管理的库目录自动添加到Visual Studio的全局搜索路径中。这意味着,当你用Visual Studio打开一个CMake项目时,它几乎能自动找到所有通过vcpkg安装的库的头文件和链接库,无需手动配置INCLUDE和LIB环境变量。这对于Unity插件开发(通常需要在Visual Studio中编写和编译C++代码)来说,是巨大的便利。 - 版本管理与清单模式:
vcpkg支持“清单模式”。你可以在项目根目录创建一个vcpkg.json文件,像package.json或requirements.txt一样,明确定义项目依赖的库及其版本。结合vcpkg-configuration.json,你甚至可以指定使用哪个版本的vcpkg本身以及库的源。这确保了在任何一台新机器上,执行vcpkg install都能获得完全一致的依赖环境,完美解决了“在我机器上是好的”这一经典问题。 - 庞大的官方库生态与三元组:
vcpkg拥有超过2800个经过验证的库端口(port)。更重要的是,它通过“三元组”来精确定义目标平台、架构和链接方式(例如x64-windows、x64-windows-static、arm64-android)。这为Unity的多平台发布提供了天然支持。你可以为Windows编辑器环境安装动态链接库,同时为Android发布环境安装静态链接库,vcpkg会帮你处理好所有平台相关的编译细节。
相比之下,Conan虽然同样强大且灵活,但其配置相对复杂,与Visual Studio的集成不如vcpkg直接。手动管理则完全不可取,会迅速将项目拖入维护地狱。
2.2 CMake:连接vcpkg与Unity的桥梁
Unity原生支持通过.asmdef和直接引用DLL来使用C++插件,但对于需要从源码编译、且依赖其他C++库的复杂项目,直接配置Unity的构建系统会非常棘手。CMake在这里扮演了“构建系统生成器”的角色。
- 标准化构建流程:
CMake允许你用一份相对平台无关的CMakeLists.txt文件来描述你的C++插件项目:需要哪些源文件、头文件目录在哪、链接哪些库、输出什么目标(动态库.dll/.so或静态库.lib/.a)。 - 与vcpkg无缝对接:
CMake可以通过工具链文件与vcpkg联动。在调用cmake配置项目时,我们传入-DCMAKE_TOOLCHAIN_FILE=[vcpkg根目录]/scripts/buildsystems/vcpkg.cmake参数。CMake在查找依赖库时,就会优先从vcpkg的安装目录中寻找,完美解决了依赖查找问题。 - 生成Visual Studio工程:对于Windows开发,我们可以让
CMake生成一个.sln解决方案文件。开发者可以在熟悉的Visual Studio环境中进行编码、调试和编译,生成的DLL再被Unity引用。这比直接在Unity中配置编译命令要直观和强大得多。
2.3 Unity端的角色:消费者与桥接
Unity在这个流程中是最终的“消费者”。它的职责清晰而有限:
- 提供C#端接口:定义
[DllImport]或使用更安全的封装(如通过NativePlugin接口)。 - 加载原生插件:将编译好的平台特定原生插件(如
Windows/x86_64/MyPlugin.dll)放置在项目的Assets/Plugins目录下对应的子文件夹中。 - 调用与交互:通过P/Invoke或Unity提供的原生插件接口,实现C#与C++之间的数据传递和函数调用。
整个流程的架构可以概括为:用vcpkg管理C++依赖,用CMake描述并构建你的C++插件项目,最后将产物交给Unity使用。这个分工明确了各工具的边界,使得每个环节都可以独立优化和调试。
3. 环境准备与工具链配置
工欲善其事,必先利其器。这一步的目标是搭建一个可重复、隔离的构建环境。我强烈建议不要使用系统全局环境,而是为每个项目或一类项目创建独立的环境。
3.1 安装与配置vcpkg
首先,我们以“本地模式”安装vcpkg。这意味着vcpkg本身和它安装的库都将位于你的项目目录或一个专门的工作目录下,与系统其他项目隔离。
# 1. 选择一个工作目录,例如 D:\Dev\UnityNativeWorkflow cd D:\Dev\UnityNativeWorkflow # 2. 克隆 vcpkg 仓库 git clone https://github.com/Microsoft/vcpkg.git # 3. 进入 vcpkg 目录并执行引导脚本 cd vcpkg .\bootstrap-vcpkg.bat # Windows系统 # 如果是 macOS/Linux: ./bootstrap-vcpkg.sh引导脚本会编译出vcpkg.exe可执行文件。
注意:国内网络环境克隆GitHub仓库或下载库源码可能较慢。
vcpkg支持配置镜像源来加速下载。你可以在vcpkg目录下创建或修改vcpkg-configuration.json文件。一个常用的配置是使用清华大学的镜像(请务必查阅镜像源官方页面获取最新且正确的配置,以下为示例格式):{ "default-registry": { "kind": "git", "repository": "https://github.com/microsoft/vcpkg", "baseline": "a1c8f1c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c" }, "registries": [ { "kind": "artifact", "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", "name": "microsoft" } ] }实际上,更常见的加速方式是设置环境变量
VCPKG_DOWNLOADS指向一个本地缓存目录,并手动或通过代理工具解决网络问题。直接替换整个默认注册表存在风险,可能导致库版本不一致。
接下来,将vcpkg集成到Visual Studio(如果你主要做Windows开发):
.\vcpkg integrate install这个命令会输出类似“Applied user-wide integration for this vcpkg root.”的信息。它修改了Visual Studio的用户级配置,让VS能自动识别从这个vcpkg根目录安装的库。
3.2 安装CMake与Visual Studio构建工具
- CMake:从官网下载安装程序,安装时勾选“Add CMake to the system PATH for all users”或“Add CMake to the system PATH for current user”,确保可以在命令行中直接使用
cmake命令。 - Visual Studio Build Tools:即使你使用其他IDE(如VSCode、CLion),在Windows上编译C++代码通常也需要Visual Studio的编译器和构建工具。请安装Visual Studio 2022,并在安装工作负载时,至少勾选“使用C++的桌面开发”。确保包含了MSVC编译器、Windows SDK和CMake工具。
安装完成后,打开一个新的命令行窗口(以便继承新的PATH环境变量),验证工具是否就绪:
cmake --version cl # 应该能显示MSVC编译器的版本信息3.3 创建项目结构
建立一个清晰的项目目录结构,这是良好工程实践的开始。我建议的结构如下:
MyUnityNativePlugin/ ├── README.md ├── CMakeLists.txt # 主CMake配置文件 ├── vcpkg.json # 项目依赖声明 ├── src/ │ ├── MyNativePlugin.cpp │ └── MyNativePlugin.h ├── unity/ │ └── MyUnityProject/ │ ├── Assets/ │ │ ├── Plugins/ # Unity插件目录 │ │ │ ├── x86_64/ │ │ │ └── Android/ │ │ └── Scripts/ │ │ └── NativeBridge.cs │ └── Packages/ └── build/ # 构建输出目录(建议.gitignore) ├── windows-x64/ └── android-arm64/这个结构将C++原生插件代码(src/)、构建配置(CMakeLists.txt,vcpkg.json)和Unity项目(unity/)分离,但又放在同一个版本库中,便于管理。
4. 定义依赖与清单模式实践
我们将使用vcpkg的清单模式来管理依赖。在项目根目录(MyUnityNativePlugin/)创建vcpkg.json文件。
假设我们的Unity插件需要用到两个著名的C++库:jsoncpp用于处理JSON数据,spdlog用于高性能日志记录(在C++侧调试非常有用)。
{ "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json", "name": "my-unity-native-plugin", "version-string": "1.0.0", "dependencies": [ "jsoncpp", "spdlog" ], "builtin-baseline": "a1c8f1c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c" }name和version-string:是你自己项目的标识。dependencies:列出了项目依赖的所有库。vcpkg会自动处理这些库自身的依赖(递归地)。builtin-baseline:这是一个非常重要的字段!它锁定了vcpkg仓库在某个特定提交时的状态,从而间接锁定了所有依赖库的版本(除非你显式指定覆盖)。这里的哈希值对应vcpkg仓库的一个提交ID。你可以通过git log在vcpkg目录中查看最新提交,或使用一个已知稳定的基线。这确保了构建的可重复性。
现在,在项目根目录打开命令行,使用vcpkg安装依赖。我们指定为64位Windows动态链接库环境(x64-windows):
cd /d D:\Dev\UnityNativeWorkflow\MyUnityNativePlugin ..\vcpkg\vcpkg install --triplet x64-windowsvcpkg会读取vcpkg.json,解析依赖,然后开始下载源码、编译并安装jsoncpp和spdlog到[vcpkg根目录]\installed\x64-windows\目录下。第一次运行会花费一些时间,因为需要编译。后续构建会直接使用已编译的库。
实操心得:
vcpkg在编译某些库时可能会失败,通常是因为缺少某些系统组件或网络问题。常见的错误如“Microsoft Visual C++ 14.0 or greater is required”,这意味着你需要安装对应版本的Visual Studio Build Tools。仔细阅读错误输出,它通常会给出明确的解决方案。另一个技巧是,你可以先尝试安装一个简单的库(如vcpkg install zlib:x64-windows)来测试整个工具链是否畅通。
5. 编写CMakeLists.txt构建原生插件
这是整个流程的核心技术环节。我们需要编写CMakeLists.txt,告诉CMake如何构建我们的插件,并正确链接vcpkg提供的库。
在项目根目录创建CMakeLists.txt:
cmake_minimum_required(VERSION 3.20) # 指定一个较新的CMake版本 project(MyUnityNativePlugin LANGUAGES CXX) # 项目名和语言(C++) # 1. 设置输出目录:将编译产物统一输出到项目根目录下的 `build/{平台}` 目录 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) # 2. 添加源码 add_library(MyNativePlugin SHARED src/MyNativePlugin.cpp src/MyNativePlugin.h ) # 3. 包含头文件目录 target_include_directories(MyNativePlugin PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src ) # 4. 关键步骤:查找通过vcpkg安装的包 # find_package 命令会通过 vcpkg.cmake 工具链文件定位到已安装的库 find_package(jsoncpp CONFIG REQUIRED) find_package(spdlog CONFIG REQUIRED) # 5. 链接库 target_link_libraries(MyNativePlugin PRIVATE jsoncpp_lib # jsoncpp 的导入目标名,可能需要查阅其文档或 .cmake 文件确认 spdlog::spdlog ) # 6. 特定于Unity插件的编译设置 if(WIN32) # 在Windows上,我们通常编译为动态链接库(.dll) # 确保导出的函数使用C语言链接规范,避免C++名称修饰 set_target_properties(MyNativePlugin PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON ) # 添加预处理器定义,用于声明导出/导入符号 target_compile_definitions(MyNativePlugin PRIVATE MY_NATIVE_PLUGIN_EXPORTS ) endif() # 7. 复制构建好的插件到Unity项目的Plugins目录(可选,自动化步骤) # 这部分可以通过CMake的add_custom_command实现,但为了清晰,我们稍后在脚本中处理。关键点解析:
find_package(... CONFIG REQUIRED):CONFIG模式告诉CMake查找库提供的配置文件(通常是<PackageName>Config.cmake)。vcpkg在安装库时会自动生成这些文件。REQUIRED表示如果找不到,则配置失败。target_link_libraries:这里链接的是find_package找到的“导入目标”。这些目标包含了库文件路径、头文件目录以及必要的编译定义。使用目标而非直接写lib文件路径,是现代CMake的最佳实践,它能正确处理依赖传递。- 导出符号:为了让Unity(C#)能够调用C++函数,这些函数必须被“导出”。在Windows上,这通常通过在函数声明前添加
__declspec(dllexport)(编译DLL时)和__declspec(dllimport)(使用DLL时)来实现。我们通过预处理器定义MY_NATIVE_PLUGIN_EXPORTS来条件化这一行为。在头文件中,我们会这样写:
使用// MyNativePlugin.h #ifdef _WIN32 #ifdef MY_NATIVE_PLUGIN_EXPORTS #define MY_API __declspec(dllexport) #else #define MY_API __declspec(dllimport) #endif #else #define MY_API __attribute__((visibility("default"))) #endif extern "C" MY_API int AddTwoIntegers(int a, int b);extern "C"是为了防止C++编译器对函数名进行修饰(Name Mangling),确保C#端能通过确切的函数名找到它。
6. 构建、部署与Unity集成实操
现在,我们将所有部分串联起来,完成从编译到在Unity中调用的完整闭环。
6.1 使用CMake配置与构建项目
我们为Windows平台构建。在项目根目录下,执行以下命令:
# 创建并进入构建目录 mkdir build\windows-x64 cd build\windows-x64 # 配置项目,关键是指定vcpkg的工具链文件 cmake ../.. -DCMAKE_TOOLCHAIN_FILE=../../vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=Release -A x64 # 开始编译 cmake --build . --config Release-DCMAKE_TOOLCHAIN_FILE:这是连接vcpkg和CMake的钥匙。必须指向你本地vcpkg目录下的vcpkg.cmake文件。-DCMAKE_BUILD_TYPE=Release:指定生成Release版本(优化过,体积小,速度快)。调试时可以用Debug。-A x64:指定生成64位目标。
如果一切顺利,你会在build/windows-x64/Release/目录下找到生成的MyNativePlugin.dll(以及可能的.lib文件)。
6.2 编写C++插件源码示例
让我们实现一个简单的MyNativePlugin.cpp:
// MyNativePlugin.cpp #include "MyNativePlugin.h" #include <json/json.h> // jsoncpp 头文件 #include <spdlog/spdlog.h> extern "C" MY_API int AddTwoIntegers(int a, int b) { // 使用 spdlog 记录日志(调试用) spdlog::info("Adding {} and {}", a, b); return a + b; } extern "C" MY_API const char* ParseJsonString(const char* jsonStr) { static std::string result; // 注意:这里使用静态变量有线程安全问题,仅作示例。 Json::Value root; Json::CharReaderBuilder builder; std::string errs; std::istringstream stream(jsonStr); if (Json::parseFromStream(builder, stream, &root, &errs)) { if (root.isMember("name")) { result = "Hello, " + root["name"].asString() + "!"; } else { result = "JSON parsed, but no 'name' field."; } } else { result = "Parse error: " + errs; } spdlog::debug("Parse result: {}", result); // 注意:返回的指针指向的静态字符串在下次调用时会被覆盖。 // 实际项目中应使用更安全的内存管理方式,例如让C#分配缓冲区。 return result.c_str(); }这个示例演示了如何调用jsoncpp和spdlog这两个通过vcpkg管理的库。
6.3 将插件部署到Unity项目
- 组织目录:在Unity项目的
Assets/Plugins目录下,创建对应平台的子文件夹。例如,对于Windows 64位编辑器,将MyNativePlugin.dll复制到Assets/Plugins/x86_64/(注意Unity传统上使用x86_64这个文件夹名)。将MyNativePlugin.lib(如果有)复制到Assets/Plugins/x86_64/,某些情况下链接需要它。 - 编写C#桥接脚本:
// Assets/Scripts/NativeBridge.cs using System; using System.Runtime.InteropServices; using UnityEngine; public class NativeBridge : MonoBehaviour { // 定义与C++ DLL的函数签名匹配 [DllImport("MyNativePlugin")] private static extern int AddTwoIntegers(int a, int b); [DllImport("MyNativePlugin")] private static extern IntPtr ParseJsonString(string jsonStr); void Start() { // 测试整数相加 int sum = AddTwoIntegers(5, 7); Debug.Log($"C++ AddTwoIntegers result: {sum}"); // 测试JSON解析 string json = "{\"name\": \"Unity Developer\"}"; IntPtr ptr = ParseJsonString(json); string message = Marshal.PtrToStringAnsi(ptr); // 转换指针为C#字符串 Debug.Log($"C++ ParseJsonString result: {message}"); } } - 在Unity中测试:将
NativeBridge脚本挂载到一个GameObject上,运行游戏。你应该在Unity编辑器的Console中看到来自C++插件的日志输出和计算结果。
6.4 为Android平台构建
跨平台是vcpkg+CMake组合的强项。为Android构建需要Android NDK和指定正确的三元组。
- 安装Android依赖:首先,确保
vcpkg可以编译Android目标。你需要安装Android NDK,并让vcpkg知道其路径。一种方法是通过环境变量ANDROID_NDK_HOME设置。 - 使用vcpkg安装Android版本库:
这会为Android ARM64架构编译cd /d D:\Dev\UnityNativeWorkflow\MyUnityNativePlugin ..\vcpkg\vcpkg install --triplet arm64-androidjsoncpp和spdlog的静态库(默认)。注意,Android通常使用静态链接以减少包体积和依赖。 - 使用CMake交叉编译:配置CMake时,需要指定Android工具链。
vcpkg提供了辅助工具链。假设你的NDK路径是D:/Android/sdk/ndk/25.2.9519653。
这将生成适用于Android的mkdir build\android-arm64 cd build\android-arm64 cmake ../.. -DCMAKE_TOOLCHAIN_FILE=../../vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=arm64-android -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_NAME=Android -DCMAKE_ANDROID_NDK=D:/Android/sdk/ndk/25.2.9519653 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a cmake --build . --config Release.so共享库文件。 - 部署到Unity:将生成的
libMyNativePlugin.so文件复制到Unity项目的Assets/Plugins/Android/arm64-v8a/目录下。Unity在构建Android APK时会自动将其打包进去。
7. 常见问题、调试技巧与进阶优化
即使流程清晰,在实际操作中你仍会遇到各种问题。以下是我从多次实践中总结的“避坑指南”。
7.1 编译与链接问题排查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
CMake配置失败,提示找不到find_package的包。 | 1.vcpkg未安装该库。2. 未正确指定 CMAKE_TOOLCHAIN_FILE。3. 安装的三元组(如 x64-windows)与CMake尝试寻找的不匹配。 | 1. 运行vcpkg list确认库已安装。2. 检查CMake命令中 -DCMAKE_TOOLCHAIN_FILE路径是否正确。3. 确保 vcpkg install和CMake配置的三元组一致。可以在CMake中强制设置-DVCPKG_TARGET_TRIPLET=x64-windows。 |
链接错误LNK2019: unresolved external symbol。 | 1. C++函数名修饰问题。C#端用extern "C"声明的函数,在C++侧未用extern "C"定义或声明不一致。2. 链接时未包含必要的 .lib文件。3. 依赖库本身链接了其他库,但未传递。 | 1. 检查C++头文件中的函数声明是否被extern "C"包裹,且导出宏MY_API正确定义。2. 确认 target_link_libraries中包含了所有直接依赖的库。对于vcpkg管理的库,使用find_package找到的导入目标。3. 使用 target_link_libraries的PUBLIC或INTERFACE关键字传递依赖,或手动添加缺失的库。 |
| Unity运行时崩溃,错误指向DLL加载。 | 1. DLL依赖项缺失(如MSVCRT版本不匹配)。2. 函数调用约定不一致( __stdcallvs__cdecl)。3. 内存管理错误(如返回局部变量指针)。 | 1. 使用Dependency Walker或Visual Studio的dumpbin /dependents检查DLL的运行时依赖。确保Unity编辑器/播放器使用的VC++运行时版本与编译插件时的一致。最佳实践是使用/MT或/MTd(静态链接运行时库)编译你的插件,这可以通过在CMakeLists.txt中添加set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")实现。2. 在C++函数声明和C#的 [DllImport]中显式指定调用约定,通常使用__cdecl(C#端是CallingConvention.Cdecl)。3. 检查C/C++边界上的内存所有权。避免返回指向栈内存的指针。对于字符串,通常由C#端传入缓冲区,或由C++端分配、C#端负责释放(使用 Marshal.FreeCoTaskMem等)。 |
spdlog等库在Unity中输出日志看不到。 | spdlog默认输出到控制台(stdout/stderr),而Unity不会捕获原生插件的标准输出。 | 1. 将spdlog的sink(输出目标)重定向到文件。2. 使用Unity提供的日志接口,如通过 [DllImport]调用Unity引擎内部的调试输出函数(这需要更深入的引擎交互)。3. 在调试阶段,可以使用 OutputDebugString(Windows)并配合DebugView工具查看。 |
7.2 调试C++插件
调试是原生插件开发中最具挑战性的一环。
- 附加到Unity编辑器进程:在Visual Studio中,打开编译生成的
.sln解决方案文件。选择Debug配置,然后点击调试->附加到进程,在列表中找到Unity.exe(或Unity Editor)进程并附加。在C++源码中设置断点,当Unity调用到该函数时,调试器就会中断。前提是你的插件DLL是用Debug配置编译的,并且PDB符号文件存在。 - 使用日志:正如之前提到的,将日志写入文件是最可靠的调试手段之一。在插件初始化时,打开一个日志文件,将所有关键步骤、变量值写入其中。
- Unity Profiler与Deep Profiling:对于性能问题,Unity Profiler的“Deep Profiling”模式可以捕获到通过
[DllImport]调用的原生函数开销,帮助你定位性能瓶颈是在C#到C++的转换层,还是在C++内部逻辑。
7.3 进阶优化与工程化建议
- 自动化构建脚本:编写一个Python或PowerShell脚本,自动执行
vcpkg install、cmake configure、cmake build以及将产物复制到UnityPlugins目录的全过程。这可以集成到CI/CD流水线中。 - 使用Git Submodule管理vcpkg:将
vcpkg作为你项目仓库的一个子模块,可以锁定vcpkg的版本,确保所有协作者使用完全相同的工具链。git submodule add https://github.com/Microsoft/vcpkg.git - 处理多平台构建矩阵:对于需要发布到Windows、Android、iOS、macOS等多个平台的项目,可以创建一个构建矩阵,在CI服务器上为每个平台的三元组(
x64-windows,arm64-android,arm64-ios)分别执行构建流程。 - 封装更友好的C# API:不要直接在业务代码中到处使用
[DllImport]。应该创建一个专门的、经过良好封装的C#类,处理所有与原生插件的交互,包括错误处理、类型转换和资源管理。考虑使用SafeHandle来包装从C++返回的非托管资源指针。 - 版本控制注意事项:将
vcpkg.json和CMakeLists.txt加入版本控制。将vcpkg的installed目录和项目的build目录加入.gitignore。编译产物和下载的库源码不应该进入版本库。
从手动管理DLL的地狱,到通过vcpkg清单声明依赖、用CMake一键构建、最终在Unity中稳定调用,这套流程虽然前期需要一些学习和配置,但它为项目的长期健康和维护性带来的收益是巨大的。它让你能自信地引入任何复杂的C++生态库,而不用担心会破坏团队其他成员的环境或未来的构建。
