CMake:文件解析的顺序(缓存、工具链等)? [英] CMake: In which order are files parsed (cache, toolchain, etc.)?

查看:47
本文介绍了CMake:文件解析的顺序(缓存、工具链等)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这似乎是一个微不足道的问题,因为 CMake 是一种脚本语言,所以一般的答案是:严格顺序.但是我遇到了几种情况,其中 CMake 解析某些文件的时间或顺序很重要.所以我想知道:

  1. 是否有描述顺序的可用文档文件(包括内部 CMake 文件)被解析?
  2. 文件顺序取决于 CMake 版本或某些 CMake 选项/设置/环境,包括.选择的生成器或主机环境?

到目前为止我遇到的案例,其中上述信息很重要:

也许你知道得更多.

为了找到答案,我尝试了以下方法:我设置了一个简单的主 CMakeLists.txt,如下所示,并运行 cmake --trace ... 来分析解析顺序.

cmake_minimum_required(VERSION 2.8)包括(BeforeProjectCmd.cmake)项目(ParserTest CXX)add_subdirectory(LibTarget1)add_subdirectory(LibTarget2)add_executable(ExeTarget Test.cpp)变量手表(CMAKE_BACKWARDS_COMPATIBILITY)

当我然后运行例如cmake --debug-output --trace -G"Visual Studio 12 2013" -DCMAKE_TOOLCHAIN_FILE:FILE_PATH=Toolchain.txt 我得到了一个我试图总结的长跟踪:

#开始尝试阅读CMakeCache.txt${CMAKE_BINARY_DIR}/CMakeCache.txt预加载文件${CMAKE_BINARY_DIR}/PreLoad.cmake# 结束尝试阅读┌ CMakeLists.txt(1): cmake_minimum_required(VERSION 2.8)│ CMakeLists.txt(3): include(BeforeProjectCmd.cmake)│├─ BeforeProjectCmd.cmake││ CMakeLists.txt(5): 项目(ParserTest CXX)├┬ share/cmake-3.2/Modules/CMakeDetermineSystem.cmake│││└─ 工具链.txt│├┬ ${CMAKE_PLATFORM_INFO_DIR}/CMakeSystem.cmake│││└─ 工具链.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:│ 变量CMAKE_BACKWARDS_COMPATIBILITY"是使用值为"的UNKNOWN_READ_ACCESS访问的.-- 配置完成-- 生成 ${CMAKE_BINARY_DIR}-- 生成 ${CMAKE_BINARY_DIR}/LibTarget1-- 生成 ${CMAKE_BINARY_DIR}/LibTarget2-- 生成完成# 写${CMAKE_BINARY_DIR}/CMakeCache.txt

所以看到上面的输出,我得出了以下结论(我希望这是真的,而且有点笼统):

  1. CMakeCache.txt 文件只在配置启动时读取一次,生成完成后写入.它只是保持全局变量"缓存的状态.
  2. project() 命令触发了 CMake 的大部分检测魔法(包括从 Toolchain.txt 文件中读取).
  3. 工具链文件被读取两次.一次是在检测到 make/compile 系统之前,一次是在随后生成的 CMakeSystem.cmake 中.
  4. variable_watch() 钩子可以随时触发,因此调用最佳执行命令"的范围是不确定的.

解决方案

没有关于 CMake 的这个特定内部工作的官方文档,所以请在下面找到我迄今为止对 CMake 的了解的总结...

解析什么文件取决于

  1. 主机和目标操作系统
  2. 目标编译器
  3. 您的主机环境(变量、注册表、安装的软件)
  4. 您项目的 CMake 脚本文件,其中可能包括

    1. 您的工具链文件
    2. 您选择的编程语言
    3. 任何外部项目/库/文件/脚本

这些参数有很多可能的组合,但大多数时候 CMake 会自动为您检测正确的设置,您无需担心它是如何完成的.好消息是 - 当您需要知道时 - 它遵循某些内在模式.

有趣的是,它仅略微依赖于 CMake 生成器 你正在选择.

初始步骤:编译器检测和验证

