CMake: в каком порядке обрабатываются файлы (кеш, toolchain и т. Д.)?
Это кажется тривиальным вопросом, поскольку CMake – это язык сценария, общий ответ: строго последовательный. Но я столкнулся с несколькими случаями, когда было важно, когда или в каком порядке CMake анализирует определенные файлы. Поэтому мне интересно:
- Есть ли доступная документация, описывающая порядок обработки файлов (включая внутренние файлы CMake)?
- Является ли порядок файлов в зависимости от версии CMake или некоторых параметров / настроек / окружения CMake, включая. выбранного генератора или среды хоста?
Случаи, к которым я дошел до сих пор, где важна информация:
- Файл toolchain анализируется до того, как компилятор будет идентифицирован, поэтому вам необходимо заполнить некоторые переменные CMake в кеше сначала / в файле инструментальной привязки: кросс-компиляция CMake с конкретным компоновщиком не передает аргументы в armlink
- Файл toolchain анализируется несколько раз, поэтому, например, печать сообщений из файла инструментальной привязки выполняется несколько раз: инструментальная цепочка CMake включает в себя несколько файлов
- Переменные часы можно вызывать из области вне вашего основного файла
CMakeLists.txt
Был проанализирован: выполнить команду или макрос в CMake в качестве последнего шага перед тем, как завершится шаг «configure»
Возможно, вы знаете еще больше.
- Как начать работу с GTest и CMake
- Как указать CMake использовать компилятор архитектуры сборки
- cmake add_custom_command
- Ошибка связи LNK2019 в MSVC, неразрешенные символы с префиксом __imp__, но должны быть из статического lib
- Cmake не может найти библиотеку, используя "link_directories"
Чтобы найти ответ, я попробовал следующее: у меня есть простой основной 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_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()
может запускаться в любое время, поэтому область, в которой вызывается оптимальная команда «выполнить», не определена.
- Передача параметров компилятора cmake
- Как добавить флаг -l "(ell) компилятора в CMake
- Emacs 24: Загрузка пакета, установленного через ELPA
- Создание библиотеки CMake, доступной для других пакетов CMake автоматически
- Общее правило из makefile в CMake
- Как установить фильтры Visual Studio для вложенной подкаталога с помощью cmake
- Скажите CMake, чтобы использовать компилятор C ++ для файлов C, поступающих из CMake?
- CMAKE_BUILD_TYPE не используется в CMakeLists.txt
Нет официальной документации об этой конкретной внутренней работе CMake, поэтому, пожалуйста, найдите ниже резюме того, что я узнал о CMake до сих пор …
Какие файлы анализируются, зависит от
- Хост и целевая операционная система
- Целевой компилятор
- Окружающая среда вашего компьютера (переменные, реестр, установленное программное обеспечение)
- Файлы сценария CMake вашего проекта, которые могут включать
- Ваш файл toolchain
- Ваши выбранные языки программирования
- Любые внешние проекты / библиотеки / файлы / скрипты
Существует множество возможных комбинаций этих параметров, но большую часть времени CMake делает все возможное, чтобы автоматически определять правильные настройки для вас, и вам не нужно беспокоиться о том, как это делается. Хорошая новость – когда вам нужно знать – это следует за некоторыми внутренними узорами.
Интересно, что он лишь незначительно зависит от выбранного вами генератора CMake .
Начальный шаг: обнаружение и проверка компилятора
Это главным образом начинается с команды project()
. В качестве примера, используя язык CXX
, основные файлы для обнаружения компилятора (см. Также корневые файлы в выводе трассировки вопроса):
-
share/cmake-xy/Modules/CMakeDetermineCXXCompiler.cmake
Это в основном пытается определить местоположение исполняемого файла компилятора и вызывает его для получения более конкретного идентификатора компилятора.
Кроме того, он, например, определяет расширения исходного / выходного файла на основе среды хост-компьютера и целевой операционной системы.
-
share/cmake-xy/Modules/CMakeCXXCompiler.cmake.in
Это шаблон для хранения результата обнаружения компилятора в
${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/xyz/CMakeCXXCompiler.cmake
.Главным образом эти переменные:
CMAKE_CXX_COMPILER
,CMAKE_CXX_SOURCE_FILE_EXTENSIONS
,CMAKE_CXX_IGNORE_EXTENSIONS
иCMAKE_CXX_COMPILER_ENV_VAR
-
share/cmake-xy/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-xy/Modules/CMakeTestCXXCompiler.cmake
Это проверяет все и, например, определяет возможности компилятора, фактически вызывая компилятор в простых сгенерированных проектах CMake.
Результаты этих шагов хранятся в кэшированных переменных, и эти файлы являются особыми в этом случае, они защищены такими переменными, как CMAKE_CXX_COMPILER_LOADED
, CMAKE_CXX_INFORMATION_LOADED
или CMAKE_CXX_COMPILER_WORKS
чтобы не запускаться с каждым последующим шагом конфигурации CMake еще раз.
Файлы конфигурации проекта: изменение настроек по умолчанию
Существует несколько способов изменить значения по умолчанию CMake, не CMakeLists.txt
файлам CMakeLists.txt
вашего проекта.
-
-C
вариант командной строкиЭто можно использовать, если вы хотите дать некоторые предустановленные значения (вы обычно передавали бы через
-D ...
) через несколько проектов снова и снова. Как некоторые пути поиска библиотеки на вашем компьютере или некоторые пресеты, используемые в вашей компании. -
CMakeCache.txt
например,cmake-gui
cmake-gui
позволяет вручную изменять параметры вашего проекта (редактирование всех не внутренних переменных вCMakeCache.txt
), прежде чем вы, наконец,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_
Это позволяет изменять неизменяемые значения по умолчанию после автоматического обнаружения CMake.
Пример . Расширение допустимых расширений исходного файла
.c
файлов.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: разобрано несколько раз
Файл toolchain считывается несколько раз при определении системы, компилятора и т. Д.
Важно знать:
-
Он считывается с каждым
try_compile()
. И так как try compile должен создать допустимый исполняемый файл, вам может понадобиться – если вы, например, перекрестно-компилируете – на-
CMAKE_TRY_COMPILE_TARGET_TYPE
вSTATIC_LIBRARY
(версия CMake версии 3.6 или выше) - Проверьте глобальное свойство
IN_TRY_COMPILE
чтобы добавить дополнительные параметры
-
-
Если вы измените файл инструментальной привязки, CMake снова запустит обнаружение компилятора (как в предыдущей строке). Что глубоко помогает играть со своими настройками компилятора.
Реадаптация CMake: все происходит из кэша
И последнее, но не менее важное: важно знать, что вышеприведенный след показывает только начальный шаг. Все последовательные конфигурации проектов будут занимать почти все, начиная с кэшированных переменных и, следовательно, будут читать гораздо меньше файлов в ходе повторной настройки конфигурации.
Рекомендации
- Архитектура приложений с открытым исходным кодом: CMake
- Общее правило от makefile до cmake
- Ошибка CMake в CMakeLists.txt: 30 (проект): не найдено CMAKE_C_COMPILER