CMake:解析文件的顺序(缓存,工具链等)?

时间:2015-05-28 10:15:44

标签: cmake

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

  1. 是否有可用的文档描述其中的顺序 解析文件(包括内部CMake文件)?
  2. 文件顺序是否取决于CMake版本或某些CMake选项/设置/环境incl。选择的发电机或主机 环境?
  3. 到目前为止我遇到的案例,上述信息很重要:

    也许你知道更多。

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

    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
    

    所以看到上面的输出,到目前为止,我得到了以下结论(我希望这是真的,有些通用):

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

1 个答案:

答案 0 :(得分:17)

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

解析的文件取决于

  1. 主机和目标操作系统
  2. 目标编译器
  3. 您的主机环境(变量,注册表,已安装的软件)
  4. 您项目的CMake脚本文件,其中包括
    1. 您的工具链文件
    2. 您选择的编程语言
    3. 任何外部项目/图书馆/文件/脚本
  5. 这些参数有很多种可能的组合,但大多数时候,CMake会为您自动检测正确的设置,并且您不需要打扰它是如何完成的。好消息是 - 当你需要知道时 - 它遵循某些内在模式。

    有趣的是,它只是略微取决于您选择的CMake generator

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

    这主要从project()命令开始。以CXX语言为例,编译器检测的主要文件是(参见问题跟踪输出中的根文件):

    • <强> 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_VAR

    • <强> share/cmake-x.y/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-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

      主要用于cross-compiling,但它通常可以描述为每个编译器工具链使用的预设值。

    • <强> PreLoad.cmake

      与&#34;初始缓存大致相同&#34;选项(见上文),但它不是通过命令行选项提供的。它只需与您的项目CMakeLists.txt位于同一目录中。

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

      • 自己的变量范围(此处未缓存的所有内容在主CMakeLists.txt中都不可见)
      • 限制已知的内容(它先于其他所有内容运行,因此大多数情况下您可以查看CMAKE_GENERATOR
    • CMAKE_USER_MAKE_RULES_OVERRIDECMAKE_USER_MAKE_RULES_OVERRIDE_<LANG>

      这允许在CMake自动检测后修改非缓存的默认值。

      Example:按.c个文件扩展有效的CXX源文件扩展名

      <强> MakeRulesOverwrite.cmake

      list(APPEND CMAKE_CXX_SOURCE_FILE_EXTENSIONS c)
      

      然后你可以用{/ p>之类的东西来呼叫cmake

      > cmake -D CMAKE_USER_MAKE_RULES_OVERRIDE:PATH=..\MakeRulesOverwrite.cmake ..
      
    • <强> CMAKE_PROJECT_ParserTest_INCLUDE

      这意味着&#34;将自定义代码注入到项目构建中,而无需修改其源代码&#34;在处理project()命令之后直接执行(并检测到构建环境)。

    Toolchain.cmake:多次解析

    在确定系统,编译器等时多次读取toolchain file

    重要的是要知道:

    • 每次try_compile()电话都会阅读。因为try compile必须生成一个有效的可执行文件,所以你可能需要 - 如果你是交叉编译 - 到

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

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

    最后但并非最不重要的一点是,知道上面的跟踪只显示了初始步骤,这一点非常重要。所有连续项目配置几乎都包含缓存变量,因此在重新配置运行中将读取更少的文件。

    参考