这主要从project() 命令.以CXX语言为例,编译器检测的主要文件有(另见问题trace输出中的根文件):

  • share/cmake-x.y/Modules/CMakeDetermineCXXCompiler.cmake

    这基本上是尝试确定编译器可执行文件的位置,并调用它来获取更具体的编译器 ID.

    此外,例如根据主机计算机环境和目标操作系统定义源/输出文件扩展名.

  • share/cmake-x.y/Modules/CMakeCXXCompiler.cmake.in

    这是将编译器检测结果存储在${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/x.y.z/CMakeCXXCompiler.cmake中的模板.

    主要是这些变量:CMAKE_CXX_COMPILERCMAKE_CXX_SOURCE_FILE_EXTENSIONSCMAKE_CXX_IGNORE_EXTENSIONSCMAKE_CXX_COMPILER_ENV_VARp>

  • share/cmake-x.y/Modules/CMakeCXXInformation.cmake

    此文件为编译器设置基本标志.这也是编译器、主机和目标对设置影响最大的地方,调用如下:

    include(平台/${CMAKE_SYSTEM_NAME}-${CMAKE_CXX_COMPILER_ID}-CXX-${CMAKE_SYSTEM_PROCESSOR} 可选)包括(平台/${CMAKE_SYSTEM_NAME}-${CMAKE_CXX_COMPILER_ID}-CXX 可选)包括(平台/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME} 可选)包括(平台/${CMAKE_SYSTEM_NAME} 可选)

  • share/cmake-x.y/Modules/CMakeTestCXXCompiler.cmake

    这确实测试了一切,例如通过在简单生成的 CMake 项目中实际调用编译器来确定编译器功能.

这些步骤的结果存储在缓存变量中,这些文件在这种情况下是特殊的,它们由诸如 CMAKE_CXX_COMPILER_LOADEDCMAKE_CXX_INFORMATION_LOADEDCMAKE_CXX_COMPILER_WORKS 不再运行每个连续的 CMake 配置步骤.

项目配置文件:修改默认值

有多种方法可以更改 CMake 默认值,而无需实际更改项目的 CMakeLists.txt 文件.

  • -C <initial-cache> 命令行选项

    如果您想通过多个项目一遍又一遍地给出一些预设值(通常通过 -D ... 选项给出),可以使用此方法.比如你电脑上的一些图书馆搜索路径或你公司使用的一些预设.

  • CMakeCache.txt 通过例如cmake-gui

    cmake-gui 允许您在最终生成构建环境之前手动修改项目的选项(编辑 CMakeCache.txt 中的所有非内部变量).

  • CMAKE_TOOLCHAIN_FILE

    主要用于交叉编译,但它可以更一般地描述为每个使用的编译器工具链的预设值.

  • PreLoad.cmake

    或多或少与初始缓存"选项(见上文)相同,但它不是通过命令行选项给出的.它必须与您项目的 CMakeLists.txt 位于同一目录中.

    注意:它支持所有 CMake 脚本命令,例如 if() 调用,但 PreLoad.cmake 有它的

    • 自己的变量范围(此处未缓存的所有内容在您的主 CMakeLists.txt 中均不可见)
    • 限制已知的东西(它在其他一切之前运行,所以大多数情况下你可以检查CMAKE_GENERATOR)
  • CMAKE_USER_MAKE_RULES_OVERRIDE, CMAKE_USER_MAKE_RULES_OVERRIDE_

    这允许在 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() 命令被处理(并检测到构建环境)后,直接将自定义代码注入到项目构建中而不修改其源代码".

    莉>

Toolchain.cmake:多次解析

工具链文件被多次读取,同时确定系统、编译器等.

重要的是:

  • 它与每个 try_compile() 呼叫.并且由于 try compile 必须生成有效的可执行文件,因此您可能需要 - 如果您是例如交叉编译 - 到

  • 如果您更改工具链文件,CMake 将重新触发编译器检测(如上面的跟踪所示).这对使用您的编译器设置有很大帮助.

CMake 重新配置:一切都来自缓存

最后但并非最不重要的是,重要的是要知道上面的跟踪仅显示了初始步骤.所有连续的项目配置都将从缓存变量中获取几乎所有内容,因此在重新配置运行中读取的文件要少得多.

参考文献

This seems as a trivial question, since CMake is a script language the general answer is: strictly sequential. But I came across several cases where it was important when or in which order CMake is parsing certain files. So I wonder:

  1. Is there a documentation available that describes the order in which files (incl. internal CMake files) are parsed?
  2. Is the file order depending on the CMake version or some CMake options/settings/environment incl. the chosen generator or host environment?

The cases I came across so far, where the above information was important:

Maybe you know even more.

To find an answer, I have tried the following: I have setup a simple main CMakeLists.txt as shown below and run cmake --trace … to analyze the parsing order.

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)

When I then run e.g. cmake --debug-output --trace -G"Visual Studio 12 2013" -DCMAKE_TOOLCHAIN_FILE:FILE_PATH=Toolchain.txt I got a long trace that I tried to summarize:

# 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

So seeing the above output I came - so far - to following conclusion (which I hope are true and somewhat generic):

  1. The CMakeCache.txt file is only read once when configuration is started and written after the generation is finished. It just persists the state of the "global variables" cache.
  2. The project() command trigger most of CMake's detection magic (including reading from the Toolchain.txt file).
  3. The toolchain file is read twice. Once before the make/compile system is detected and once inside the then generated CMakeSystem.cmake.
  4. The variable_watch() hook can trigger anytime, so the scope in which the optimal "command to execute" is called is undefined.

