☰
CMake 集成 Protobuf 实战:FindProtobuf 模块与 protobuf_generate 完整指南
2026/10/9 1:17:49 网站建设 项目流程
  • 构建工具
  • 开发工具
  • CLI

【免费下载链接】CMake

Mirror of CMake upstream repository

项目地址:https://gitcode.com/gh_mirrors/cm/CMake
点击查看免费下载

本文围绕 CMake 官方仓库中 FindProtobuf 模块 的完整文档展开,系统讲解如何在 CMake 工程中查找并链接 Protocol Buffers(Protobuf)库、利用protobuf_generate系列命令在构建期自动从.proto文件生成 C++/Python 源码,并结合模块源码实现与仓库自带测试用例,帮助读者掌握从find_package到代码生成、链接、gRPC 扩展的全链路集成方案。

一、模块定位:module mode 与 config mode 的区别

Protocol Buffers 是 Google 开发的开源、语言中立、平台无关的结构化数据序列化机制,常用于程序间或网络间的数据交换。CMake 官方提供的FindProtobuf模块位于 Modules/FindProtobuf.cmake,其用途是在module mode下查找已安装的 Protobuf 库:

find_package(Protobuf [<version>] [...])

需要特别注意的是(模块文档开篇即强调):

  • 如果 Protobuf 库是使用其CMake 构建系统构建并安装的,它会提供一份package configuration file(配置模式包),此时应优先使用config mode:

    find_package(Protobuf CONFIG)

    在 config mode 下,导入目标和protobuf_generate等命令由上游 Protobuf 包自身提供,本模块文档中记录的部分变量在 config mode 下不可用(因为官方推荐直接使用导入目标),具体用法以 Protobuf 上游文档为准。官方明确表示:当 Protobuf 使用 CMake 构建时,config mode 是推荐用法。

  • 本模块仅在 module mode 下工作,即执行find_package(Protobuf)且未命中 config 包、或设置CMAKE_FIND_PACKAGE_PREFER_CONFIG FALSE时,由 CMake 加载本模块完成查找。

从版本演进看,模块支持两个关键里程碑:

  • 3.6:find_package(Protobuf <version>)支持版本号参数;所有输入/输出变量统一改用Protobuf_前缀(PROTOBUF_前缀仅保留向后兼容)。
  • 3.9 起:陆续引入protobuf::libprotobuf、protobuf::libprotobuf-lite、protobuf::libprotoc导入库目标与protobuf::protoc导入可执行目标。

二、导入目标(Imported Targets)

当模块成功找到 Protobuf 后,会提供以下导入目标(均为::命名空间目标,可直接用于target_link_libraries):

目标名引入版本说明
protobuf::libprotobuf3.9封装完整 Protobuf 库的使用要求,库存在即可用
protobuf::libprotobuf-lite3.9封装精简版protobuf-lite库(体积更小,适用于嵌入式等受限场景)
protobuf::libprotoc3.9封装protoc库(编译器库,写编译器插件时使用)
protobuf::protoc3.10导入的protoc编译器可执行目标

从源码实现看,这些目标在 Modules/FindProtobuf.cmake 中以UNKNOWN IMPORTED/IMPORTED类型创建,并附带精确的使用要求:

  • INTERFACE_INCLUDE_DIRECTORIES指向Protobuf_INCLUDE_DIR;
  • 同时记录IMPORTED_LOCATION以及按配置区分的IMPORTED_LOCATION_RELEASE/IMPORTED_LOCATION_DEBUG(由Protobuf_LIBRARY_RELEASE/Protobuf_LIBRARY_DEBUG驱动);
  • 若Protobuf_VERSION不低于 3.6,目标会附加INTERFACE_COMPILE_FEATURES cxx_std_11,自动为下游目标启用 C++11 编译特性(见 Modules/FindProtobuf.cmake);
  • 在 Windows 且未使用静态库时,会自动附加PROTOBUF_USE_DLLS编译定义以匹配 DLL 导出约定;
  • 在 UNIX 平台,若找到Threads::Threads则自动追加链接Threads::Threads(Protobuf 头文件可能依赖线程)。

三、结果变量与缓存变量

3.1 结果变量(Result Variables)

查找结束后,模块会定义以下变量:

