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

Flo*_*ian 25 cmake

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

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

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

也许你知道更多.

为了找到答案,我尝试了以下内容:我已经设置了一个简单的主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)
Run Code Online (Sandbox Code Playgroud)

然后,当我运行时,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
Run Code Online (Sandbox Code Playgroud)

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

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

Flo*_*ian 18

关于CMake的这种特殊内部工作原理没有官方文档,所以请在下面找到我迄今为止所学到的关于CMake的内容的摘要......

解析的文件取决于

  1. 主机和目标操作系统
  2. 目标编译器
  3. 您的主机环境(变量,注册表,已安装的软件)
  4. 您的项目的CMake脚本文件,可能包括
    1. 你的工具链文件
    2. 您选择的编程语言
    3. 任何外部项目/库/文件/脚本

这些参数有很多可能的组合,但大多数情况下,CMake会为您自动检测正确的设置,并且您不必费心去做.好消息是 - 当你需要知道时 - 它遵循某些内在模式.

有趣的是,它只是略微取决于您选择的CMake生成器.

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

这主要从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_COMPILER,CMAKE_CXX_SOURCE_FILE_EXTENSIONS,CMAKE_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)        
    
    Run Code Online (Sandbox Code Playgroud)
  • share/cmake-x.y/Modules/CMakeTestCXXCompiler.cmake

    这会测试所有内容,例如通过在简单生成的CMake项目中实际调用编译器来确定编译器功能.

这些步骤的结果存储在缓存变量中,并且这些文件在这种情况下是特殊的,它们由变量保护CMAKE_CXX_COMPILER_LOADED,CMAKE_CXX_INFORMATION_LOADED或者CMAKE_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_<LANG>

    这允许在CMake自动检测之后修改非限定的默认值.

    示例:按.c文件扩展有效的CXX源文件扩展名

    MakeRulesOverwrite.cmake

    list(APPEND CMAKE_CXX_SOURCE_FILE_EXTENSIONS c)
    
    Run Code Online (Sandbox Code Playgroud)

    然后你可以cmake用类似的东西打电话

    > cmake -D CMAKE_USER_MAKE_RULES_OVERRIDE:PATH=..\MakeRulesOverwrite.cmake ..
    
    Run Code Online (Sandbox Code Playgroud)
  • CMAKE_PROJECT_ParserTest_INCLUDE

    这是为了project()在处理命令后直接"将自定义代码注入项目构建而不修改其源代码" (并检测到构建环境).

Toolchain.cmake:多次解析

工具链文件被读出多个时间而确定系统,编译器,等

重要的是要知道:

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

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

CMake Re-Configuartions:一切都来自Cache

最后但同样重要的是,重要的是要知道上面的跟踪仅显示了最初的步骤.所有连续的项目配置几乎都包含缓存变量,因此在重新配置运行中将读取更少的文件.

参考