如何阻止CMake接口库源码向上传播,避免代码重复编译?
解决CMake静态库重复编译接口库源文件的问题
问题根源
你原来的代码中,接口库A通过PUBLIC方式链接到静态库B,导致A的INTERFACE_SOURCES(即a.cpp)会被传播给所有依赖B的目标(库C和可执行文件test),每个依赖B的目标都会独立编译a.cpp,最终生成的ELF文件中出现重复符号。
解决方案
方案1:拆分接口与实现(推荐)
将a.cpp直接作为静态库B的私有源文件,接口库A仅用于传递公共接口属性(如头文件路径、编译定义),避免源文件的不必要传播:
# 定义INTERFACE库A,仅传递接口属性(无源代码) add_library(a INTERFACE) # 示例:传递头文件目录(如果a.cpp需要的头文件对外暴露) target_include_directories(a INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) # 示例:传递公共编译定义(如果有需要) # target_compile_definitions(a INTERFACE COMMON_DEF) # 静态库B包含自身源文件和a.cpp,PRIVATE链接A以获取接口属性 add_library(b STATIC b.cpp a.cpp) target_link_libraries(b PRIVATE a) # 库C仅包含自身源文件,PUBLIC链接B add_library(c STATIC c.cpp) target_link_libraries(c PUBLIC b) # 可执行文件test链接B和C add_executable(test main.cpp) target_link_libraries(test PUBLIC b c)
方案2:限制接口库属性传播
如果希望保留接口库A包含a.cpp的定义,通过PRIVATE链接方式阻止A的属性传播给B的依赖目标:
# 定义INTERFACE库A,包含a.cpp作为接口源文件 add_library(a INTERFACE) target_sources(a INTERFACE a.cpp) # 静态库B链接A时使用PRIVATE,避免A的属性传播给依赖B的目标 add_library(b STATIC b.cpp) target_link_libraries(b PRIVATE a) # 库C仅包含自身源文件,PUBLIC链接B add_library(c STATIC c.cpp) target_link_libraries(c PUBLIC b) # 可执行文件test链接B和C add_executable(test main.cpp) target_link_libraries(test PUBLIC b c)
效果说明
两种方案都能实现:
libb.a包含a.cpp和b.cpp的编译产物libc.a仅包含c.cpp的编译产物test.elf仅链接libb.a和libc.a,不会重复编译a.cpp,避免符号重复问题
内容的提问来源于stack exchange,提问作者Maxim
相关产品推荐
相关产品推荐