变量引入版本含义
Protobuf_FOUND3.3是否找到(指定版本)Protobuf 库的布尔值
Protobuf_VERSION3.6找到的 Protobuf 版本号
Protobuf_INCLUDE_DIRS—使用 Protobuf 所需的头文件目录
Protobuf_LIBRARIES—使用 Protobuf 需要链接的库列表
Protobuf_PROTOC_LIBRARIES—使用protoc库需要链接的库列表
Protobuf_LITE_LIBRARIES—使用protobuf-lite库需要链接的库列表

3.2 缓存变量(Cache Variables)

以下缓存变量也可供用户设置或查询:

缓存变量含义
Protobuf_INCLUDE_DIR包含 Protobuf 头文件的目录
Protobuf_LIBRARYprotobuf库的路径
Protobuf_PROTOC_LIBRARYprotoc库的路径
Protobuf_PROTOC_EXECUTABLEprotoc编译器的路径
Protobuf_LIBRARY_DEBUGprotobuf调试库的路径
Protobuf_PROTOC_LIBRARY_DEBUGprotoc调试库的路径
Protobuf_LITE_LIBRARYprotobuf-lite库的路径
Protobuf_LITE_LIBRARY_DEBUGprotobuf-lite调试库的路径
Protobuf_SRC_ROOT_FOLDERMSVC 下使用的 Protobuf 源码根目录(见下文)

Protobuf_SRC_ROOT_FOLDER专用于 Windows/MSVC 场景:当使用 Protobuf 自带的 Visual Studio 工程构建产物时,设置该变量后,模块会去以下位置查找库和可执行文件:

  • <Protobuf_SRC_ROOT_FOLDER>/vsprojects/{Debug,Release}
  • <Protobuf_SRC_ROOT_FOLDER>/vsprojects/x64/{Debug,Release}

3.3 向后兼容:双写大小写前缀

模块保留了大量向后兼容逻辑:查找前,会把已定义的PROTOBUF_*大写输入变量(如PROTOBUF_SRC_ROOT_FOLDER、PROTOBUF_IMPORT_DIRS、PROTOBUF_DEBUG等)映射为Protobuf_*形式;查找结束后,又会把全部Protobuf_*输出变量以string(TOUPPER)形式回写到PROTOBUF_*大写变量(见 Modules/FindProtobuf.cmake)。因此旧工程中依赖PROTOBUF_LIBRARIES等大写变量的代码仍然可用,但新代码应统一使用Protobuf_前缀。

四、查找前的 Hint 变量

在调用find_package(Protobuf)之前,可以设置以下可选变量影响查找行为:

  • Protobuf_DEBUG(3.6 引入):布尔值,置 ON 后模块会打印内部调试信息,便于排查查找路径、版本解析等问题。源码中大量使用if(Protobuf_DEBUG)输出message(STATUS ...),例如输出Protobuf_USE_STATIC_LIBS当前值、common.h位置、从common.h解析出的版本号、protoc --version结果等。
  • Protobuf_USE_STATIC_LIBS(3.9 引入):置 ON 强制使用静态库,默认 OFF。实现上,置 ON 时模块会临时修改CMAKE_FIND_LIBRARY_SUFFIXES:Windows 下优先.lib/.a,其他平台直接置为.a,查找结束后恢复原值(见 Modules/FindProtobuf.cmake)。

五、核心命令:protobuf_generate

protobuf_generate命令(3.13 引入)用于在构建期从.proto模式文件自动生成源码,是现代用法的主力命令,其完整签名如下:

protobuf_generate( [TARGET <target>] [LANGUAGE <lang>] [OUT_VAR <variable>] [EXPORT_MACRO <macro>] [PROTOC_OUT_DIR <out-dir>] [PLUGIN <plugin>] [PLUGIN_OPTIONS <plugin-options>] [DEPENDENCIES <dependencies>...] [PROTOS <proto-files>...] [IMPORT_DIRS <dirs>...] [APPEND_PATH] [GENERATE_EXTENSIONS <extensions>...] [PROTOC_OPTIONS <options>...] [PROTOC_EXE <executable>] [DESCRIPTORS] )

5.1 各选项详解