解决方案

There's no official documentation about this particular inner workings of CMake, so please find below a summary of what I've learned about CMake so far ...

What files are parsed depends on the

  1. The host and target operating system
  2. The target compiler
  3. Your host computer's environment (variables, registry, installed software)
  4. Your project's CMake script files, which could include

    1. Your toolchain file
    2. Your selected programming languages
    3. Any external projects/libraries/files/scripts

There are a lot of possible combinations of those parameters, but most of the time CMake does all the magic of automatically detecting the correct settings for you and you don't need to bother how it's done. The good news is - when you need to know - it follows certain intrinsic patterns.

Interesting is that it only marginally depends on the CMake generator you are selecting.

Initial Step: Compiler Detection and Verification

This mainly starts with the project() command. Taking CXX language as an example, the main files for compiler detection are (see also the root files in the question's trace output):

  • share/cmake-x.y/Modules/CMakeDetermineCXXCompiler.cmake

    This basically tries to determine the compiler executable's location and does call it to get a more specific compiler id.

    Furthermore it e.g. defines source/output file extensions based on the host computer environment and target operating system.

  • share/cmake-x.y/Modules/CMakeCXXCompiler.cmake.in

    This is the template to store the result of the compiler detection in ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/x.y.z/CMakeCXXCompiler.cmake.

    Mainly those variables are: CMAKE_CXX_COMPILER, CMAKE_CXX_SOURCE_FILE_EXTENSIONS, CMAKE_CXX_IGNORE_EXTENSIONS and CMAKE_CXX_COMPILER_ENV_VAR

  • share/cmake-x.y/Modules/CMakeCXXInformation.cmake

    This file sets the basic flags for the compiler. It's also where the compiler, host and target does have the most influence on the setup with calls like this:

    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-x.y/Modules/CMakeTestCXXCompiler.cmake

    This does test everything and e.g. determine compiler features by actually calling the compiler in a simple generated CMake projects.

The results of those steps are stored in cached variables and those files are special in such case the they are safeguarded by variables like CMAKE_CXX_COMPILER_LOADED, CMAKE_CXX_INFORMATION_LOADED or CMAKE_CXX_COMPILER_WORKS to not run with each consecutive CMake configuration step again.

Project Configuration Files: Modify the Defaults

There are several ways you could change a CMake default values without actually having to touch your project's CMakeLists.txt files.

  • -C <initial-cache> command line option

    This can be used if you want to give some preset values (you would normally give via -D ... option) trough several projects over and over again. Like some library search paths on your computer or some presets used in your company.

  • CMakeCache.txt through e.g. cmake-gui

    cmake-gui lets you manually modify your project's options (editing all non-internal variables in CMakeCache.txt) before you finally generate the build environment.

  • CMAKE_TOOLCHAIN_FILE

    Mainly used for cross-compiling, but it can more generally describes as preset values per compiler toolchain used.

  • PreLoad.cmake

    More or less the same as the "initial cache" option (see above), but it's not given through a command line option. It has just to be in the same directory as your project's CMakeLists.txt.

    Note: It supports all CMake script commands like if() calls, but PreLoad.cmake has its

    • own variable scope (everything non-cached here is not visible in your main CMakeLists.txt)
    • limitations what is already known (it runs before everything else, so mostly you can check against CMAKE_GENERATOR)
  • CMAKE_USER_MAKE_RULES_OVERRIDE, CMAKE_USER_MAKE_RULES_OVERRIDE_<LANG>

    This allows to modify non-cached default values after the automatic detection by CMake.

    Example: Extending the valid CXX source file extensions by .c files

    MakeRulesOverwrite.cmake

    list(APPEND CMAKE_CXX_SOURCE_FILE_EXTENSIONS c)
    

    Then you can call cmake with something like

    > cmake -D CMAKE_USER_MAKE_RULES_OVERRIDE:PATH=..MakeRulesOverwrite.cmake ..
    

  • CMAKE_PROJECT_ParserTest_INCLUDE

    This is meant to "inject custom code into project builds without modifying their source" directly after your project() command was processed (and the build environment was detected).

Toolchain.cmake: Parsed Multiple Times

A toolchain file is read multiple time while determining the system, compiler, etc.

Important to know is:

  • It's read with each try_compile() call. And since try compile must produce a valid executable, you may need - if you are e.g. cross-compiling - to

  • If you change your toolchain file, CMake will re-trigger the compiler detection (as in the trace above). Which profoundly helps to play with your compiler settings.

CMake Re-Configurations: Everything comes from the Cache

Last but not least, it's important to know that the trace above only shows the initial step. All consecutive project configurations will take almost everything from cached variables and therefore will read much less files in the re-configuration runs.

References

这篇关于CMake:文件解析的顺序(缓存、工具链等)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