ubuntu安装protobuf过程和问题

我使用的 protobuf 版本是 22.5。protobuf 从版本 22 以后依赖 abseil 等第三方库,需要递归 clone。如果手动下载的话也要注意下载对应版本的第三方库,否则链接时会错误。

1
git clone -b v22.5 https://github.com/protocolbuffers/protobuf.git --recursive

然后按照 protobuf github 上的说明编译安装。编译这一步需要好久,在虚拟机里还有可能出现内存不足的情况,扩展一下虚拟机内存就好了。cmake install 安装前缀是 /usr/local

1
2
3
4
cmake .
cmake --build . --parallel 10
ctest --verbose
sudo cmake --install .

执行 protoc –version 确认安装成功了

写个简单的测试 demo。一开始我尝试用官方和网上大多数方法在自己的 CMakeLists.txt 里引入 protobuf 库,即直接find_package(Protobuf REQUIRED),这会使用 cmake 官方的 FindProtobuf.cmake 模块来搜索 protobuf。

1
2
3
4
5
6
find_package(Protobuf REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})

add_executable(protobuf_learn main.cpp test.pb.cc)
target_link_libraries(protobuf_learn ${Protobuf_LIBRARIES})

编译没有问题,但是链接出现大量类似下面的报错,看起来是没有链接到 abseil 的静态库:

1
/usr/bin/ld: any_lite.cc:(.text+0x165): undefined reference to `absl::lts_20230125::StrCat[abi:cxx11](absl::lts_20230125::AlphaNum const&, absl::lts_20230125::AlphaNum const&, absl::lts_20230125::AlphaNum const&)'

然后 在cmake 里输出一下 Protobuf_LIBRARIES:

1
2
3
4
5
6
7
8
9
find_package(Protobuf REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})

MESSAGE(STATUS "Protobuf dirs:" ${Protobuf_INCLUDE_DIRS})
MESSAGE(STATUS "Protobuf lib:" ${Protobuf_LIBRARIES})

add_executable(protobuf_learn main.cpp test.pb.cc)
target_link_libraries(protobuf_learn ${Protobuf_LIBRARIES})

输出如下:确实没有链接 abseil,只是链接了 libprotobuf。查了好久也没找到类似的问题解决方案。

1
2
-- Protobuf dirs:/usr/local/include
-- Protobuf lib:/usr/local/lib/libprotobuf.a-lpthread

后来尝试不直接 find_package(Protobuf REQUIRED),使用 pkg-config 来搜索 protobuf 的依赖:

1
2
3
4
5
6
7
8
9
10
11
find_package(PkgConfig)
pkg_search_module(Protobuf REQUIRED protobuf)
MESSAGE(STATUS "Protobuf dirs:" ${Protobuf_INCLUDE_DIRS})
MESSAGE(STATUS "Protobuf lib:" ${Protobuf_LIBRARIES})
include_directories(${Protobuf_INCLUDE_DIRS})
link_directories(${Protobuf_LIBRARY_DIRS})

add_executable(protobuf_learn main.cpp test.pb.cc)
target_link_libraries(protobuf_learn
${Protobuf_LIBRARIES}
)

这种方式可以链接成功,而且 Protobuf_LIBRARY_DIRS 变量里也包含了一大堆 abseil 的库:

1
2
-- Protobuf lib:protobufpthreadabsl_log_internal_check_opabsl_leak_checkabsl_die_if_nullabsl_log_internal_conditionsabsl_log_internal_messageabsl_examine_stackabsl_log_internal_formatabsl_log_internal_protoabsl_log_internal_nullguardabsl_log_internal_log_sink_setabsl_log_sinkabsl_log_entryabsl_flagsabsl_flags_internalabsl_flags_marshallingabsl_flags_reflectionabsl_flags_private_handle_accessorabsl_flags_commandlineflagabsl_flags_commandlineflag_internalabsl_flags_configabsl_flags_program_nameabsl_log_initializeabsl_log_globalsabsl_log_internal_globalsabsl_hashabsl_cityabsl_low_level_hashabsl_raw_hash_setabsl_hashtablez_samplerabsl_statusorabsl_statusabsl_cordabsl_cordz_infoabsl_cord_internalabsl_cordz_functionsabsl_exponential_biasedabsl_cordz_handleabsl_crc_cord_stateabsl_crc32cabsl_crc_internalabsl_crc_cpu_detectabsl_bad_optional_accessabsl_str_format_internalabsl_strerrorabsl_synchronizationabsl_graphcycles_internalabsl_stacktraceabsl_symbolizeabsl_debugging_internalabsl_demangle_internalabsl_malloc_internalabsl_timeabsl_civil_timeabsl_time_zoneabsl_bad_variant_accessutf8_validityutf8_rangepthreadabsl_stringsabsl_strings_internalrtabsl_baseabsl_spinlock_waitabsl_int128absl_throw_delegateabsl_raw_logging_internalabsl_log_severity

暂时还不知道为什么第一种方法不行。