为何CMake在依赖的导入库更新时不触发重建?
问题
先通过add_library(Foo STATIC foo.cpp foo.h)创建libFoo.a,再执行以下代码:
add_library(Foo STATIC IMPORTED) set_target_properties(Foo PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/libFoo.a) add_library(Bar STATIC bar.cpp bar.h) target_link_libraries(Bar Foo)
执行touch libFoo.a后再运行make,却未触发重建,这是为什么?
实际场景中,编译第三方依赖并执行make install更新后,通过find_package引入该依赖的项目构建目录并未重建,必须删除构建目录重新编译才能生效,这是CMake的bug吗?
解答
第一个问题的原因
CMake对IMPORTED目标不会自动追踪其关联文件的依赖关系。当你用add_library(Foo STATIC IMPORTED)声明导入库时,CMake只会记录这个库的路径,不会把libFoo.a作为Bar的依赖项监控它的修改时间。哪怕你用touch修改了libFoo.a,CMake构建系统也感知不到变化,自然不会触发Bar的重建。
而如果是直接用add_library(Foo STATIC foo.cpp foo.h)创建的原生目标,CMake会自动生成完整的依赖链,监控源文件和生成库的变化,一旦有修改就会触发重建。但改为导入目标后,这份自动依赖追踪就被切断了。
第二个问题:不是CMake的bug
这是CMake的设计特性,而非bug。find_package在第一次运行时会将依赖的路径、版本等信息缓存到构建目录的CMakeCache.txt文件中,后续执行make或cmake --build时,默认不会重新执行find_package检查依赖是否更新。
无需删除整个构建目录,有几种更高效的解决方式:
- 删除构建目录下的
CMakeCache.txt,重新运行cmake ..,让CMake重新查找依赖的最新版本 - 若使用CMake 3.24及以上版本,执行构建时添加
--fresh参数:cmake --build . --fresh,强制CMake重新运行配置步骤、刷新依赖信息 - 对于导入目标,可手动添加依赖追踪,比如用
add_dependencies或配置相关属性,让CMake监控依赖库的修改时间
内容的提问来源于stack exchange,提问作者user3667089
相关产品推荐
相关产品推荐

