Bagaimana cara mengatur tingkat peringatan di CMake?

116

Bagaimana cara mengatur tingkat peringatan untuk sebuah proyek (bukan seluruh solusi) menggunakan CMake ? Harus bekerja di Visual Studio dan GCC .

Saya menemukan berbagai opsi tetapi sebagian besar tampaknya tidak berfungsi atau tidak konsisten dengan dokumentasinya.

Wernight
sumber

Jawaban:

96

UPDATE: Jawaban ini mendahului era CMake Modern. Setiap pengguna CMake yang waras harus menahan diri dari mengutak-atik CMAKE_CXX_FLAGSsecara langsung dan memanggil target_compile_optionsperintah sebagai gantinya. Periksa jawaban mrts yang menyajikan praktik terbaik yang direkomendasikan.

Anda dapat melakukan sesuatu yang mirip dengan ini:

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.dll
sumber
Perhatikan bahwa versi baru Visual Studio (setidaknya 2013) mendukung /Wallbendera (yang diberi nama EnableAllWarnings). Ini menghasilkan lebih banyak peringatan daripada /W4. Namun dari pengalaman saya, hal itu menghasilkan terlalu banyak peringatan.
Adam Badura
12
/Walldapat digunakan jika Anda ingin mengikuti strategi 'subtraktif' untuk peringatan, seperti dentang -Weverything. Alih-alih memilih peringatan untuk diaktifkan, Anda mengaktifkan semuanya dan kemudian memilih peringatan tertentu untuk dinonaktifkan.
bames53
86

Di CMake modern, berikut ini bekerja dengan baik:

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

Rekan saya menyarankan versi alternatif:

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

Ganti ${TARGET_NAME}dengan nama target yang sebenarnya.-Werrorbersifat opsional, ini mengubah semua peringatan menjadi kesalahan.

Atau gunakan add_compile_options(...)jika Anda ingin menerapkannya ke semua target seperti yang disarankan oleh @aldo di komentar.

Juga, pastikan untuk memahami perbedaan antara PRIVATEdan PUBLIC(opsi publik akan diwarisi oleh target yang bergantung pada target yang diberikan).

mrts
sumber
19
Atau sederhana add_compile_options(...)jika Anda ingin menerapkannya ke semua target.
aldo
1
FYI modern CMake tidak memerlukan pengulangan kondisi dalam else()atau endif().
Timmmm
1
@Timmmm Terima kasih atas perhatiannya! Apakah ini hanya catatan atau Anda lebih suka saya menghapus ketentuannya?
mrts
1
@helmesjo Tidak, Timmmm mengacu pada kode CMake seperti yang ada sebelum pengeditan 9 April. Anda dapat melihat histori edit untuk melihat bit yang telah dihapus, yang merupakan hal yang sama yang ditunjukkan oleh Timmmm.
FeRD
2
@aldo Masalahnya add_compile_options()adalah bahwa peringatan akan menyebar ke target yang ditambahkan melalui add_subdirectory(). Jika Anda menyertakan pustaka eksternal dengan cara ini, Anda mungkin mendapatkan banyak peringatan jika pustaka itu dirancang dengan tingkat peringatan yang berbeda.
trozen
24

Beberapa modul CMake yang saya tulis mencakup penekanan peringatan lintas-platfrom eksperimental :

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

Hasil untuk Xcode:

  • Setel CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSIONatribut Xcode (alias pengaturan build -> peringatan -> konversi implisit yang mencurigakan -> YA )
  • Tambahkan tanda kompilator: -Werror

Makefile gcc dan clang:

  • Menambahkan bendera compiler: -Wconversion,-Werror

Studio visual:

  • Menambahkan bendera compiler: /WX,/w14244

Tautan