选项说明
TARGET <target>生成的源码文件作为源文件加入该 CMake 目标;当不使用OUT_VAR时必须指定
LANGUAGE <lang>取cpp或python,决定生成哪种源码;默认cpp。其他语言请配合GENERATE_EXTENSIONS使用
OUT_VAR <variable>将生成的源文件路径列表写入该 CMake 变量
EXPORT_MACRO <macro>应用于所有生成的 Protobuf 消息类与 extern 变量的预处理宏名,常用于 DLL 导出声明(展开为__declspec(dllexport)或__declspec(dllimport));仅当LANGUAGE为cpp时生效
PROTOC_OUT_DIR <out-dir>生成文件的输出目录,默认为CMAKE_CURRENT_BINARY_DIR
PLUGIN <plugin>(3.21 引入)可选的插件可执行程序,例如grpc_cpp_plugin的路径
PLUGIN_OPTIONS <plugin-options>(3.28 引入)传给插件的额外选项,如 gRPC C++ 插件的generate_mock_code=true
DEPENDENCIES <dependencies>...(3.28 引入)生成所依赖的项,转发给底层的add_custom_command(DEPENDS)。4.1 起该参数支持多个值(DEPENDENCIES a b c...),此前只接受单值(DEPENDENCIES "a;b;c;...")
PROTOS <proto-files>...要处理的.proto文件列表;若同时指定了<target>,则与目标上的所有.proto源文件合并
IMPORT_DIRS <dirs>...模式文件的一个或多个公共父目录。例如模式文件是proto/helloworld/helloworld.proto、导入目录是proto/,则生成文件为<out-dir>/helloworld/helloworld.pb.h和<out-dir>/helloworld/helloworld.pb.cc
APPEND_PATH指定后,把所有.proto文件的基路径追加到IMPORT_DIRS(即让protoc对每个包含.proto文件的目录都加上-I参数)
GENERATE_EXTENSIONS <extensions>...省略LANGUAGE时必须设置,用于指定protoc生成文件的扩展名
PROTOC_OPTIONS <options>...(3.28 引入)直接传给protoc编译器的额外命令行选项
PROTOC_EXE <executable>(4.0 引入)用于生成绑定的命令行程序、路径或 CMake 可执行目标;省略时默认使用protobuf::protoc导入目标
DESCRIPTORS指定后,为每个.proto源文件附加--descriptor_set_out=<proto-file>选项,生成自描述消息描述文件;仅当<lang>为cpp且处于 module mode 时可用,config mode 下不可用

5.2 源码级执行机制

从 Modules/FindProtobuf.cmake 的实现可以看清该命令的完整工作流:

  1. 参数校验:PROTOS与TARGET均未提供,或OUT_VAR与TARGET均未提供时,message(SEND_ERROR)报错并return();LANGUAGE缺省为cpp(统一转为小写);PROTOC_OUT_DIR缺省为${CMAKE_CURRENT_BINARY_DIR}。

  2. 默认扩展名映射:cpp→.pb.h .pb.cc;python→_pb2.py;其他语言若无GENERATE_EXTENSIONS会直接报错。

  3. 收集.proto文件:指定TARGET时,通过get_target_property(... SOURCES)取出目标源文件,筛选出以proto结尾的文件并入PROTOS。

  4. 确定protoc可执行文件:未显式传PROTOC_EXE时,要求存在protobuf::protoc目标,否则报错并提示三种补救方式:设置Protobuf_PROTOC_EXECUTABLE变量、给protobuf_generate传PROTOC_EXE、或确保protoc在 CMake 搜索路径中。

  5. 构建-I导入路径:APPEND_PATH为真时为每个.proto文件所在目录追加-I;随后追加IMPORT_DIRS(均取绝对路径并去重);若未启用APPEND_PATH,还会默认追加-I ${CMAKE_CURRENT_SOURCE_DIR}。

  6. 计算生成文件路径:对每个.proto文件计算相对目录(默认相对CMAKE_CURRENT_SOURCE_DIR),拼出<PROTOC_OUT_DIR>/<相对路径>/<基名><扩展名>;若启用DESCRIPTORS且语言为cpp,额外生成${CMAKE_CURRENT_BINARY_DIR}/<基名>.desc。

  7. 生成自定义命令:最终通过add_custom_command执行protoc,命令行形如:

    protoc [PROTOC_OPTIONS...] --<lang>_out [plugin-options]:<PROTOC_OUT_DIR> [--plugin=...] [--descriptor_set_out=...] [-I dir...] <abs.proto>

    依赖项包含.proto文件本身、protobuf::protoc以及用户传入的DEPENDENCIES,并注明VERBATIM保证参数原样传递。

  8. 产出与注入:所有生成文件被标记为GENERATED TRUE;OUT_VAR结果写回父作用域(PARENT_SCOPE);指定TARGET时通过target_sources(... PRIVATE ...)注入目标。

