CMake中从库生成可执行文件并实现跨库链接的问题
问题原因与解决方法
你犯的核心错误是把库目标名当成源文件传给了add_executable。add_executable的参数规则是:第一个是可执行目标名,后面跟的都是编译该可执行文件需要的源文件路径,CMake会把foo-lib、bar-lib当成源文件名去磁盘查找,自然找不到,所以报错。
正确的CMake写法
要实现「用库生成可执行文件+库之间互相链接」,应该遵循「先定义库/可执行目标,再通过target_link_libraries建立链接依赖」的规则:
# 构建foo静态库 add_library(foo-lib STATIC src/foo.cpp) target_include_directories(foo-lib PUBLIC include) # 把include目录暴露给依赖foo-lib的目标 # 构建foo的测试可执行文件:这里要传测试源文件,比如foo的单元测试代码src/foo_ut.cpp add_executable(foo-ut src/foo_ut.cpp) target_link_libraries(foo-ut PRIVATE foo-lib lib1 lib2) # 把foo-lib和其他依赖库链接到foo-ut # 构建bar静态库,并链接foo-lib add_library(bar-lib STATIC src/bar.cpp) target_link_libraries(bar-lib PRIVATE foo-lib) # bar-lib依赖foo-lib,自动继承foo-lib的include目录 target_include_directories(bar-lib PUBLIC include) # 构建bar的测试可执行文件 add_executable(bar-ut src/bar_ut.cpp) target_link_libraries(bar-ut PRIVATE bar-lib) # 只需要链接bar-lib,bar-lib已经依赖foo-lib,会自动传递链接
关键细节说明
target_include_directories用PUBLIC/PRIVATE控制目录的可见性:如果库的头文件需要被依赖它的目标使用,就用PUBLIC,这样依赖方不需要再重复写include目录。target_link_libraries里的库目标会自动处理依赖传递,比如bar-ut链接bar-lib后,CMake会自动把foo-lib也链接进去,不需要手动重复写。
关于直接添加源文件的方式
你提到的add_executable(bar-ut src/foo.cpp src/bar.cpp)确实能运行,但非常不推荐:
- 重复编译:foo.cpp会被编译两次(一次在foo-lib,一次在bar-ut),浪费编译时间。
- 维护性差:如果后续foo.cpp的路径、文件名修改,你需要手动在所有直接引用它的地方更新,而用库的话只需要修改foo-lib的定义即可。
- 依赖关系混乱:无法清晰体现bar-ut是依赖bar-lib和foo-lib的,CMake的目标依赖管理能力完全没用到。
内容的提问来源于stack exchange,提问作者xyf
相关产品推荐
相关产品推荐

