Jak ustawić poziom ostrzeżenia w CMake?

116

Jak ustawić poziom ostrzegania dla projektu (a nie całego rozwiązania) za pomocą CMake ? Powinien działać na Visual Studio i GCC .

Znalazłem różne opcje, ale większość z nich nie działa lub nie jest zgodna z dokumentacją.

Wernight
źródło

Odpowiedzi:

96

AKTUALIZACJA: Ta odpowiedź poprzedza erę współczesnego CMake. Każdy rozsądny użytkownik CMake powinien powstrzymać się od CMAKE_CXX_FLAGSbezpośredniego manipulowania i wywołać target_compile_optionspolecenie. Sprawdź odpowiedź mrts, która przedstawia zalecane najlepsze praktyki.

Możesz zrobić coś podobnego do tego:

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
źródło
Zwróć uwagę, że /Wallflaga obsługi nowych wersji programu Visual Studio (co najmniej 2013) (o nazwie EnableAllWarnings). Generuje jeszcze więcej ostrzeżeń niż /W4. Jednak z mojego doświadczenia wynika o wiele za dużo ostrzeżeń.
Adam Badura
12
/Wallprzydaje się, jeśli chcesz stosować „subtraktywną” strategię ostrzeżeń, podobnie jak strategia clang -Weverything. Zamiast wybierać ostrzeżenia do włączenia, włączasz wszystko, a następnie wybierasz określone ostrzeżenia do wyłączenia.
bames53,
86

W nowoczesnym CMake dobrze działa:

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

Mój kolega zasugerował alternatywną wersję:

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

Zastąp ${TARGET_NAME}rzeczywistą nazwą celu. -Werrorjest opcjonalna, zamienia wszystkie ostrzeżenia w błędy.

Lub użyj, add_compile_options(...)jeśli chcesz zastosować go do wszystkich celów, zgodnie z sugestią @aldo w komentarzach.

Pamiętaj też, aby zrozumieć różnicę między PRIVATEi PUBLIC(opcje publiczne będą dziedziczone przez cele zależne od danego celu).

mrts
źródło
19
Lub po prostu, add_compile_options(...)jeśli chcesz zastosować go do wszystkich celów.
aldo
1
FYI nowoczesny CMake nie wymaga powtarzania warunku w else()lub endif().
Timmmm,
1
@Timmmm Dzięki za ostrzeżenia! Czy to tylko uwaga, czy wolisz, żebym usunął warunki?
kończy się
1
@helmesjo Nie, Timmmm odnosił się do kodu CMake, który istniał przed edycją z 9 kwietnia. Możesz spojrzeć na historię edycji, aby zobaczyć bity, które zostały usunięte, czyli te same rzeczy, które wskazał Timmmm.
FeRD
2
@aldo, problem add_compile_options()polega na tym, że ostrzeżenia będą propagowane do celów dodanych przez add_subdirectory(). Jeśli włączysz w ten sposób biblioteki zewnętrzne, możesz otrzymać wiele ostrzeżeń, jeśli ta biblioteka została zaprojektowana z innym poziomem ostrzeżenia.
trozen
24

Niektóre moduły CMake, które napisałem, obejmują eksperymentalne tłumienie ostrzeżeń międzyplatformowych :

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}"
)

Wynik dla Xcode:

  • Ustaw CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSIONatrybut Xcode (inaczej ustawienia kompilacji -> ostrzeżenia -> podejrzane niejawne konwersje -> TAK )
  • Dodaj flagę kompilatora: -Werror

Makefile gcc i clang:

  • Dodaj flagi kompilatora: -Wconversion,-Werror

Studio wizualne:

  • Dodaj flagi kompilatora: /WX,/w14244

Spinki do mankietów

