Как установить уровень предупреждений в CMake?

116

Как установить уровень предупреждения для проекта (а не всего решения) с помощью CMake ? Должен работать в Visual Studio и GCC .

Я нашел различные варианты, но большинство из них либо не работают, либо не соответствуют документации.

Wernight
источник

Ответы:

96

ОБНОВЛЕНИЕ: этот ответ предшествует эпохе Modern CMake. Каждый здравомыслящий пользователь CMake должен воздерживаться от CMAKE_CXX_FLAGSнепосредственных действий и target_compile_optionsвместо этого вызывать команду. Проверьте ответ MRTS, в котором представлены рекомендуемые лучшие практики.

Вы можете сделать что-то подобное:

if(MSVC)
  # Force to always compile with W4
  if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
    string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
  else()
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
  endif()
elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
  # Update if necessary
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic")
endif()
mloskot
источник
Обратите внимание, что новые версии Visual Studio (по крайней мере, 2013) поддерживают /Wallфлаг (с именем EnableAllWarnings). Он выдает даже больше предупреждений, чем /W4. Однако, по моему опыту, он дает слишком много предупреждений.
Адам Бадура,
12
/Wallможно использовать, если вы хотите использовать «вычитающую» стратегию предупреждений, как и clang -Weverything. Вместо того, чтобы выбирать предупреждения для включения, вы включаете все, а затем выбираете определенные предупреждения, которые нужно отключить.
bames53 07
86

В современном CMake хорошо работает следующее:

if(MSVC)
  target_compile_options(${TARGET_NAME} PRIVATE /W4 /WX)
else()
  target_compile_options(${TARGET_NAME} PRIVATE -Wall -Wextra -pedantic -Werror)
endif()

Мой коллега предложил альтернативный вариант:

target_compile_options(${TARGET_NAME} PRIVATE
  $<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
  $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -pedantic -Werror>
)

Замените ${TARGET_NAME}фактическим именем цели.-Werrorне является обязательным, он превращает все предупреждения в ошибки.

Или используйте add_compile_options(...) если хотите применить его ко всем целям, как предлагает @aldo в комментариях.

Кроме того, убедитесь, что понимаете разницу между PRIVATEи PUBLIC(общедоступные параметры будут унаследованы целями, которые зависят от данной цели).

MRTS
источник
19
Или просто, add_compile_options(...)если вы хотите применить его ко всем целям.
aldo
1
FYI modern CMake не требует повторения условия в else()или endif().
Timmmm
1
@Timmmm Спасибо за внимание! Это просто примечание или вы бы предпочли, чтобы я удалил условия?
мрт
1
@helmesjo Нет, Тимммм имел в виду код CMake в том виде, в каком он существовал до редактирования 9 апреля. Вы можете взглянуть на историю редактирования, чтобы увидеть биты, которые были удалены, - это то же самое, что указывал Timmmm.
FeRD
2
@aldo проблема add_compile_options()в том, что предупреждения будут распространяться на цели, добавленные через add_subdirectory(). Если вы включите внешние библиотеки таким образом, вы можете получить множество предупреждений, если эта библиотека была разработана с другим уровнем предупреждений.
trozen
24

Некоторые модули CMake, которые я написал, включают экспериментальное подавление предупреждений между платформами :

sugar_generate_warning_flags(
    target_compile_options
    target_properties
    ENABLE conversion
    TREAT_AS_ERRORS ALL
)

set_target_properties(
    foo
    PROPERTIES
    ${target_properties}
    COMPILE_OPTIONS
    "${target_compile_options}"
)

Результат для Xcode:

  • Установите CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSIONатрибут Xcode (он же настройки сборки -> предупреждения -> подозрительные неявные преобразования -> ДА )
  • Добавить флаг компилятора: -Werror

Makefile gcc и clang:

  • Добавить компилятор флаги: -Wconversion,-Werror

Визуальная студия:

  • Добавить компилятор флаги: /WX,/w14244

связи

