Ganti tanda kompilasi untuk file tunggal

109

Saya ingin menggunakan serangkaian tanda global untuk menyusun proyek, yang berarti bahwa pada file CMakeLists.txt tingkat atas saya, saya telah menentukan:

ADD_DEFINITIONS ( -Wall -Weffc++ -pedantic -std=c++0x )

Namun, untuk file tertentu (katakanlah "foo.cpp") di subdirektori, saya ingin mengganti flag kompilasi untuk tidak menerapkan -Weffc ++ (termasuk pustaka komersial yang tidak dapat saya ubah). Untuk menyederhanakan situasi agar hanya menggunakan -Wall, saya mencoba:

 SET_SOURCE_FILES_PROPERTIES( foo.cpp PROPERTIES COMPILE_FLAGS -Wall )
 ADD_EXECUTABLE( foo foo.cpp )

, yang tidak berhasil. Saya juga mencoba

SET_PROPERTY( SOURCE foo.cpp PROPERTY COMPILE_FLAGS -Wall )
ADD_EXECUTABLE( foo foo.cpp )

dan

ADD_EXECUTABLE( foo foo.cpp )
SET_TARGET_PROPERTIES( foo PROPERTIES COMPILE_FLAGS -Wall )

, yang tidak berhasil.

Akhirnya, saya mencoba menghapus definisi ini:

REMOVE_DEFINITIONS( -Weffc++ )
ADD_EXECUTABLE( foo foo.cpp )
ADD_DEFINITIONS( -Weffc++ )

, yang juga tidak berfungsi (artinya, saya mendapat banyak peringatan gaya tentang pustaka komersial). (** Catatan: Peringatan akan disembunyikan jika saya TIDAK menyertakan kembali direktif -Weffc ++ setelah executable dibuat.)

Saya juga mencoba menghapus sementara bendera kompilasi: http://www.cmake.org/pipermail/cmake/2007-June/014614.html , tetapi itu tidak membantu.

Apakah tidak ada solusi elegan untuk ini?

JB Brown
sumber
1
Tunggu, jika upaya terakhir Anda berhasil, tetapi hanya setelah dibuat, mungkinkah ini bukan masalah cache? Coba hapus CMakeCache setelah melakukan perubahan.
Cameron
Terkait, lihat Bagaimana mengubah flag compiler hanya untuk satu executable di CMake? Jawaban Andre menunjukkan apa yang tampaknya menjadi cara untuk mengganti opsi yang ada dengan opsi baru.
jww

Jawaban:

126

Upaya Anda di atas menambahkan flag lebih lanjut ke file / target Anda daripada menimpa seperti yang Anda harapkan. Misalnya, dari dokumen untuk Properti di File Sumber - COMPILE_FLAGS :

Tanda ini akan ditambahkan ke daftar tanda kompilasi saat file sumber ini dibuat.

Anda harus dapat -Weffc++mengimbangi flag untuk foo.cpp dengan melakukan

set_source_files_properties(foo.cpp PROPERTIES COMPILE_FLAGS -Wno-effc++)

Ini seharusnya memiliki efek menambahkan -Wno-effc++setelah -Weffc++dalam perintah kompilator, dan pengaturan terakhir menang. Untuk melihat perintah lengkap dan memeriksa apakah memang demikian, Anda dapat melakukannya

make VERBOSE=1

Selain itu, salah satu pengelola Perpustakaan Standar GNU C ++ memberikan pendapat yang cukup negatif -Weffc++dalam jawaban ini .

Poin lainnya adalah Anda menyalahgunakan add_definitionsdalam artian Anda menggunakan ini untuk flag compiler daripada definisi preprocessor yang dimaksudkan.

Akan lebih baik jika digunakan add_compile_options

add_compile_options(-Wall -Weffc++ -pedantic -std=c++0x)

atau untuk CMake versi <3.0 untuk melakukan sesuatu yang lebih seperti:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Weffc++ -pedantic -std=c++0x")

Menanggapi pertanyaan lebih lanjut di komentar di bawah, saya yakin tidak mungkin untuk menghapus bendera dengan andal pada satu file. Alasannya adalah karena untuk file sumber tertentu, ia memiliki target COMPILE_OPTIONSdan 1 yang diterapkan, tetapi ini tidak muncul di properti mana pun untuk file sumber tersebut.COMPILE_FLAGS

Anda dapat melihat COMPILE_OPTIONSmenghapus tanda masalah dari target , lalu menerapkannya ke setiap sumber target secara individual, menghilangkannya dari file sumber spesifik sesuai kebutuhan.

Namun, meskipun ini bisa berhasil di banyak skenario, ini memiliki beberapa masalah.

