如何解决Ubuntu下链接libc++时Google Benchmark的CMake导出错误
问题背景
在Ubuntu的C++项目中,通过CMake的add_subdirectory引入llvm-project的runtimes模块构建libc++,并通过link_libraries让所有目标链接cxx_shared和cxxabi_shared。但引入Google Benchmark时,因为其src/CMakeLists.txt中的无条件export语句,导致报错:
CMake Error in external/benchmark/src/CMakeLists.txt:
export called with target "benchmark" which requires target "cxx_shared"
that is not in any export set.CMake Error in external/benchmark/src/CMakeLists.txt:
export called with target "benchmark" which requires target "cxxabi_shared"
that is not in any export set.
该export语句未包含在BENCHMARK_ENABLE_INSTALL条件块中,而用户已设置BENCHMARK_ENABLE_INSTALL=OFF。
1. 是否有办法让CMake忽略项目中的所有导出集合?
没有直接对应CMAKE_SKIP_INSTALL_ALL_DEPENDENCY的全局忽略export的选项,但可以通过两种实用方法屏蔽Benchmark的export行为:
- 方法一:临时覆盖
export函数
在add_subdirectory(benchmark)之前定义空的export函数,屏蔽该子目录内的所有export调用:# 在add_subdirectory(benchmark)前添加 function(export) # 空函数覆盖默认export命令 endfunction() add_subdirectory(external/benchmark EXCLUDE_FROM_ALL SYSTEM) # 恢复默认export函数 unset(export) - 方法二:预修改Benchmark的导出目标列表
创建benchmark_fix.cmake脚本:
然后在主CMakeLists中指定预包含脚本,清空Benchmark要导出的目标:set(targets_to_export "")set(CMAKE_PROJECT_benchmark_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/benchmark_fix.cmake) add_subdirectory(external/benchmark EXCLUDE_FROM_ALL SYSTEM)
2. 是否应向Google Benchmark反馈修改export为条件执行?
完全合理。该export语句原本属于BENCHMARK_ENABLE_INSTALL块,后来被移出属于逻辑回归:
- 当
BENCHMARK_ENABLE_INSTALL=OFF时,导出的cmake配置文件没有实际用途,因为不会被安装或供外部项目引用。 - 其他主流依赖(如abseil、fmt等)的
export语句均包含在安装条件块中,符合CMake常规实践。 - 可以提交Issue或PR,建议将
export语句放回if(BENCHMARK_ENABLE_INSTALL)块内,或新增BENCHMARK_ENABLE_EXPORT开关变量默认与安装开关联动。
3. 是否应向llvm-project反馈为libcxx目标定义导出集合?
不建议。libcxx作为LLVM运行时库,其构建系统的设计目标是独立构建或作为LLVM整体构建的一部分,而非作为CMake子项目被其他项目导出复用:
cxx_shared等目标是本地构建产物,依赖特定的路径和配置,不具备跨项目导出的通用性。- 强行添加导出集合会导致其他项目引入时出现路径、版本不匹配的问题,违背libcxx的使用场景。
4. 是否可以自行为libcxx目标定义导出集合?
可以,但维护成本高,不推荐作为长期方案:
- 手动导出需要处理绝对路径等问题,示例代码如下:
这种方法会让导出文件包含本地构建的绝对路径,无法在其他环境复用,且libcxx配置(如调试、sanitizer)变化时需要重新导出。add_subdirectory(external/llvm-project/runtimes EXCLUDE_FROM_ALL SYSTEM) # 导出libcxx目标到临时文件 export(TARGETS cxx_shared cxxabi_shared FILE ${CMAKE_BINARY_DIR}/libcxx_export.cmake) # 导入导出的目标供后续项目使用 include(${CMAKE_BINARY_DIR}/libcxx_export.cmake)
内容的提问来源于stack exchange,提问作者Chris