仓库自带测试 Tests/FindProtobuf/Test/CMakeLists.txt 展示了多个典型用法,例如:

add_library(msgs_protoc_options msgs/example.proto) protobuf_generate(TARGET msgs_protoc_options DESCRIPTORS EXPORT_MACRO PROTO_EXPORT PLUGIN_OPTIONS speed PROTOC_OPTIONS --include_imports --include_source_info)

并注释说明"多个 protoc/plugin 选项必须仍然汇成单一的 COMMENT 字符串"——这正是实现中对PLUGIN_OPTIONS用逗号拼接、对PROTOC_OPTIONS以空格替换分号的细节体现。

六、Deprecated 命令:protobuf_generate_cpp / protobuf_generate_python

为向后兼容,模块保留了旧版命令,4.1 起标记为 deprecated,应迁移到protobuf_generate。

6.1 protobuf_generate_cpp

在构建期从.proto文件生成 C++ 源码:

protobuf_generate_cpp( <sources-variable> <headers-variable> [DESCRIPTORS <variable>] [EXPORT_MACRO <macro>] <proto-files>... )
  • <sources-variable>:保存生成的 C++ 源文件列表的变量名;
  • <headers-variable>:保存生成的头文件列表的变量名;
  • DESCRIPTORS <variable>(3.10 引入):保存生成的描述文件列表;config mode 下不可用;
  • EXPORT_MACRO <macro>:展开为__declspec(dllexport)/__declspec(dllimport)的宏名;
  • <proto-files>...:一个或多个待处理的.proto文件。

6.2 protobuf_generate_python

(3.4 引入,4.1 起 deprecated)在构建期生成 Python 源码:

protobuf_generate_python(<python-sources-variable> <proto-files>...)

6.3 两个旧命令共用的前置变量

调用旧命令前还可设置以下变量:

  • Protobuf_IMPORT_DIRS(4.1 deprecated):附加的.proto导入搜索目录列表;
  • PROTOBUF_GENERATE_CPP_APPEND_PATH(4.1 deprecated,请改用protobuf_generate(APPEND_PATH)):布尔值,为真时让protoc对每个包含.proto文件的目录都传-I;默认值为真(见源码if(NOT DEFINED PROTOBUF_GENERATE_CPP_APPEND_PATH) set(PROTOBUF_GENERATE_CPP_APPEND_PATH TRUE))。

6.4 旧命令的作用域与 config mode 限制(重要)

  • 两个旧命令只在与find_package(Protobuf ...)相同的目录作用域内正确工作;
  • 若 Protobuf 以config mode找到,则自 Protobuf 3.0.0 起protobuf_generate_cpp()与protobuf_generate_python()不可用,除非在调用find_package(Protobuf ...)之前将上游包配置提示变量protobuf_MODULE_COMPATIBLE设为布尔真。

实现上,两个旧函数本质是protobuf_generate的薄包装:PROTOBUF_GENERATE_CPP解析参数后转调protobuf_generate(... LANGUAGE cpp ...),再把输出的文件按扩展名.cc(源)、.desc(描述文件)、其余(头文件)分类回写;PROTOBUF_GENERATE_PYTHON则转调protobuf_generate(... LANGUAGE python ...)(见 Modules/FindProtobuf.cmake)。

七、完整实战示例

7.1 查找 Protobuf 的三种基本写法

# 只查找,未找到不报错 find_package(Protobuf) # 指定最低版本 find_package(Protobuf 30) # 必需,找不到则停止并报错 find_package(Protobuf REQUIRED)

7.2 config mode 优先、module mode 兜底

某些 Protobuf 安装可能不提供 package configuration file。官方推荐的兜底写法是利用CMAKE_FIND_PACKAGE_PREFER_CONFIG:

set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE) find_package(Protobuf) unset(CMAKE_FIND_PACKAGE_PREFER_CONFIG)

这样优先尝试 config mode,找不到配置文件时自动回退到 module mode。

7.3 链接导入目标

find_package(Protobuf) target_link_libraries(example PRIVATE protobuf::libprotobuf)

7.4 完整工程:生成并编译 C++ 代码

CMakeLists.txt:

