Jawaban singkat
Tidak mungkin untuk menetapkan nilai akhir baris perintah kompiler ke variabel dalam skrip CMake, yang berfungsi di semua kasus penggunaan.
Jawaban panjang
Sayangnya, bahkan solusi yang diterima sebagai jawaban masih belum mendapatkan semua tanda kompiler. Seperti yang disebutkan di komentar, ada Persyaratan Penggunaan Transitif. Ini adalah cara modern dan tepat untuk menulis file CMake, yang semakin populer. Anda juga mungkin memiliki beberapa opsi kompilasi yang ditentukan menggunakan ekspresi generator (terlihat seperti referensi variabel tetapi tidak akan diperluas bila diperlukan).
Pertimbangkan untuk memiliki contoh berikut:
add_executable(myexe ...);
target_compile_definitions(myexe PRIVATE "PLATFORM_$<PLATFORM_ID>");
add_library(mylib ...);
target_compile_definitions(mylib INTERFACE USING_MY_LIB);
target_link_libraries(myexe PUBLIC mylib);
Jika Anda mencoba memanggil makro GET_COMPILER_FLAGS yang diusulkan dengan target myexe
, Anda akan mendapatkan keluaran -DPLATFORM_$<PLATFORM_ID>
, bukan -DPLATFORM_Linux -DUSING_MY_LIB
yang diharapkan.
Hal ini karena ada dua tahapan antara menjalankan CMake dan menghasilkan sistem build:
- Pengolahan. Pada tahap ini CMake membaca dan mengeksekusi perintah dari skrip cmake, khususnya, nilai variabel yang dievaluasi dan ditetapkan. Saat ini CMake hanya mengumpulkan semua informasi yang diperlukan dan bersiap untuk menghasilkan sistem build (makefiles).
- Menghasilkan. CMake menggunakan nilai variabel khusus dan properti, ditinggalkan di akhir skrip yang diproses untuk akhirnya memutuskan dan bentuk keluaran yang dihasilkan. Di sinilah ia membangun baris perintah akhir untuk kompiler sesuai dengan algoritma internalnya, tidak tersedia untuk skrip.
Properti target yang mungkin diambil pada tahap pemrosesan dengan get_target_property(...)
atau get_property(... TARGET ...)
tidak lengkap (bahkan ketika dipanggil di akhir skrip). Pada tahap pembuatan, CMake menelusuri setiap pohon ketergantungan target (secara rekursif) dan menambahkan nilai properti sesuai dengan persyaratan penggunaan transitif (nilai yang diberi tag PUBLIC
dan INTERFACE
disebarkan).
Meskipun demikian, ada solusinya, tergantung pada hasil akhir yang ingin Anda capai. Hal ini dimungkinkan dengan menerapkan ekspresi generator, yang memungkinkan penggunaan nilai final dari properti target apa pun (ditentukan pada tahap pemrosesan)... tetapi nanti!
Tersedia dua kemungkinan umum:
- Hasilkan file keluaran apa pun berdasarkan templat, yang isinya berisi referensi variabel dan/atau ekspresi generator, dan didefinisikan sebagai nilai variabel string, atau file masukan. Ini tidak fleksibel karena dukungan logika kondisional yang sangat terbatas (yaitu Anda tidak dapat menggunakan rangkaian kompleks yang hanya tersedia dengan loop
foreach()
bersarang), tetapi memiliki kelebihan, yaitu tidak diperlukan tindakan lebih lanjut dan konten dijelaskan dengan cara yang tidak bergantung pada platform. Gunakan varian perintah file(GENERATE ...). Perhatikan, perilakunya berbeda dari varian file (WRITE ...)
.
- Tambahkan target khusus (dan/atau perintah khusus) yang mengimplementasikan penggunaan lebih lanjut dari nilai yang diperluas. Ini bergantung pada platform dan mengharuskan pengguna untuk memanggil
make
tambahan (baik dengan beberapa target khusus, atau menyertakan ke target all
), tetapi memiliki keuntungan, yaitu cukup fleksibel karena Anda dapat mengimplementasikan skrip shell (tetapi tanpa bit yang dapat dieksekusi).
Contoh yang menunjukkan solusi dengan menggabungkan opsi-opsi ini:
set(target_name "myexe")
file(GENERATE OUTPUT script.sh CONTENT "#!/bin/sh\n echo \"${target_name} compile definitions: $<TARGET_PROPERTY:${target_name},COMPILE_DEFINITIONS>\"")
add_custom_target(mycustomtarget
COMMAND echo "\"Platform: $<PLATFORM_ID>\""
COMMAND /bin/sh -s < script.sh
)
Setelah memanggil direktori build CMake akan berisi file script.sh
dan memanggil make mycustomtarget
akan mencetak ke konsol:
Platform: Linux
myexe compile definitions: PLATFORM_Linux USING_MY_LIB
person
Artem Pisarenko
schedule
05.11.2019