CMake:parsing文件的哪个Order(Cache,Toolchain,…)?
这似乎是一个微不足道的问题,因为CMake是一种脚本语言,一般的答案是:严格的顺序。 但是我遇到过几种情况,CMake在parsing某些文件的时候或者以何种顺序重要。 所以我想知道:
- 是否有可用的文档描述文件(包括内部CMake文件)的parsing顺序?
- 文件顺序取决于CMake版本或一些CMake选项/设置/环境。 select的发生器或主机环境?
我遇到的情况到目前为止,上面的信息是重要的:
- 在编译器被识别之前,工具链文件被parsing,所以你必须首先在工具链文件中/在工具链文件中填充某些CMakevariables: 具有特定链接器的cmake交叉编译不会将parameter passing给armlink
- 工具链文件被多次parsing,因此例如从工具链文件中显示多次打印消息: cmake toolchain包含多个文件
- 可以从主
CMakeLists.txt
文件之外的范围调用variables监视器已parsing: 在“configuration”步骤完成之前的最后一步,执行CMake中的命令或macros
也许你知道更多。
要find答案,我已经尝试了以下内容:我已经安装了一个简单的主CMakeList.txt,如下所示,并运行cmake --trace …
来分析parsing顺序。
cmake_minimum_required(VERSION 2.8) include(BeforeProjectCmd.cmake) project(ParserTest CXX) add_subdirectory(LibTarget1) add_subdirectory(LibTarget2) add_executable(ExeTarget Test.cpp) variable_watch(CMAKE_BACKWARDS_COMPATIBILITY)
当我然后运行如cmake --debug-output --trace -G"Visual Studio 12 2013" -DCMAKE_TOOLCHAIN_FILE:FILE_PATH=Toolchain.txt
我得到了一个长的痕迹,我试图总结:
# begin try to read CMakeCache.txt ${CMAKE_BINARY_DIR}/CMakeCache.txt PreLoad.cmake ${CMAKE_BINARY_DIR}/PreLoad.cmake # end try to read ┌ CMakeLists.txt(1): cmake_minimum_required(VERSION 2.8 ) │ CMakeLists.txt(3): include(BeforeProjectCmd.cmake ) │ ├─ BeforeProjectCmd.cmake │ │ CMakeLists.txt(5): project(ParserTest CXX ) ├┬ share/cmake-3.2/Modules/CMakeDetermineSystem.cmake ││ │└─ Toolchain.txt │ ├┬ ${CMAKE_PLATFORM_INFO_DIR}/CMakeSystem.cmake ││ │└─ Toolchain.txt │ ├─ share/cmake-3.2/Modules/CMakeSystemSpecificInitialize.cmake ├┬ share/cmake-3.2/Modules/CMakeDetermineCXXCompiler.cmake │├┬ share/cmake-3.2/Modules/CMakeDetermineCompiler.cmake ││├ share/cmake-3.2/Modules/Platform/Windows-CXX.cmake … ││├ share/cmake-3.2/Modules/CMakeDetermineCompilerId.cmake ││├─ share/cmake-3.2/Modules/CMakeCompilerIdDetection.cmake … ││├ share/cmake-3.2/Modules/Compiler/MSVC-DetermineCompiler.cmake … │├ ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/3.2.2/CMakeCXXCompiler.cmake │├ share/cmake-3.2/Modules/CMakeSystemSpecificInformation.cmake │├┬ share/cmake-3.2/Modules/CMakeGenericSystem.cmake ││├ share/cmake-3.2/Modules/Platform/Windows.cmake ││└─ share/cmake-3.2/Modules/Platform/WindowsPaths.cmake │├ share/cmake-3.2/Modules/CMakeCXXInformation.cmake │├┬ share/cmake-3.2/Modules/Compiler/MSVC-CXX.cmake ││├ share/cmake-3.2/Modules/Platform/Windows-MSVC-CXX.cmake ││├┬ share/cmake-3.2/Modules/Platform/Windows-MSVC.cmake │││└─ share/cmake-3.2/Modules/CMakeRCInformation.cmake ││└ share/cmake-3.2/Modules/CMakeCommonLanguageInclude.cmake │├ share/cmake-3.2/Modules/CMakeTestCXXCompiler.cmake │├┬ share/cmake-3.2/Modules/CMakeTestCompilerCommon.cmake ││├ share/cmake-3.2/Modules/CMakeDetermineCompilerABI.cmake ││├ share/cmake-3.2/Modules/CMakeDetermineCompileFeatures.cmake ││├ share/cmake-3.2/Modules/Internal/FeatureTesting.cmake ││└ share/cmake-3.2/Modules/Compiler/MSVC-CXX-FeatureTests.cmake │└ ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/3.2.2/CMakeCXXCompiler.cmake │ │ CMakeLists.txt(7): add_subdirectory(LibTarget1 ) │ ├─ LibTarget1/CMakeLists.txt │ │ CMakeLists.txt(8): add_subdirectory(LibTarget2 ) │ ├─ LibTarget2/CMakeLists.txt │ │ CMakeLists.txt(10): add_executable(ExeTarget Test.cpp ) │ CMakeLists.txt(12): variable_watch(CMAKE_BACKWARDS_COMPATIBILITY ) │ │ CMake Debug Log in CMakeLists.txt: │ Variable "CMAKE_BACKWARDS_COMPATIBILITY" was accessed using UNKNOWN_READ_ACCESS with value "". -- Configuring done -- Generating ${CMAKE_BINARY_DIR} -- Generating ${CMAKE_BINARY_DIR}/LibTarget1 -- Generating ${CMAKE_BINARY_DIR}/LibTarget2 -- Generating done # writes ${CMAKE_BINARY_DIR}/CMakeCache.txt
所以看到上面的输出,我到了目前为止,下面的结论(我希望是真实的,有点通用):
- CMakeCache.txt文件只有在configuration开始后才读取一次,并在生成完成后写入。 它只是坚持“全局variables”caching的状态。
-
project()
命令触发了大部分CMake的检测魔法(包括从Toolchain.txt
文件中读取)。 - 工具链文件被读取两次。 一旦检测到make / compile系统,并且一旦在生成的
CMakeSystem.cmake
。 -
variable_watch()
钩子可以随时触发,因此调用optinal“执行命令”的作用域是未定义的。
关于CMake的这个特定的内部工作没有官方文档,所以请在下面总结一下我所了解到的关于CMake的内容。
什么文件被parsing取决于
- 主机和目标操作系统
- 目标编译器
- 你的主机的环境(variables,registry,安装的软件)
- 您的项目的CMake脚本文件,其中可能包括
- 你的工具链文件
- 您select的编程语言
- 任何外部项目/库/文件/脚本
这些参数有很多可能的组合,但是大部分时间CMake都会自动检测正确的设置,并且不需要麻烦它是如何完成的。 好消息是,当你需要知道的时候,它会遵循一些固有的模式。
有趣的是,它只是勉强取决于你正在select的CMake发生器 。
初始步骤:编译器检测和validation
这主要从project()
命令开始。 以CXX
语言为例,编译器检测的主要文件是(参见问题跟踪输出中的根文件):
-
share/cmake-xy/Modules/CMakeDetermineCXXCompiler.cmake
这基本上试图确定编译器可执行文件的位置,并调用它来获得更具体的编译器ID。
此外,它还定义了基于主机环境和目标操作系统的源/输出文件扩展名。
-
share/cmake-xy/Modules/CMakeCXXCompiler.cmake.in
这是将编译器检测结果存储在
${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/xyz/CMakeCXXCompiler.cmake
。主要是这些variables是:
CMAKE_CXX_COMPILER
,CMAKE_CXX_SOURCE_FILE_EXTENSIONS
,CMAKE_CXX_IGNORE_EXTENSIONS
和CMAKE_CXX_COMPILER_ENV_VAR
-
share/cmake-xy/Modules/CMakeCXXInformation.cmake
该文件为编译器设置基本标志。 这也是编译器,主机和目标确实对调用具有最大影响的地方,例如:
include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_CXX_COMPILER_ID}-CXX-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL) include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_CXX_COMPILER_ID}-CXX OPTIONAL) include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME} OPTIONAL) include(Platform/${CMAKE_SYSTEM_NAME} OPTIONAL)
-
share/cmake-xy/Modules/CMakeTestCXXCompiler.cmake
这确实testing了一切,例如通过在一个简单的生成的CMake项目中调用编译器来确定编译器function。
这些步骤的结果存储在cachingvariables中,这些文件在这种情况下是特殊的,它们由像CMAKE_CXX_COMPILER_LOADED
, CMAKE_CXX_INFORMATION_LOADED
或CMAKE_CXX_COMPILER_WORKS
这样的variables进行保护,以便不再在每个连续的CMakeconfiguration步骤中运行。
项目configuration文件:修改默认值
有几种方法可以改变一个CMake默认值,而不需要实际触及你项目的CMakeLists.txt
文件。
-
-C <initial-cache>
命令行选项如果你想给出一些预置值(你通常会通过
-D ...
选项)一次又一次地通过几个项目,这可以使用。 就像计算机上的某些库searchpath或公司中使用的某些预设一样。 -
CMakeCache.txt
通过例如cmake-gui
在最终生成构build环境之前,
cmake-gui
允许您手动修改项目的选项(编辑CMakeCache.txt
所有非内部variables)。 -
CMAKE_TOOLCHAIN_FILE
主要用于交叉编译 ,但可以更一般地描述为每个编译器工具链使用的预设值。
-
PreLoad.cmake
或多或less与“初始caching”选项相同(请参阅上文),但不是通过命令行选项给出的。 它只是在你的项目的
CMakeLists.txt
相同的目录。注意 :它支持所有的CMake脚本命令,如
if()
调用,但是PreLoad.cmake
有它的- 自己的variables范围(这里的所有非caching在主
CMakeLists.txt
是不可见的) - 限制什么是已知的(它在一切之前运行,所以主要是你可以检查
CMAKE_GENERATOR
)
- 自己的variables范围(这里的所有非caching在主
-
CMAKE_USER_MAKE_RULES_OVERRIDE
,CMAKE_USER_MAKE_RULES_OVERRIDE_<LANG>
这允许在CMake自动检测后修改非分配的默认值。
示例 :通过
.c
文件扩展有效的CXX源文件扩展名MakeRulesOverwrite.cmake
list(APPEND CMAKE_CXX_SOURCE_FILE_EXTENSIONS c)
然后你可以用类似的方式调用
cmake
> cmake -D CMAKE_USER_MAKE_RULES_OVERRIDE:PATH=..\MakeRulesOverwrite.cmake ..
-
CMAKE_PROJECT_ParserTest_INCLUDE
这是为了在处理完
project()
命令(并检测到构build环境project()
后直接“将自定义代码注入到项目构build中而不修改其源代码”。
Toolchain.cmake:parsing多次
在确定系统,编译器等时多次读取工具链文件 。
重要的是要知道的是:
-
它是每个
try_compile()
调用读取的。 而且由于尝试编译必须产生一个有效的可执行文件,所以你可能需要 – 如果你正在交叉编译 –-
CMAKE_TRY_COMPILE_TARGET_TYPE
到STATIC_LIBRARY
(CMake版本3.6或以上) - 检查
IN_TRY_COMPILE
全局属性以添加其他选项
-
-
如果你改变你的工具链文件,CMake会重新触发编译器检测(如上面的跟踪)。 这对你的编译器设置有很大的帮助。
CMake重新configuration:一切都来自caching
最后但并非最不重要,重要的是要知道上面的跟踪只显示了第一步。 所有连续的项目configuration将从caching的variables中获取几乎所有内容,因此在重新configuration运行时将读取less得多的文件。
参考
- 开源应用程序体系结构:CMake
- 从makefile到cmake的一般规则
- CMakeLists.txt CMake错误:30(项目):找不到CMAKE_C_COMPILER