cmake_minimum_required(VERSION 3.24) project(ProtobufExample) add_executable(example main.cxx person.proto) find_package(Protobuf) if(Protobuf_FOUND) protobuf_generate(TARGET example) endif() target_link_libraries(example PRIVATE protobuf::libprotobuf) target_include_directories(example PRIVATE ${CMAKE_CURRENT_BINARY_DIR})

person.proto:

syntax = "proto3"; message Person { string name = 1; int32 id = 2; }

main.cxx:

#include <iostream> #include "person.pb.h" int main() { Person person; person.set_name("Alice"); person.set_id(123); std::cout << "Name: " << person.name() << "\n"; std::cout << "ID: " << person.id() << "\n"; return 0; }

注意:example目标把person.proto直接作为源文件加入,protobuf_generate(TARGET example)自动收集其中的.proto文件并生成person.pb.h/person.pb.cc注入目标;头文件生成在${CMAKE_CURRENT_BINARY_DIR},故需将该目录加入包含路径。

7.5 Protobuf + gRPC

gRPC 场景使用PLUGIN、PLUGIN_OPTIONS与GENERATE_EXTENSIONS组合生成服务桩代码:

find_package(Protobuf REQUIRED) find_package(gRPC CONFIG REQUIRED) add_library(ProtoExample Example.proto) target_link_libraries(ProtoExample PUBLIC gRPC::grpc++) protobuf_generate(TARGET ProtoExample) protobuf_generate( TARGET ProtoExample LANGUAGE grpc PLUGIN protoc-gen-grpc=$<TARGET_FILE:gRPC::grpc_cpp_plugin> PLUGIN_OPTIONS generate_mock_code=true GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc )

这里LANGUAGE grpc并非内置语言,必须配合GENERATE_EXTENSIONS指明插件输出扩展名;$<TARGET_FILE:...>生成器表达式在构建期解析为插件绝对路径。

仓库测试中对应的 gRPC 用例(受CMake_TEST_FindProtobuf_gRPC开关控制)还演示了IMPORT_DIRS与APPEND_PATH对输出目录布局的影响(见 Tests/FindProtobuf/Test/CMakeLists.txt):

  • 默认(无 IMPORT_DIRS/APPEND_PATH):生成文件落在${CMAKE_CURRENT_BINARY_DIR}/msgs/grpc/;
  • 带IMPORT_DIRS msgs/:落在${CMAKE_CURRENT_BINARY_DIR}/grpc/;
  • 带APPEND_PATH:直接落在${CMAKE_CURRENT_BINARY_DIR}/。

7.6 从旧命令升级到 protobuf_generate

旧式 C++ 生成:

find_package(Protobuf) if(Protobuf_FOUND) protobuf_generate_cpp( proto_sources proto_headers EXPORT_MACRO DLL_EXPORT DESCRIPTORS proto_descriptors src/protocol/Proto1.proto src/protocol/Proto2.proto ) endif() target_sources( example PRIVATE ${proto_sources} ${proto_headers} ${proto_descriptors} ) target_link_libraries(example PRIVATE protobuf::libprotobuf)

升级后的等价写法:

find_package(Protobuf) if(Protobuf_FOUND) protobuf_generate( TARGET example EXPORT_MACRO DLL_EXPORT IMPORT_DIRS src/protocol DESCRIPTORS PROTOS src/protocol/Proto1.proto src/protocol/Proto2.proto ) endif() target_link_libraries(example PRIVATE protobuf::libprotobuf)

旧式 Python 生成:

find_package(Protobuf) if(Protobuf_FOUND) protobuf_generate_python(python_sources foo.proto) endif() add_custom_target(proto_files DEPENDS ${python_sources})

升级后:

find_package(Protobuf) if(Protobuf_FOUND) protobuf_generate( LANGUAGE python PROTOS foo.proto OUT_VAR python_sources ) endif() add_custom_target(proto_files DEPENDS ${python_sources})

八、模块内部查找流程与版本校验

