CMake: в каком порядке анализируются файлы (кеш, цепочка инструментов и т. Д.)?
Это кажется тривиальным вопросом, поскольку CMake является языком сценариев, общий ответ: строго последовательный. Но я сталкивался с несколькими случаями, когда было важно, когда или в каком порядке CMake анализирует определенные файлы. Так что мне интересно
- Имеется ли документация, описывающая порядок, в котором файлы (включая внутренние файлы CMake) анализируются?
- Порядок файлов зависит от версии CMake или некоторых параметров / настроек / среды CMake, вкл. выбранный генератор или среда хоста?
Случаи, с которыми я сталкивался до сих пор, где вышеупомянутая информация была важна:
- Файл цепочки инструментов анализируется до идентификации компилятора, поэтому вы должны сначала заполнить определенные переменные CMake в кеше / в файле цепочки инструментов: кросс-компиляция CMake с определенным компоновщиком не передает аргументы в armlink
- Файл набора инструментов анализируется несколько раз, поэтому, например, печать сообщений из файла набора инструментов отображается несколько раз: набор инструментов CMake включает в себя несколько файлов
- Переменные часы можно вызывать из области за пределами вашей основной
CMakeLists.txt
файл был проанализирован: выполнить команду или макрос в CMake как последний шаг перед завершением шага 'configure'
Может быть, вы знаете, даже больше.
Чтобы найти ответ, я попробовал следующее: я установил простой основной 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
Таким образом, увидев вышеприведенный вывод, я дошел до следующего заключения (которое, я надеюсь, является правдивым и несколько общим):
- Файл CMakeCache.txt читается только один раз, когда конфигурация запускается, и записывается после завершения генерации. Он просто сохраняет состояние кеша "глобальных переменных".
project()
Команда запускает большую часть магии обнаружения CMake (включая чтение изToolchain.txt
файл).- Файл цепочки инструментов читается дважды. Один раз до обнаружения системы make/compile и один раз внутри затем сгенерированного
CMakeSystem.cmake
, variable_watch()
Хук может срабатывать в любое время, поэтому область, в которой вызывается оптимальная "команда для выполнения", не определена.
1 ответ
Нет официальной документации об этой конкретной внутренней работе CMake, поэтому, пожалуйста, найдите ниже краткое изложение того, что я узнал о CMake до сих пор...
Какие файлы анализируются, зависит от
- Хост и целевая операционная система
- Целевой компилятор
- Среда вашего главного компьютера (переменные, реестр, установленное программное обеспечение)
- Файлы сценариев CMake вашего проекта, которые могут включать
- Ваш набор инструментов
- Ваши выбранные языки программирования
- Любые внешние проекты / библиотеки / файлы / скрипты
Существует множество возможных комбинаций этих параметров, но в большинстве случаев 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: все приходит из кеша
И последнее, но не менее важное: важно знать, что приведенная выше трассировка показывает только начальный шаг. Все последовательные конфигурации проекта будут брать почти все из кэшированных переменных и, следовательно, будут читать намного меньше файлов в ходе переконфигурирования.