CMake链接依赖GRPC的库时出现链接错误,求正确处理方式
我有一个依赖GRPC第三方库的应用,用Make构建时,通过pkg-config --libs protobuf grpc++ grpc能正常完成链接。但切换到CMake+Vcpkg构建后,链接第三方库时出现大量未定义引用错误,示例错误如下:
In function `absl::lts_20220623::MutexLock::MutexLock(absl::lts_20220623::Mutex*)': [build] (.text._ZN4absl12lts_202206239MutexLockC2EPNS0_5MutexE[_ZN4absl12lts_202206239MutexLockC5EPNS0_5MutexE]+0x26): undefined reference to `absl::lts_20220623::Mutex::Lock()'
目前我通过在target_link_libraries中直接添加pkg-config --libs protobuf grpc++ grpc的输出解决了问题,相关CMake配置如下:
target_include_directories( .... /workspace/third_party/centos/grpc_1480/lib .... ) target_link_libraries(kv-validation_lib PRIVATE fmt::fmt libkv.a libkvproto.a yaml-cpp -lpthread ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF} stdc++fs <pkg-config --libs protobuf grpc++ grpc GOES HERE AND FIXES IT> )
但这只是临时的hack方案。作为CMake新手,我想咨询:
- 如何正确告知CMake链接指定位置的库?
- 是否存在
${_ABSL}这类可用的标志? - 应该如何使用CMake的函数调用pkg-config文件?
我曾尝试使用${ABSL}标志但无效,已参考过Stack Overflow上的相关问题。
1. 正确链接指定位置的库
不要直接在target_include_directories中填写库路径,推荐用find_library精准定位自定义路径下的库文件,再通过变量链接,这样更清晰且能处理库不存在的错误:
# 定位grpc相关库 find_library(GRPC_LIB grpc PATHS /workspace/third_party/centos/grpc_1480/lib NO_DEFAULT_PATH) find_library(GRPCPP_LIB grpc++ PATHS /workspace/third_party/centos/grpc_1480/lib NO_DEFAULT_PATH) find_library(PROTOBUF_LIB protobuf PATHS /workspace/third_party/centos/grpc_1480/lib NO_DEFAULT_PATH) # 定位报错涉及的absl库 find_library(ABSL_MUTEX_LIB absl_mutex PATHS /workspace/third_party/centos/grpc_1480/lib NO_DEFAULT_PATH) find_library(ABSL_BASE_LIB absl_base PATHS /workspace/third_party/centos/grpc_1480/lib NO_DEFAULT_PATH) # 链接时使用找到的库变量 target_link_libraries(kv-validation_lib PRIVATE fmt::fmt libkv.a libkvproto.a yaml-cpp -lpthread ${_REFLECTION} ${GRPCPP_LIB} ${GRPC_LIB} ${PROTOBUF_LIB} ${ABSL_MUTEX_LIB} ${ABSL_BASE_LIB} stdc++fs )
如果不想逐个定位,也可以用link_directories指定库搜索路径,但优先级低于find_library的定位结果:
link_directories(/workspace/third_party/centos/grpc_1480/lib)
2. 关于ABSL相关标志
CMake没有默认的${_ABSL}或${ABSL}变量,除非你自己定义,或者通过find模块、pkg-config导入。
- 如果是Vcpkg安装的absl,它会提供CMake目标(比如
absl::base、absl::mutex),可以直接链接:
但必须保证Vcpkg的absl版本和第三方库依赖的版本完全匹配,否则仍会出现链接错误。find_package(absl REQUIRED) target_link_libraries(kv-validation_lib PRIVATE absl::mutex absl::base) - 如果第三方库用的是自定义编译的absl(比如报错中的lts_20220623版本),就需要像上面那样用
find_library手动定位对应的absl库文件。
3. CMake调用pkg-config的正确方式
CMake提供pkg_check_modules函数来规范调用pkg-config,不需要手动执行命令:
# 导入protobuf、grpc++、grpc的pkg-config配置,生成PkgConfig::GRPC目标 pkg_check_modules(GRPC REQUIRED IMPORTED_TARGET protobuf grpc++ grpc) # 链接时直接使用导入的目标 target_link_libraries(kv-validation_lib PRIVATE fmt::fmt libkv.a libkvproto.a yaml-cpp -lpthread ${_REFLECTION} PkgConfig::GRPC stdc++fs )
pkg_check_modules会自动处理头文件路径、链接库、编译选项,比手动粘贴命令输出更可靠。如果自定义库的pkg-config文件不在默认搜索路径,可以通过PATHS参数指定:
pkg_check_modules(GRPC REQUIRED IMPORTED_TARGET protobuf grpc++ grpc PATHS /workspace/third_party/centos/grpc_1480/lib/pkgconfig )
需要确保目标目录下存在protobuf.pc、grpc++.pc、grpc.pc这些pkg-config配置文件。
内容的提问来源于stack exchange,提问作者Raaka