Properti file sumber pertama tidak termasuk COMPILE_OPTIONS, hanya COMPILE_FLAGS. Ini menjadi masalah karena COMPILE_OPTIONStarget dapat menyertakan ekspresi generator , tetapi COMPILE_FLAGStidak mendukungnya. Jadi, Anda harus mengakomodasi ekspresi generator saat mencari flag Anda, dan bahkan Anda mungkin harus "mengurai" ekspresi generator jika flag Anda ada di satu atau lebih untuk melihat apakah harus diterapkan kembali ke yang tersisa file sumber.

Kedua - sejak CMake v3.0, target dapat ditentukan INTERFACE_COMPILE_OPTIONS. Ini berarti bahwa ketergantungan target Anda dapat menambah atau mengganti target Anda COMPILE_OPTIONSmelalui itu INTERFACE_COMPILE_OPTIONS. Jadi Anda selanjutnya harus mengulang secara rekursif melalui semua dependensi target Anda (bukan tugas yang sangat mudah karena daftar LINK_LIBRARIESuntuk target juga dapat berisi ekspresi generator) untuk menemukan yang menerapkan flag masalah, dan mencoba dan menghapusnya dari itu. target ' INTERFACE_COMPILE_OPTIONSjuga.

Pada tahap kompleksitas ini, saya akan mencari untuk mengirimkan tambalan ke CMake untuk menyediakan fungsionalitas untuk menghapus bendera tertentu tanpa syarat dari file sumber.


1: Perhatikan bahwa tidak seperti COMPILE_FLAGSproperti pada file sumber, COMPILE_FLAGSproperti pada target tidak digunakan lagi.

Fraser
sumber
6
Tetapi bagaimana Anda benar-benar menyetel flag kompilasi untuk file secara terpisah tanpa menambahkannya. Misalnya saya ingin menggunakan bendera kompilasi yang berbeda untuk target yang dihasilkan daripada untuk file tetapi karena mereka ditambahkan, saya harus menghapusnya secara manual. Apakah tidak ada properti yang tidak menambahkan tetapi sebenarnya hanya menyetelnya untuk file / target yang ditentukan?
Baradé
2
Apa yang bisa kita lakukan jika -fno-flag tidak tersedia (dan -fflag disetel)?
gnzlbg
@ Baradé Anda tidak bisa - tidak untuk file sumber.
Fraser
@gnzlbg Sekali lagi, kami cukup banyak terjebak. Saya telah memperbarui jawaban saya untuk memberikan lebih banyak info (dan kemungkinan solusi yang mungkin akan berhasil dalam beberapa skenario).
Fraser
Apakah benar-benar tidak ada solusi untuk pengaturan opsi kompilasi file tunggal? Saya harus menonaktifkan pembuatan cakupan gcc untuk beberapa file yang membuat gcov mogok.
Lothar
5

Hanya menambahkan jawaban benar @ Fraser.

Jika Anda ingin menambahkan bendera khusus ke folder tertentu, Anda dapat melakukan:

file(GLOB SPECIAL_SRC_FILES
        "path/one/src/*.cpp"
        "path/two/src/*.cpp")
set_property(SOURCE ${SPECIAL_SRC_FILES} PROPERTY COMPILE_FLAGS -Wno-effc++)

atau

file(GLOB SPECIAL_SRC_FILES
        "path/one/src/*.cpp"
        "path/two/src/*.cpp")
set_source_files_properties(${SPECIAL_SRC_FILES} PROPERTIES COMPILE_FLAGS -Wno-effc++)

Perhatikan bahwa tidak disarankan menggunakan GLOB seperti yang dibahas di sini

Levon
sumber
0

Menggunakan jawaban @Fraser, saya membuat yang berikut ini untuk menangani termasuk Qt karena variabel mencakup beberapa jalur yang dipisahkan oleh titik koma. Ini berarti saya harus terlebih dahulu menambahkan foreach()loop dan membuat flag include dengan tangan . Tetapi itu memungkinkan saya memiliki satu pengecualian: foo.cpp (satu file itu menggunakan Qt untuk saat ini tetapi untuk jangka panjang saya ingin menghapus ketergantungan itu dan saya ingin memastikan Qt tidak merayap di tempat lain).

find_package(Qt5Core REQUIRED)
set(QT_INCLUDE_PROPERTIES "")
foreach(DIR ${Qt5Core_INCLUDE_DIRS})
    set(QT_INCLUDE_PROPERTIES "${QT_INCLUDE_PROPERTIES} -isystem ${DIR}")
endforeach()
set_source_files_properties(foo.cpp PROPERTIES
    COMPILE_FLAGS
        ${QT_INCLUDE_PROPERTIES}
)

Perhatikan juga bahwa saya menggunakan -isystemalih - alih -Iuntuk menghindari beberapa peringatan yang dihasilkan oleh header Qt (Saya memiliki banyak peringatan yang dihidupkan).

Alexis Wilke
sumber