理解模块的查找顺序有助于排查“找不到库”或“版本不匹配”的问题。从 Modules/FindProtobuf.cmake 源码看,主要流程如下:

  1. 库查找:通过内部函数_protobuf_find_libraries依次查找Protobuf(protobuf)、Protobuf_LITE(protobuf-lite)、Protobuf_PROTOC(protoc),每个库同时查找 release 与 debug 变体(debug 名自动加d后缀),再借助SelectLibraryConfigurations.cmake的select_library_configurations合成*_LIBRARIES;UNIX 下若启用了线程还会追加${CMAKE_THREAD_LIBS_INIT}。
  2. 头文件查找:find_path(Protobuf_INCLUDE_DIR google/protobuf/service.h ...)。
  3. 编译器查找:find_program(Protobuf_PROTOC_EXECUTABLE NAMES protoc ...),MSVC 下额外搜索vsprojects/{x64/}{Debug,Release}目录。
  4. 版本解析:读取${Protobuf_INCLUDE_DIR}/google/protobuf/stubs/common.h中的GOOGLE_PROTOBUF_VERSION宏(形如3023002的整数),通过math(EXPR ...)拆出主/次/修订号组成Protobuf_VERSION。
  5. 版本一致性校验:执行protoc --version解析libprotoc <version>,与库版本比对,不一致时输出WARNING;实现中还特别注释:protoc 22 及以后版本不再打印主版本号,因此比对逻辑额外兼容minor.subminor形式(见 Modules/FindProtobuf.cmake)。
  6. 最终判定:调用find_package_handle_standard_args(Protobuf REQUIRED_VARS Protobuf_LIBRARIES Protobuf_INCLUDE_DIR VERSION_VAR Protobuf_VERSION)生成标准的Protobuf_FOUND结果与错误提示。

模块还针对 MSVC 做了特殊兼容:由于 Google 提供的 vcproj 工程在 Windows 上生成的库带lib前缀,模块会临时把CMAKE_FIND_LIBRARY_PREFIXES改为"lib" ""再恢复,确保libprotobuf这类命名也能被正确匹配。

九、官方回归测试:验证模块与生成命令

仓库为 FindProtobuf 提供了完整回归测试(位于 Tests/FindProtobuf/CMakeLists.txt 与 Tests/FindProtobuf/Test/CMakeLists.txt),通过ctest --build-and-test在临时目录独立构建TestFindProtobuf工程,覆盖:

  • 分别用导入目标(protobuf::libprotobuf、protobuf::libprotobuf-lite、protobuf::libprotoc)和传统变量(${Protobuf_INCLUDE_DIRS}、${Protobuf_LIBRARIES}、${Protobuf_LITE_LIBRARIES}、${Protobuf_PROTOC_LIBRARIES})两种风格链接并运行测试程序;
  • 通过protobuf::protoc --version验证导入的可执行目标可用;
  • 调用protobuf_generate_cpp生成msgs/example.proto与msgs/example_desc.proto的源码与描述文件,编译后运行test_generate、test_desc验证生成代码可编译、可运行;
  • 在 gRPC 开关开启时,验证PLUGIN、IMPORT_DIRS、APPEND_PATH三种模式下生成的 gRPC 桩代码均可构建运行。

测试目标属性中设置的FAIL_REGULAR_EXPRESSION PROTOC_EXE还用于捕获PROTOC_EXE相关错误输出。这些用例可直接作为读者本地集成 Protobuf 的参考模板。

十、快速决策清单

  • 用 config mode 还是 module mode?Protobuf 由 CMake 构建安装 → 优先find_package(Protobuf CONFIG);否则用本模块(module mode),并可用CMAKE_FIND_PACKAGE_PREFER_CONFIG实现“config 优先、module 兜底”。
  • 链接用目标还是变量?优先protobuf::libprotobuf等命名空间目标(自动携带包含目录、C++11 特性、Windows DLL 定义、线程依赖);老代码可继续用Protobuf_LIBRARIES系列变量。
  • 生成代码用什么命令?新工程一律用protobuf_generate;旧命令仅在维护遗留代码时使用,并注意其目录作用域与 config mode 限制。
  • 多语言/插件怎么办?非 cpp/python 语言必须提供GENERATE_EXTENSIONS;gRPC 等插件用PLUGIN+PLUGIN_OPTIONS。
  • 排查问题开什么开关?设置Protobuf_DEBUG=ON可观察模块完整查找过程;Protobuf_USE_STATIC_LIBS=ON强制静态链接。
  • 构建工具
  • 开发工具
  • CLI

【免费下载链接】CMake

Mirror of CMake upstream repository

项目地址:https://gitcode.com/gh_mirrors/cm/CMake
点击查看免费下载

相关推荐

上一篇:探索未来的数据存储:Dragonfly 开源数据库
下一篇:Kubernetes DRA 动态资源分配升级/降级端到端测试套件(test/e2e_dra)运行指南与源码解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询