CMake中INCLUDE引入文件内FILE GLOB路径异常问题咨询
问题:CMake中
FILE(GLOB)在INCLUDE与ADD_SUBDIRECTORY场景下行为差异? 环境与项目结构
- 系统:Windows
- CMake版本:3.22.2
- 项目文件结构:
go.batCMakeLists.txtextensions/LookForExtensions.cmakesubprojects/CMakeLists.txt
go.bat内容
:: launch an out-of-source build, to avoid clutter; generator could be anything @cmake -G "Visual Studio 16" -H%~dp0 -B%~dp0build
根目录CMakeLists.txt内容
CMAKE_MINIMUM_REQUIRED(VERSION 3.5) PROJECT( mve ) INCLUDE( extensions/LookForExtensions.cmake ) # 通过INCLUDE()调用脚本 ADD_SUBDIRECTORY( subprojects ) # 通过ADD_SUBDIRECTORY()加载子项目
subprojects/CMakeLists.txt 与 extensions/LookForExtensions.cmake 内容(两者完全一致)
SET( here ${CMAKE_CURRENT_LIST_DIR} ) MESSAGE( "Looking for files/directories in " ${here} ) # 两种场景下路径均正确 FILE( GLOB contents RELATIVE ${here} * ) # 行为出现差异 FOREACH( match ${contents} ) MESSAGE( "* found " ${match} ) ENDFOREACH()
执行输出(带注释)
C:\cmake-trouble>go -- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.22621. Looking for files/directories in C:/cmake-trouble/extensions # 路径正确 * found ../CMakeLists.txt # 结果错误,列出了上级目录内容 * found ../build # 结果错误 * found ../go.bat # 结果错误 * found ../subprojects # 结果错误 Looking for files/directories in C:/cmake-trouble/subprojects # 路径正确 * found CMakeLists.txt # 结果正确 -- Configuring done -- Generating done -- Build files have been written to: C:/cmake-trouble/build
核心疑问
为何相同代码在两种调用场景中FILE(GLOB)表现差异巨大?如何让LookForExtensions.cmake中的FILE(GLOB)正常工作?${here}路径正确,但RELATIVE ${here}似乎未生效。
解答
差异原因
问题核心在于CMake工作目录与源码目录的区别:
- 使用
ADD_SUBDIRECTORY(subprojects)时,CMake会自动切换工作目录到build/subprojects(对应子项目的构建目录),此时FILE(GLOB *)是在该构建目录下查找内容,再通过RELATIVE ${here}(即源码目录C:/cmake-trouble/subprojects)转换路径,得到的是相对源码目录的正确结果。 - 使用
INCLUDE(extensions/LookForExtensions.cmake)时,CMake工作目录仍为根构建目录build,此时FILE(GLOB *)查找的是build目录下的所有内容,再通过RELATIVE ${here}(即源码目录C:/cmake-trouble/extensions)转换路径,自然得到../开头的相对路径——因为build目录的内容相对于extensions目录就是上级目录的文件。
简言之:FILE(GLOB)的通配符*是相对于**当前工作目录(构建目录)**而非CMAKE_CURRENT_LIST_DIR(源码目录)查找的,RELATIVE仅负责将找到的绝对路径转换为相对指定目录的路径,并非限定查找范围。
修复方法
要让LookForExtensions.cmake正确查找extensions目录下的内容,需明确指定查找路径为${here}/*,修改后的代码如下:
SET( here ${CMAKE_CURRENT_LIST_DIR} ) MESSAGE( "Looking for files/directories in " ${here} ) # 明确指定查找路径为当前源码目录下的所有内容 FILE( GLOB contents RELATIVE ${here} "${here}/*" ) FOREACH( match ${contents} ) MESSAGE( "* found " ${match} ) ENDFOREACH()
修改后,无论CMake当前工作目录在哪里,FILE(GLOB)都会直接查找${here}(即extensions源码目录)下的内容,再通过RELATIVE ${here}转换为相对该目录的路径,即可得到正确结果。
额外提示:CMake官方不推荐用
FILE(GLOB)做依赖管理,因为它不会自动检测文件的新增/删除。如果需要跟踪文件变化,建议手动列出文件或结合其他机制,但这不属于当前问题的核心修复范围。
内容的提问来源于stack exchange,提问作者jez
相关产品推荐
相关产品推荐