xaxxon
источник
1
жаль, что cmake не предоставляет эту функциональность
Слава
3
Хорошие новости. Извините, что разместил его здесь, а не в списке рассылки cmake, но без уровня это будет бесполезно. Слишком много предупреждений, чтобы перечислить их все явно. Если вы хотите унифицировать его, один из способов сделать это - два отдельных cmake_level - унифицированный набор предупреждений, основанный, например, на clang, и native_level со значением, специфичным для компилятора. Один из них, вероятно, можно сократить до уровня. Извините, если я действительно не следил за разговором и что-то не так
Слава
1
@ void.pointer поднимает действительную точку. Предлагаемый вами ответ гласит: « Я планирую добавить эту функцию» . Это не говорит о том, что вы провели поверхностное исследование и теперь надеетесь, что кто-то другой сделает за вас тяжелую работу. Если вы не хотите, чтобы вас связывали с реализацией (и вопросами о ее ходе), вам необходимо отредактировать свой ответ и отмежеваться от задачи, в которой вы не добились прогресса более года.
Inspectable 06
«Спустя год все еще нет прогресса». - Теперь, когда есть действительная точка. Более года прошло с нулевым прогрессом. Это очень сильный признак заброшенного проекта. Если вы хотите доказать, что мы неправы, покажите нам прогресс. Этого не произошло, но ваш предложенный ответ все еще предполагает, что эта функция вот-вот будет добавлена ​​в CMake. Зачем так волноваться из-за функции, которая не будет доступна через годы? Это совершенно бесполезно. Либо покажите прогресс, либо отредактируйте свой ответ, чтобы он не вводил в заблуждение.
Inspectable 07
5
Кажется, вы не понимаете. Если вы предполагаете, что собираетесь реализовать функцию, то вам необходимо реализовать ее в свое время. В противном случае вас попросят удалить это обещание из предложенного вами ответа. Вы не продемонстрировали никаких обязательств по внедрению указанной функции, поэтому не утверждайте обратное. Я понимаю, что он большой. Я также понимаю, что вы, возможно, не справитесь с этим. Я просто прошу вас, чтобы ваш ответ отражал это.
Inspectable 07
6

Вот лучшее решение, которое я нашел до сих пор (включая проверку компилятора):

if(CMAKE_BUILD_TOOL MATCHES "(msdev|devenv|nmake)")
    add_definitions(/W2)
endif()

Это установит уровень предупреждения 2 в Visual Studio. Я полагаю, что с a -W2это будет работать и в GCC (непроверено).

Обновление от @Williams: должно быть -Wall для GCC.

Wernight
источник
6
Флаг предупреждения для GCC будет -Wallи, возможно, -Wextraподробно описан на gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Milliams,
1
Список, который я использую, есть -W -Wall -Wextra -pedantic. -WextraIIRC заменен -Wв более поздней версии GCC, но я оставлю оба варианта для обеспечения совместимости.
Jimmio92
2
Это не предназначение add_definitions ( «он предназначен для добавления определений препроцессора» ). Это не просто рекомендация по передовому опыту. Аргументы, переданные этой команде, будут отображаться в сгенерированных сценариях сборки, вызывающих инструменты, которые их не ожидают (например, компилятор ресурсов).
IInspectable
Это не «проверка компилятора», это проверка инструмента сборки.
Thomas
3

В соответствии с CMake 3.17.1 документации :

if (MSVC)
    # warning level 4 and all warnings as errors
    add_compile_options(/W4 /WX)
else()
    # lots of warnings and all warnings as errors
    add_compile_options(-Wall -Wextra -pedantic -Werror)
endif()

GCC и Clang используют эти флаги, поэтому они должны охватывать все 3.

сойка
источник
Не используйте это. Вместо этого используйте target_compile_options (). Ссылка на последний документ кажется «правильной», но это древняя запись просто для обратной совместимости.
Каоанан
1
@caoanan В документации для этого ничего не упоминается об обратной совместимости. add_compile_optionsраспространяется на весь каталог, тогда target_compile_optionsкак только для одной цели.
TehWan
2
if(MSVC)
    string(REGEX REPLACE "/W[1-3]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif()

Если вы используете target_compile_options- cmake попытается использовать двойной /W*флаг, который выдаст предупреждение компилятору.

TarmoPikaro
источник
Спасибо за это. Я наивно использовал add_compile_optionsединственный, чтобы получить массу предупреждений, /W3которые меняют /W4. Тот факт, что CMake не обращается к этому элементарному параметру (установка уровня предупреждения), невероятен.
Воскресение