Як встановити рівень попередження в CMake?


116

Як встановити рівень попередження для проекту (не всього рішення) за допомогою CMake ? Слід працювати над Visual Studio та GCC .

Я знайшов різні варіанти, але більшість, здається, або не працюють, або не відповідають документації.

Відповіді:


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()

Зауважте, що нові версії Visual Studio (принаймні 2013 року) підтримують /Wallпрапор (який названий EnableAllWarnings). Це дає навіть більше попереджень, ніж /W4. Однак, з мого досвіду, це створює занадто багато попереджень.
Адам Бадура

12
/Wallє корисним, якщо ви хочете дотримуватися "віднімаючої" стратегії для попереджень, як і кланг -Weverything. Замість того, щоб вибирати попередження для ввімкнення, ви вмикаєте все, а потім вибираєте конкретні попередження для відключення.
bames53

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(публічні параметри будуть успадковані цілями, які залежать від заданої цілі).


19
Або просто, add_compile_options(...)якщо ви хочете застосувати його до всіх цілей.
альдо

1
FYI-сучасний CMake не вимагає повторення умови в else()або endif().
Timmmm

1
@Timmmm Дякую за голову! Це просто записка чи ви віддаєте перевагу мені зняти умови?
мрц

1
@helmesjo Ні, Timmmm посилався на код CMake, як він існував до редагування 9 квітня. Ви можете переглянути історію редагування, щоб побачити вилучені біти, які є тим самим, що вказував Timmmm.
FeRD

2
@aldo проблема add_compile_options()полягає в тому, що попередження поширюватимуться на цілі, додані через add_subdirectory(). Якщо ви включаєте зовнішні бібліотеки таким чином, ви можете отримати багато попереджень, якщо ця бібліотека була розроблена з різним рівнем попередження.
заморожена

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

Посилання


1
шкода cmake не надає цієї функціональності
Slava

3
Гарні новини. Вибачте, що розміщуєте його тут, а не в списку розсилки cmake, але без рівня це буде марно. Існує занадто багато попереджень, щоб перераховувати їх усі чітко. Якщо ви хочете уніфікувати його одним із способів, це зробити два окремих cmake_level - уніфікований набір попереджень, заснований, наприклад, на clang, і native_level зі значенням, характерним для компілятора. Одне з них, можливо, можна скоротити до рівня. Вибачте, якщо я насправді не стежив за розмовою і щось трапилось не так
Slava

1
@ void.pointer піднімає дійсну точку. Ваша запропонована відповідь зазначає: " Я планую додати цю функцію" . Це не говорить про те, що ви провели деякі побіжні дослідження і тепер сподіваєтесь, що хтось інший зробить важкий підйом для вас. Якщо ви не хочете, щоб його пов'язували із впровадженням (та питанням щодо його прогресу), вам потрібно відредагувати свою відповідь та відмежуватися від завдання, над яким ви не досягли жодного прогресу протягом більше року.
IIнеочікуваний

"Через рік, як і раніше, прогресу немає". - Тепер це справедливий момент. Минуло більше року, з нульовим прогресом. Це дуже сильний показник покинутого проекту. Якщо ви хочете довести нас неправильно, покажіть нам певний прогрес. Цього не сталося, але запропонована відповідь все ж говорить про те, що функція збирається додати до CMake. Навіщо робити метушні щодо функції, яка не буде доступною через роки? Це зовсім не корисно. Або покажіть певний прогрес, або редагуйте свою відповідь, щоб бути менш оманливою.
Неочікувана

5
Ви, здається, не розумієте. Якщо ви припускаєте, що ви збираєтесь реалізувати функцію, то вам потрібно її реалізувати вчасно. Якщо цього не зробити, вас попросять видалити цю обіцянку із запропонованої вами відповіді. Ви проявили нульову прихильність до реалізації зазначеної функції, тому не вимагайте іншого. Я розумію, що це великий. Я також розумію, що ви, можливо, не зможете цього зняти. Я просто прошу вас, щоб ваша відповідь відображала це.
Неочікувана

6

Ось найкраще рішення, яке я знайшов поки що (включаючи перевірку компілятора):

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

Це встановить рівень попередження 2 у Visual Studio. Я припускаю, що -W2це може працювати і в GCC (не перевірено).

Оновлення від @Williams: Це має бути -Wallдля GCC.


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 ( "призначене для додавання визначень препроцесора" ). Це не просто рекомендація з найкращих практик. Аргументи, передані цій команді, з’являться в створених скриптах побудови, що викликають інструменти, які не очікують їх (наприклад, компілятор ресурсів).
IIнеочікуваний

Це не "перевірка компілятора", це перевірка інструменту побудови.
Томас

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 (). Посилання на останній документ видається "правильним", але це давнє входження лише для зворотної сумісності.
caoanan

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*прапор, який попередить компілятор.


Дякую за це Я наївно використовував add_compile_optionsєдине, щоб отримати тонни попереджень, /W3які перекриваються /W4. Те, що CMake не звертається до цього рудиментарного варіанту (встановлення рівня попередження), є непереконливим.
Воскресіння
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.