如何编译4.22.0+版本C++ Protobuf,使指定g++命令正常运行?
需求背景
编译4.22.0及以上版本的C++ Protobuf,确保命令g++ pb.cpp pb.pb.cc $(pkg-config --cflags --libs protobuf)可正常执行,禁止使用apt提供的3.12低版本包,必须从源码构建。
一、CMake构建的链接错误问题
问题现象
按官方cmake/README.md步骤构建安装后,执行目标g++命令时出现链接错误,提示缺失absl_log_internal_check_op相关符号,需额外添加pkg-config --cflags --libs absl_log_internal_check_op才能编译,而apt安装版本无需此操作。
解决办法
构建时通过CMake参数让Protobuf静态链接Abseil依赖,将Abseil的符号打包进libprotobuf.so,避免用户编译时额外指定依赖:
# 克隆Protobuf源码(替换为目标版本) git clone --depth 1 --branch v4.22.0 https://github.com/protocolbuffers/protobuf.git cd protobuf git submodule update --init --recursive # 配置CMake参数 cmake -S . -B build \ -DCMAKE_INSTALL_PREFIX=/usr/local \ -Dprotobuf_BUILD_SHARED_LIBS=ON \ -Dprotobuf_ABSL_PROVIDER=builtin \ -Dprotobuf_STATIC_LINK_ABSL=ON \ -Dprotobuf_BUILD_TESTS=OFF # 编译并安装 cmake --build build --parallel $(nproc) cmake --install build
验证:执行ldd /usr/local/lib/libprotobuf.so,输出中不会包含Abseil的动态库;运行pkg-config --libs protobuf仅返回-lprotobuf相关参数,原g++命令可正常执行。
二、Bazel构建的两个问题
问题1:缺失well-known类型的.proto文件
问题现象
构建后系统include目录缺少timestamp.proto等well-known类型的proto文件,源码目录虽有这些文件但包含大量unittest_*冗余文件,不想直接复制全部。
解决办法
通过Bazel目标提取纯净的well-known proto文件,复制到系统include目录:
# 构建well-known protos目标 bazel build //src/google/protobuf:well_known_protos # 创建目标目录并复制文件 mkdir -p /usr/local/include/google/protobuf cp bazel-bin/src/google/protobuf/*.proto /usr/local/include/google/protobuf/
问题2:缺少.pc文件导致无法使用pkg-config
问题现象
构建产物中无protobuf.pc文件,无法通过pkg-config --cflags --libs protobuf获取编译参数。
解决办法
手动生成protobuf.pc文件并放置到pkgconfig目录:
mkdir -p /usr/local/lib/pkgconfig cat > /usr/local/lib/pkgconfig/protobuf.pc << EOF prefix=/usr/local exec_prefix=\${prefix} libdir=\${exec_prefix}/lib includedir=\${prefix}/include Name: Protocol Buffers Description: Google's Data Interchange Format Version: 4.22.0 Libs: -L\${libdir} -lprotobuf Cflags: -I\${includedir} EOF chmod 644 /usr/local/lib/pkgconfig/protobuf.pc
替换Version字段为实际构建的Protobuf版本,执行pkg-config --cflags --libs protobuf即可正常输出参数,原g++命令可正常执行。
内容的提问来源于stack exchange,提问作者jmpsabisb

