Изменить значение по умолчанию CMAKE_CXX_FLAGS_DEBUG и друзей в CMake
Я хотел бы изменить значения по умолчанию для CMAKE_CXX_FLAGS_RELEASE
или же CMAKE_CXX_FLAGS_DEBUG
в CMake. По сути, у меня есть некоторые значения по умолчанию для проекта, которые немного отличаются от CMake (например, для выпуска), и мне не нужно спрашивать себя: "О, их -O3 или наш -O2 имеют преимущество при добавлении с add_compile_options".
Теперь я знаю, как установить эти значения, но я не знаю, как сделать их редактируемыми пользователем двумя обычными способами: используя -DCMAKE_CXX_FLAGS_DEBUG=yourflags
в командной строке или путем настройки его с помощью ccmake или CMakeSetup.
Проблема в том, что CMAKE устанавливает и кэширует свои собственные значения по умолчанию для них, и если вы попытаетесь перезаписать переменные без использования FORCE, "значения по умолчанию" никогда не изменятся. Если я использую FORCE в моей команде set: set(CMAKE_CXX_FLAGS_DEBUG blah CACHE STRING "" FORCE)
, он будет перезаписывать его каждый раз при запуске скрипта, исключая возможность для пользователя изменить его, если он пожелает.
Мне удалось взломать его для работы с CCMAKE, выполнив следующее, но это по-прежнему не работает с cmake -DCMAKE_CXX_FLAGS_DEBUG
поскольку он перезаписывает изменение пользователя ПОСЛЕ того, как он это сделал:
set(DEFAULTS_SET FALSE CACHE BOOL "")
set(CMAKE_CXX_FLAGS_DEBUG "-this -that" CACHE STRING "" FORCE)
set(DEFAULTS_SET TRUE CACHE BOOL "" FORCE)
Очевидно, что это неприятный хак и не работает полностью (в случае cmake -Dwhwhat =thisorthat). Я мог бы добавить и другие типы сборки, но я не понимаю, почему это необходимо, чтобы просто изменить несколько простых вещей.
Изменить 1 марта 2015 г.:
Я создал решение, которое работает, хотя я все еще не в восторге от того, что я должен сделать. Я видел другие комментарии, которые решают проблему установки CMAKE_CXX_FLAGS_DEBUG
и друзья, не имея их, получают удар, но это первоначально не работало для меня, потому что я пытался также выбрать их на основе используемого компилятора. Однако компилятор не определен, пока он не заполнит переменные для меня. Хитрость, которую я использовал, заключается в следующем. Вы должны установить переменные флагов на что-то особенное перед командой проекта.
set(CMAKE_CXX_FLAGS_DEBUG "_UNSET" CACHE STRING "")
project(your_project C CXX)
if(${CMAKE_CXX_FLAGS_DEBUG} STREQUAL "_UNSET")
# Do some compiler switching here and then set your flags with FORCE.
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3 -O0" CACHE STRING "" FORCE)
endif()
Теперь это позволяет мне выбирать значения по умолчанию, которые полностью переопределяются через командную строку с -D или в cmake-gui.
2 ответа
Я просто хотел добавить четыре варианта, которые я вижу:
Наличие ваших собственных файлов инструментов, содержащих пресеты для каждого поддерживаемого вами компилятора, например:
GNUToolchain.cmake
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3 -O0" CACHE STRING "")
А затем использовать его с
cmake -DCMAKE_TOOLCHAIN_FILE:string=GNUToolchain.cmake ...
Вы можете попытаться определить компилятор, проверив
CMAKE_GENERATOR
(который действителен доproject()
команды):CMakeLists.txt
if("${CMAKE_GENERATOR}" MATCHES "Makefiles" OR ("${CMAKE_GENERATOR}" MATCHES "Ninja" AND NOT WIN32)) set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3 -O0" CACHE STRING "") endif() project(your_project C CXX)
Ты можешь использовать
CMAKE_USER_MAKE_RULES_OVERRIDE
дать сценарий со своим собственным..._INIT
ценности:Он загружается после загрузки встроенного компилятора CMake и информационных модулей платформы, но до использования информации. Файл может установить переменные информации о платформе, чтобы переопределить значения по умолчанию CMake.
MyInitFlags.cmake
# Overwrite the init values choosen by CMake if (CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS_DEBUG_INIT "-ggdb3 -O0") endif()
CMakeLists.txt
set(CMAKE_USER_MAKE_RULES_OVERRIDE "MyInitFlags.cmake") project(your_project C CXX)
Вы можете упростить свое решение с 1 марта, проверив
..._INIT
варианты переменных флага компилятора:CMakeLists.txt
project(your_project C CXX) if (DEFINED CMAKE_CXX_FLAGS_DEBUG_INIT AND "${CMAKE_CXX_FLAGS_DEBUG_INIT}" STREQUAL "${CMAKE_CXX_FLAGS_DEBUG}") # Overwrite the init values choosen by CMake if (CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS_DEBUG "-ggdb3 -O0" CACHE STRING "" FORCE) endif() endif()
Комментарии:
Я предпочитаю и использую вариант toolchain. Но я признаю, что у него есть недостаток, заключающийся в том, что файл инструментария нужно давать вручную (если вы не звоните cmake
через скрипт / пакетный файл).
Рекомендации:
Ответ Флориана с использованием файлов набора инструментов хорошо подходит для более ранних версий CMake. Но в CMake 3.19 добавлена функция, называемая пресетами , которая помогает управлять общими наборами переменных кэша для вашего проекта. По сути, вы создаете как минимум один из двух файлов,
CMakePresets.json
а также
CMakeUserPresets.json
(обычно добавляют к
.gitignore
или аналогичные), которые содержат спецификации того, как настроить проект.
Например, вы можете написать:
{
"version": 1,
"cmakeMinimumRequired": {
"major": 3,
"minor": 19,
"patch": 0
},
"configurePresets": [
{
"name": "default",
"displayName": "Default",
"description": "Build using Ninja and a GCC-like compiler",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_CXX_FLAGS_DEBUG": "-ggdb3 -O0"
}
},
{
"name": "default-vcpkg",
"displayName": "Default (vcpkg)",
"description": "Default build with vcpkg (from VCPKG_ROOT)",
"inherits": "default",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
}
}
]
}
Затем из исходного каталога ваша командная строка CMake просто станет:
$ cmake --preset=default
Этот подход имеет несколько преимуществ:
- Это делает командную строку намного проще
- Он совместим с другими файлами набора инструментов (например, vcpkg во втором пресете).
- Он может переопределять флаги, которые обычно безоговорочно добавляются в
*_INIT
флаги. - Вам не нужно писать неуклюжую логику в вашем CMakeLists.txt.
- Предустановки доступны для пользователя, что важно, если вы распространяете библиотеку.
В дополнение к пунктам 4 и 5: добавление флагов — плохая идея, если только они не должны быть абсолютно необходимы для правильной компиляции, и нет встроенной функции для достижения этих флагов (например.
CMAKE_CXX_STANDARD
). Если кто-то попытается скомпилировать вашу библиотеку с помощью другого компилятора (или даже другой версии того же компилятора), он может столкнуться с проблемами, если, например, вы добавите слишком новый или неподдерживаемый флаг предупреждения. Вы можете обойти это с помощью выражений генератора и/или сложной логики (например,
_UNDEF
трюк выше), но, как правило, проще и удобнее использовать набор инструментов или эти новые пресеты.
Например, чтобы правильно добавить
-Wsuggest-override
, вам нужно будет написать:
target_compile_options(lib PRIVATE $<$<AND:$<VERSION_GREATER_EQUAL:$<CXX_COMPILER_VERSION>,5.1>,$<COMPILE_LANG_AND_ID:CXX,GNU>>:-Wsuggest-override>)
# ... or ...
# Note: only correct if using "PRIVATE". Must use a genex for INTERFACE/PUBLIC because the whole genex gets exported, whereas this flag will get exported verbatim.
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 5.1)
target_compile_options(lib PRIVATE -Wsuggest-override)
endif ()
Или вы можете просто поместить флаг в цепочку инструментов/пресет, где вы уже знаете, какой компилятор вы используете.