xaxxon
źródło
1
Szkoda, że ​​cmake nie zapewnia tej funkcjonalności
Slava
3
Dobre wieści. Przepraszam, że umieszczam to tutaj, a nie na liście mailingowej cmake, ale bez poziomu będzie to bezużyteczne. Jest po prostu zbyt wiele ostrzeżeń, aby je wszystkie wyraźnie wymienić. Jeśli chcesz to ujednolicić, jednym ze sposobów są dwa oddzielne cmake_level - ujednolicony zestaw ostrzeżeń, oparty na przykład na clang i native_level o znaczeniu specyficznym dla kompilatora. Jeden z nich można prawdopodobnie skrócić do poziomu. Przepraszam, jeśli tak naprawdę nie śledziłem rozmowy i coś mi się nie udało
Slava
1
@ void.pointer podnosi ważny punkt. Proponowanego odpowiedź brzmi: Mam zamiar dodać tę funkcję” . Nie mówi, że zrobiłeś jakieś pobieżne badania i teraz masz nadzieję, że ktoś inny wykona za Ciebie ciężkie podnoszenie. Jeśli nie chcesz przypisywać Ci realizacji (i pytań dotyczących jej postępów), musisz edytować swoją odpowiedź i odciąć się od zadania, w którym nie poczyniłeś żadnych postępów od ponad roku.
Niespodziewane
„Ponad rok później nadal brak postępu”. - To jest ważny punkt. Minął ponad rok, bez postępu. To bardzo mocna oznaka porzuconego projektu. Jeśli chcesz nam udowodnić, że się mylimy, pokaż nam postęp. Tak się nie stało, ale proponowana przez Ciebie odpowiedź nadal sugeruje, że ta funkcja zostanie właśnie dodana do CMake. Po co robić tyle zamieszania na temat funkcji, która nie będzie dostępna za lata? To wcale nie jest pomocne. Pokaż pewien postęp lub edytuj swoją odpowiedź, aby była mniej myląca.
Niespodziewane
5
Wydaje się, że nie rozumiesz. Jeśli sugerujesz, że zamierzasz wdrożyć funkcję, musisz wdrożyć tę funkcję w odpowiednim czasie. W przeciwnym razie zostaniesz poproszony o usunięcie tej obietnicy z proponowanej odpowiedzi. Nie wykazałeś żadnego zaangażowania we wdrożenie tej funkcji, więc nie twierdzisz inaczej. Rozumiem, że jest duży. Rozumiem również, że możesz nie być w stanie tego zrobić. Po prostu proszę, aby Twoja odpowiedź to odzwierciedlała.
Niespodziewane
6

Oto najlepsze rozwiązanie, jakie do tej pory znalazłem (w tym sprawdzenie kompilatora):

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

Spowoduje to ustawienie poziomu ostrzeżenia 2 w programie Visual Studio. Przypuszczam -W2, że działałoby to również w GCC (niesprawdzone).

Aktualizacja z @Williams: Powinna być -Walldla GCC.

Wernight
źródło
6
Flaga ostrzegawcza dla GCC byłaby -Walli być może -Wextratak szczegółowa, jak na stronie gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Milliams
1
Lista, której używam, to -W -Wall -Wextra -pedantic. -WextraIIRC zastąpione -Ww późniejszej wersji GCC, ale dla zachowania kompatybilności zostawiam oba.
Jimmio92
2
Nie jest to zamierzony cel add_definitions ( „ma na celu dodanie definicji preprocesorów” ). To nie tylko zalecenie dotyczące najlepszych praktyk. Argumenty przekazane do tego polecenia pojawią się w wygenerowanych skryptach kompilacji wywołujących narzędzia, które ich nie oczekują (np. Kompilator zasobów).
Niespodziewane
To nie jest „sprawdzenie kompilatora”, to sprawdzenie narzędzia kompilacji.
Thomas
3

Zgodnie z dokumentacją 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 i Clang współużytkują te flagi, więc powinno to obejmować wszystkie 3.

Sójka
źródło
Nie używaj tego. Zamiast tego użyj target_compile_options (). Odnoszenie się do najnowszego dokumentu wydaje się być „poprawne”, ale jest to starożytny wpis dotyczący jedynie wstecznej kompatybilności.
caoanan
1
@caoanan Dokumentacja nie wspomina o kompatybilności wstecznej. add_compile_optionsobejmuje cały katalog, a target_compile_optionsdotyczy tylko jednego celu.
TehWan
2
if(MSVC)
    string(REGEX REPLACE "/W[1-3]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif()

Jeśli używasz target_compile_options- cmake spróbuje użyć podwójnej /W*flagi, co da ostrzeżenie kompilatorowi.

TarmoPikaro
źródło
Dzięki za to. Naiwnie korzystałem z add_compile_optionsjedynego, aby uzyskać mnóstwo ostrzeżeń, które /W3są zastępowane /W4. Fakt, że CMake nie zajmuje się tą podstawową opcją (ustawieniem poziomu ostrzegawczego) jest nie do uwierzenia.
Zmartwychwstanie