xaxxon.dll
sumber
1
sayangnya cmake tidak menyediakan fungsi ini
Slava
3
Kabar baik. Maaf untuk mempostingnya di sini dan tidak di milis cmake, tetapi tanpa level ini akan sia-sia, Ada terlalu banyak peringatan untuk mencantumkan semuanya secara eksplisit. Jika Anda ingin menyatukannya, salah satu cara untuk melakukannya adalah dua cmake_level terpisah - kumpulan peringatan yang disatukan, misalnya berdasarkan clang, dan native_level dengan arti khusus untuk kompilator. Salah satunya mungkin bisa disingkat menjadi level. Maaf jika saya tidak benar-benar mengikuti percakapan dan mendapatkan kesalahan
Slava
1
@ void.pointer memunculkan poin yang valid. Jawaban yang Anda usulkan berbunyi: " Saya berencana menambahkan fitur ini" . Tidak dikatakan, bahwa Anda melakukan penelitian sepintas lalu dan sekarang berharap ada orang lain yang melakukan pekerjaan berat untuk Anda. Jika Anda tidak ingin dikaitkan dengan implementasi (dan pertanyaan tentang kemajuannya), Anda perlu mengedit jawaban Anda dan memisahkan diri Anda dari tugas yang belum Anda buat kemajuannya selama lebih dari setahun.
IInspectable
"Lebih dari setahun kemudian, masih belum ada kemajuan." - Sekarang adalah titik yang valid. Lebih dari satu tahun telah berlalu, tanpa kemajuan sama sekali. Itu adalah indikasi yang sangat kuat dari sebuah proyek yang ditinggalkan. Jika Anda ingin membuktikan kami salah, tunjukkan beberapa kemajuan. Itu belum terjadi, tetapi jawaban yang Anda usulkan masih menunjukkan, bahwa fitur tersebut akan segera ditambahkan ke CMake. Mengapa membuat keributan tentang fitur yang tidak akan tersedia selama bertahun-tahun? Itu tidak membantu sama sekali. Tunjukkan kemajuan, atau edit jawaban Anda agar tidak terlalu menyesatkan.
IInspectable
5
Anda tampaknya tidak mengerti. Jika Anda menyarankan Anda untuk mengimplementasikan fitur, maka Anda perlu mengimplementasikan fitur itu pada waktunya. Jika gagal, Anda diminta untuk menghapus janji itu dari jawaban yang Anda usulkan. Anda tidak menunjukkan komitmen apa pun untuk menerapkan fitur tersebut, jadi jangan mengklaim sebaliknya. Saya mengerti bahwa ini besar. Saya juga memahami bahwa Anda mungkin tidak dapat melakukan ini. Saya hanya meminta Anda untuk membuat jawaban Anda mencerminkan hal itu.
IInspectable
6

Berikut adalah solusi terbaik yang saya temukan sejauh ini (termasuk pemeriksaan kompiler):

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

Ini akan menetapkan peringatan level 2 di Visual Studio. Saya kira dengan -W2itu akan bekerja di GCC juga (belum teruji).

Pembaruan dari @Williams: Seharusnya -Walluntuk GCC.

Wernight
sumber
6
Bendera peringatan untuk GCC adalah -Walldan mungkin -Wextraseperti yang dijelaskan di gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
Milliams
1
Daftar yang saya gunakan adalah -W -Wall -Wextra -pedantic. -WextraIIRC diganti -Wdi versi GCC yang lebih baru, tetapi saya meninggalkan keduanya demi kompatibilitas.
Jimmio92
2
Itu bukan tujuan dari add_definitions ( "ini dimaksudkan untuk menambahkan definisi preprocessor" ). Ini juga bukan hanya rekomendasi praktik terbaik. Argumen yang diteruskan ke perintah ini akan muncul di skrip build yang memanggil alat yang tidak mengharapkannya (mis. Kompiler sumber daya).
IInspectable
Itu bukan "pemeriksaan kompiler", ini adalah pemeriksaan alat build.
Thomas
3

Sesuai dokumentasi 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 dan Clang berbagi tanda ini, jadi ini harus mencakup semua 3.

Jay
sumber
Jangan gunakan ini. Sebagai gantinya, gunakan target_compile_options (). Mengacu pada dokumen terbaru tampaknya "benar", tetapi ini adalah entri kuno hanya untuk kompatibilitas ke belakang.
caoanan
1
@caoanan Dokumentasi tidak menyebutkan kompatibilitas ke belakang untuk ini. add_compile_optionsadalah seluruh direktori, sedangkan target_compile_optionshanya untuk satu target.
TehWan
2
if(MSVC)
    string(REGEX REPLACE "/W[1-3]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif()

Jika Anda menggunakan target_compile_options- cmake akan mencoba menggunakan /W*flag ganda , yang akan memberikan peringatan oleh compiler.

TarmoPikaro
sumber
Terima kasih untuk ini. Saya secara naif menggunakan add_compile_optionssatu - satunya untuk mendapatkan banyak peringatan yang /W3sedang diganti /W4. Fakta bahwa CMake tidak menangani opsi dasar ini (pengaturan tingkat peringatan) tidak dapat dipercaya.
Kebangkitan