CMake: в каком порядке обрабатываются файлы (Cache, Toolchain,...)?

Это кажется тривиальным вопросом, поскольку CMake - это script язык, общий ответ: строго последовательный. Но я столкнулся с несколькими случаями, когда было важно, когда или в каком порядке CMake анализирует определенные файлы. Поэтому мне интересно:

  • Имеется ли доступная документация, описывающая порядок, в котором файлы (включая внутренние файлы CMake) анализируются?
  • Является ли порядок файлов в зависимости от версии CMake или некоторых параметров/настроек/окружения CMake, включая. выбранный генератор или хост окружающая среда?

Случаи, к которым я дошел до сих пор, где важна информация выше:

Возможно, вы знаете еще больше.

Чтобы найти ответ, я попробовал следующее: у меня есть простой основной CMakeList.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

Итак, увидев вышеприведенный вывод, я пришел - до сих пор - к следующему выводу (который, я надеюсь, правдивый и несколько общий):

  • Файл CMakeCache.txt читается только один раз, когда настройка запускается и записывается после завершения Поколения. Он просто сохраняет состояние кэша "глобальных переменных".
  • Команда project() запускает большую часть магии обнаружения CMake (включая чтение из файла Toolchain.txt).
  • Файл toolchain считывается дважды. Однажды до того, как система make/компиляции обнаружена и один раз внутри созданного тогда CMakeSystem.cmake.
  • Крючок variable_watch() может запускаться в любое время, поэтому область, в которой вызывается "команда для выполнения", называется undefined.

Ответ 1

Нет официальной документации об этой конкретной внутренней работе CMake, поэтому, пожалуйста, найдите ниже резюме того, что я узнал о CMake до сих пор...

Какие файлы обрабатываются, зависит от

  • Хост и целевая операционная система
  • Целевой компилятор
  • Среда вашего компьютера (переменные, реестр, установленное программное обеспечение)
  • Ваш проект CMake script файлы, которые могут включать
    • Ваш файл toolchain
    • Выбранные языки программирования
    • Любые внешние проекты/библиотеки/файлы/скрипты

Существует много возможных комбинаций этих параметров, но большую часть времени CMake делает все возможное для автоматического определения правильных настроек для вас, и вам не нужно беспокоиться о том, как это делается. Хорошая новость - когда вам нужно знать - это следует за некоторыми внутренними узорами.

Интересно, что он лишь незначительно зависит от генератора CMake, который вы выбираете.

Начальный шаг: обнаружение и проверка компилятора

В основном это начинается с команды project(). В качестве примера, например, для языка CXX, основными файлами для обнаружения компилятора (см. Также корневые файлы в выходном сигнале вопроса):

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

    Это в основном пытается определить исполняемое место компилятора и вызывает его, чтобы получить более конкретный идентификатор компилятора.

    Кроме того, это, например, определяет расширения исходного/выходного файла на основе среды хост-компьютера и целевой операционной системы.

  • 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_EXTENSIONS и CMAKE_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_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

    В основном используется для cross-compiling, но он может более широко описываться как заданные значения для используемой инструментальной комбинации компилятора.

  • PreLoad.cmake

    Более или менее то же, что и опция "начального кеша" (см. выше), но она не предоставляется через параметр командной строки. Он должен быть только в том же каталоге, что и ваш проект CMakeLists.txt.

    Примечание. Он поддерживает все команды CMake script, такие как if(), но PreLoad.cmake имеет

    • собственный диапазон переменных (все, не кэшированные здесь, не отображаются в вашем основном CMakeLists.txt)
    • ограничения, которые уже известны (он работает до всего остального, поэтому в основном вы можете проверить CMAKE_GENERATOR)
  • CMAKE_USER_MAKE_RULES_OVERRIDE, CMAKE_USER_MAKE_RULES_OVERRIDE_<LANG>

    Это позволяет изменять неизменяемые значения по умолчанию после автоматического обнаружения с помощью CMake.

    Пример: Расширение допустимых расширений исходного файла CXX с помощью .c файлов

    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: разобрано несколько раз

A файл toolchain читается несколько раз при определении системы, компилятора и т.д.

Важно знать:

  • Он читается с каждым вызовом try_compile(). И так как try compile должен создать действительный исполняемый файл, вам может понадобиться - если вы, например, кросс-компиляция - до

    • CMAKE_TRY_COMPILE_TARGET_TYPE до STATIC_LIBRARY (версия CMake версии 3.6 или выше)
    • Отметьте IN_TRY_COMPILE глобальное свойство, чтобы добавить дополнительные параметры
  • Если вы измените файл инструментальной привязки, CMake будет повторно запускать обнаружение компилятора (как в предыдущей строке). Что глубоко помогает играть со своими настройками компилятора.

Реадаптации CMake: все происходит из кэша

И последнее, но не менее важное: важно знать, что вышеприведенный след показывает только начальный шаг. Все последовательные конфигурации проектов будут занимать почти все, начиная с кэшированных переменных и, следовательно, будут считывать гораздо меньше файлов в ходе повторной настройки.

Ссылки