如何避免CMake为两个相似库重复构建?附设计合理性咨询
解决共享库测试重复编译与内部符号访问问题
避免重复编译的方法
最直接的方案是用CMake的对象库(OBJECT Library),先把源码编译成可复用的对象文件,再基于这些对象构建正式库和测试库,这样源码只会编译一次。
修改后的CMake代码如下:
# 先编译对象库,源码仅编译一次 add_library(mylib_objects OBJECT ${SOURCES}) # 构建正式共享库,链接对象库并启用符号限制 add_library(mylib SHARED $<TARGET_OBJECTS:mylib_objects>) export_signatures(mylib) install(TARGETS mylib DESTINATION "${CMAKE_INSTALL_PREFIX}/lib") # 若启用测试构建,基于同一份对象库构建无符号限制的测试库 if(ENABLE_TEST_BUILD) add_library(mylib-test SHARED $<TARGET_OBJECTS:mylib_objects>) endif()
这样就能避免util.cpp等源码被重复编译,大幅减少构建时间。
当前设计的合理性分析
你的思路是对的:通过构建无符号限制的测试库绕开内部符号无法访问的问题,能保证正式库的符号安全性。但原实现的问题在于直接重复创建共享库目标,导致CMake重复编译源码,属于实现方式不够高效,而非设计思路错误。
额外优化建议
- 无需安装测试库:测试库仅用于本地测试,不需要安装到系统路径,可去掉测试库的
install指令,避免污染正式安装目录。 - 直接编译测试代码:如果测试代码不多,也可以不单独建测试库,而是把测试源码和
mylib_objects直接链接成测试可执行文件,减少目标数量:if(ENABLE_TEST_BUILD) add_executable(mylib-tests test.cpp $<TARGET_OBJECTS:mylib_objects>) target_link_libraries(mylib-tests ...) # 链接测试框架等依赖 endif() - 条件控制符号限制:如果不想维护两个库目标,也可以给正式库添加条件编译开关,仅在非测试模式下启用符号限制:
但这种方式要注意:发布构建时必须确保add_library(mylib SHARED ${SOURCES}) if(NOT ENABLE_TEST_BUILD) export_signatures(mylib) endif() install(TARGETS mylib DESTINATION "${CMAKE_INSTALL_PREFIX}/lib")ENABLE_TEST_BUILD处于关闭状态,避免正式库意外暴露内部符号。
内容的提问来源于stack exchange,提问作者rahman
相关产品推荐
相关产品推荐

