CMake: в каком порядке анализируются файлы (кеш, цепочка инструментов и т. Д.)?

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

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

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

Может быть, вы знаете, даже больше.

Чтобы найти ответ, я попробовал следующее: я установил простой основной 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. variable_watch() Хук может срабатывать в любое время, поэтому область, в которой вызывается оптимальная "команда для выполнения", не определена.

1 ответ

Решение

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

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

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

Существует множество возможных комбинаций этих параметров, но в большинстве случаев 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

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

  • PreLoad.cmake

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

    Примечание: он поддерживает все команды сценария CMake, такие как 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: анализируется несколько раз

Файл цепочки инструментов читается несколько раз при определении системы, компилятора и т. Д.

Важно знать это:

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

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

Переконфигурации CMake: все приходит из кеша

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

Рекомендации

Другие вопросы по тегам