为什么 CMake 从 INCLUDE_DIRECTORIES() 调用中删除一些包含目录?
Why is CMake removing some include directories from INCLUDE_DIRECTORIES() calls?
我们正在尝试交叉编译某个软件并且在大多数情况下它一直在工作。但是,包含文件被拆分到多个目录中,如果目录位于 sysroot 树之外,有时 CMake 决定不将其添加到 Makefiles 的包含列表中。
工具链是:
- 用于 ARM 的 GCC 4.4.1(windows 个可执行文件)
- MinGW 生成(无 MSYS)
CMake调用如下:
cmake -G"MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE=toolchain-vde.cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=C:\vf-install ..
toolchain-vde.cmake
文件是:
# the name of the target operating system
set(CMAKE_SYSTEM_NAME Linux)
# which compilers to use for C and C++
include(CMakeForceCompiler)
#Use 8.1 names if path has spaces since it will break on paths with spaces
set(CMAKE_C_COMPILER "C:/VDE/toolchains/windows/vos/arm-vf-linux-gnueabi/bin/arm-vf-linux-gnueabi-gcc.exe")
set(CMAKE_CXX_COMPILER "C:/VDE/toolchains/windows/vos/arm-vf-linux-gnueabi/bin/arm-vf-linux-gnueabi-g++.exe")
# here is the target environment located
SET(VF_SYSROOT "C:/VDE/SDKs/vos/default")
#Vf includes and libs
#Declared as variables for compatibility and usage by CMake scripts down the line
SET(VF_ADK_INCLUDE "C:\VDE\ADKs\default\vos\include")
SET(VF_ADK_LIB "C:/VDE/ADKs/default/vos/lib")
SET(VF_SDK_USR_LIB "${VF_SYSROOT}/usr/lib")
SET(VF_SDK_USR_LOCAL_LIB "${VF_SYSROOT}/usr/local/lib")
SET(VF_SDK_USR "${VF_SDK_USR_LIB}") #<-- Compatibility with old Vf detection
SET(VF_SVCMGR "${VF_SYSROOT}/usr/local/lib/svcmgr")
MESSAGE("debug1: --- ${VF_ADK_INCLUDE} --- ${VF_SYSROOT} ---")
SET(CMAKE_SYSROOT "${VF_SYSROOT}")
#Define variables for compiler and CMAKE scripts
set(VF_UX_410 TRUE)
add_definitions(-DVF_UX_410="${VF_UX_410}")
LINK_DIRECTORIES("${CMAKE_INSTALL_PREFIX}/lib")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lrt --std=gnu99")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lrt")
LIST(APPEND CMAKE_PREFIX_PATH "${CMAKE_INSTALL_PREFIX}")
INCLUDE_DIRECTORIES("${CMAKE_INSTALL_PREFIX}/include")
INCLUDE_DIRECTORIES("${VF_ADK_INCLUDE}")
注意最后一行,INCLUDE_DIRECTORIES("${VF_ADK_INCLUDE}")
这个目录,VF_ADK_INCLUDE
,如果它存在,将在构建期间被忽略。这意味着 make
调用将没有 -IC:\VDE\ADKs\default\vos\include
参数,但如果目录不存在,makefile 将具有 正确的 -I[...]
参数。
如果我添加 INCLUDE_DIRECTORIES
例如:
INCLUDE_DIRECTORIES(
"X:\"
"C:\VDE\ADKs\default\vos\include"
"Y:\"
)
X:
和 Y:
都将作为 -IX:\ -IY:\
出现在编译器调用中,但中间的包含不知何故丢失了。奇怪的是,如果我在配置期间重命名 include 目录(因此 cmake 找不到它),然后在编译期间将其重命名,CMake 添加了正确的 -I[...]
参数并且程序编译得很好。
作为一种解决方法,现在我正在对 CMAKE_C_FLAGS
和 CMAKE_CXX_FLAGS
变量的 -I[...]
参数进行硬编码,但这个解决方案远非正确。
编辑: MESSAGE
调用在 CMake 配置期间显示正确的 path/value。所以这不应该是 "variable is not defined" 问题。
本质上并使这个问题成为一个适当的问题:
为什么 CMake 从 INCLUDE_DIRECTORIES
调用中删除或忽略包含路径?
几天后我找不到更好的答案所以我会post这个自我回答因为它有效。
在编译器检测期间,CMake 将提取一系列通常始终可用的隐式包含路径,如果添加到包含路径,可能会破坏编译过程(感谢@Tsyvarev 的警告)。但是,如果此路径被错误地添加到排除的路径中,我能找到覆盖它的唯一方法是使用以下方法一起删除排除列表:
unset(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES)
unset(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES)
如 https://gitlab.kitware.com/cmake/cmake/issues/17966 所述,但此解决方案使用 CMake 内部构件,因此它可能成功或失败,具体取决于您的编译器或环境。在这种特殊情况下,修复有效。
在类似的情况下,再次使用专有 + 古老的 gcc 工具链,只需更新到最新的 CMake 版本就可以了,显然是由于更好的编译器检测。
我们正在尝试交叉编译某个软件并且在大多数情况下它一直在工作。但是,包含文件被拆分到多个目录中,如果目录位于 sysroot 树之外,有时 CMake 决定不将其添加到 Makefiles 的包含列表中。
工具链是:
- 用于 ARM 的 GCC 4.4.1(windows 个可执行文件)
- MinGW 生成(无 MSYS)
CMake调用如下:
cmake -G"MinGW Makefiles" -DCMAKE_TOOLCHAIN_FILE=toolchain-vde.cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=C:\vf-install ..
toolchain-vde.cmake
文件是:
# the name of the target operating system
set(CMAKE_SYSTEM_NAME Linux)
# which compilers to use for C and C++
include(CMakeForceCompiler)
#Use 8.1 names if path has spaces since it will break on paths with spaces
set(CMAKE_C_COMPILER "C:/VDE/toolchains/windows/vos/arm-vf-linux-gnueabi/bin/arm-vf-linux-gnueabi-gcc.exe")
set(CMAKE_CXX_COMPILER "C:/VDE/toolchains/windows/vos/arm-vf-linux-gnueabi/bin/arm-vf-linux-gnueabi-g++.exe")
# here is the target environment located
SET(VF_SYSROOT "C:/VDE/SDKs/vos/default")
#Vf includes and libs
#Declared as variables for compatibility and usage by CMake scripts down the line
SET(VF_ADK_INCLUDE "C:\VDE\ADKs\default\vos\include")
SET(VF_ADK_LIB "C:/VDE/ADKs/default/vos/lib")
SET(VF_SDK_USR_LIB "${VF_SYSROOT}/usr/lib")
SET(VF_SDK_USR_LOCAL_LIB "${VF_SYSROOT}/usr/local/lib")
SET(VF_SDK_USR "${VF_SDK_USR_LIB}") #<-- Compatibility with old Vf detection
SET(VF_SVCMGR "${VF_SYSROOT}/usr/local/lib/svcmgr")
MESSAGE("debug1: --- ${VF_ADK_INCLUDE} --- ${VF_SYSROOT} ---")
SET(CMAKE_SYSROOT "${VF_SYSROOT}")
#Define variables for compiler and CMAKE scripts
set(VF_UX_410 TRUE)
add_definitions(-DVF_UX_410="${VF_UX_410}")
LINK_DIRECTORIES("${CMAKE_INSTALL_PREFIX}/lib")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -lrt --std=gnu99")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lrt")
LIST(APPEND CMAKE_PREFIX_PATH "${CMAKE_INSTALL_PREFIX}")
INCLUDE_DIRECTORIES("${CMAKE_INSTALL_PREFIX}/include")
INCLUDE_DIRECTORIES("${VF_ADK_INCLUDE}")
注意最后一行,INCLUDE_DIRECTORIES("${VF_ADK_INCLUDE}")
这个目录,VF_ADK_INCLUDE
,如果它存在,将在构建期间被忽略。这意味着 make
调用将没有 -IC:\VDE\ADKs\default\vos\include
参数,但如果目录不存在,makefile 将具有 正确的 -I[...]
参数。
如果我添加 INCLUDE_DIRECTORIES
例如:
INCLUDE_DIRECTORIES(
"X:\"
"C:\VDE\ADKs\default\vos\include"
"Y:\"
)
X:
和 Y:
都将作为 -IX:\ -IY:\
出现在编译器调用中,但中间的包含不知何故丢失了。奇怪的是,如果我在配置期间重命名 include 目录(因此 cmake 找不到它),然后在编译期间将其重命名,CMake 添加了正确的 -I[...]
参数并且程序编译得很好。
作为一种解决方法,现在我正在对 CMAKE_C_FLAGS
和 CMAKE_CXX_FLAGS
变量的 -I[...]
参数进行硬编码,但这个解决方案远非正确。
编辑: MESSAGE
调用在 CMake 配置期间显示正确的 path/value。所以这不应该是 "variable is not defined" 问题。
本质上并使这个问题成为一个适当的问题:
为什么 CMake 从 INCLUDE_DIRECTORIES
调用中删除或忽略包含路径?
几天后我找不到更好的答案所以我会post这个自我回答因为它有效。
在编译器检测期间,CMake 将提取一系列通常始终可用的隐式包含路径,如果添加到包含路径,可能会破坏编译过程(感谢@Tsyvarev 的警告)。但是,如果此路径被错误地添加到排除的路径中,我能找到覆盖它的唯一方法是使用以下方法一起删除排除列表:
unset(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES)
unset(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES)
如 https://gitlab.kitware.com/cmake/cmake/issues/17966 所述,但此解决方案使用 CMake 内部构件,因此它可能成功或失败,具体取决于您的编译器或环境。在这种特殊情况下,修复有效。
在类似的情况下,再次使用专有 + 古老的 gcc 工具链,只需更新到最新的 CMake 版本就可以了,显然是由于更好的编译器检测。