Panduan Lengkap CMake. Bagian Satu: Sintaks


Pendahuluan


CMake adalah rangkaian utilitas terbuka dan lintas platform yang dirancang untuk mengotomatisasi pengujian, kompilasi, dan membuat paket proyek dalam C / C ++. Dengan menulis satu skrip kecil yang dipahami semua orang, Anda akan memastikan proyek yang sama dibangun pada platform apa pun di mana CMake tersedia.


Bahasa CMake , yang diterjemahkan ke dalam file assembly asli (misalnya, Makefile atau Ninja), mendefinisikan proses semua manajemen proyek. Yang Anda inginkan, di sisi fungsional, hanya ada tim yang dapat dibentuk menjadi struktur yang cukup kompleks. Kami akan mulai dengan mereka.


Peluncuran CMake


Berikut ini adalah contoh penggunaan bahasa CMake yang harus Anda praktikkan. Eksperimen dengan kode sumber dengan memodifikasi perintah yang ada dan menambahkan yang baru. Untuk menjalankan contoh-contoh ini, instal CMake dari situs web resmi .


Tim


Perintah dalam CMake mirip dengan fungsi dalam banyak bahasa pemrograman. Untuk memanggil perintah, Anda harus menulis namanya, dan kemudian memberikannya argumen yang dilampirkan dalam tanda kurung, dipisahkan dengan spasi. Dalam contoh di atas, enam argumen dilewatkan ke perintah message untuk output ke konsol:


 #    "CMake is the most powerful buildsystem!" message("CMake " "is " "the " "most " "powerful " "buildsystem!") 

Argumen


Argumen dibingkai dalam tanda kutip ganda memungkinkan Anda untuk melarikan diri dan mengganti variabel di dalam diri Anda. Argumen yang tidak dibingkai tidak memungkinkan produksi hal-hal seperti itu dan tidak dapat menyertakan karakter ()#"\ dan spasi, tetapi lebih nyaman digunakan. Contoh:


 #  "Hello, my lovely CMake",    "!": message("Hello, my lovely CMake\t!") #  "Hello,_my_lovely_CMake!"  : message(Hello,_my_lovely_CMake!) 

Perlu dicatat bahwa argumen Walk;around;the;forest akan meluas ke daftar Walk around the forest , karena setiap argumen yang tidak dibingkai secara otomatis memperluas ke daftar nilai (asalkan nilai-nilai argumen asli dipisahkan dengan titik koma), tetapi dengan dua tanda kutip sebagai argumen transformasi seperti itu tidak terjadi (karakter titik koma hilang begitu saja). Fitur ini disebutkan dalam komentar.


Komentar


Komentar dimulai dengan tanda pound dan berakhir di ujung garis di mana mereka dicetak. Teks yang terkandung dalam komentar diabaikan oleh sistem build dan tidak berpengaruh pada operasinya. Contoh-contoh di atas juga menunjukkan penggunaan komentar.


Variabel


Variabel dapat didefinisikan dengan memanggil perintah yang set , dan dihapus dengan memanggil unset . Anda bisa mendapatkan nilai variabel dengan membuat ${VARIABLE} . Jika variabel belum ditentukan dan di suatu tempat itu diperlukan untuk mendapatkan nilainya, maka variabel ini akan berubah menjadi string kosong. Contoh:


 #   VARIABLE   "Mr. Thomas": set(VARIABLE "Mr. Thomas") #  "His name is: Mr. Thomas": message("His name is: " ${VARIABLE}) #  "'BINGO' is equal to: []",   "BINGO"  : message("'BINGO' is equal to: [${BINGO}]") #   VARIABLE: unset(VARIABLE) 

Opsi


CMake mendukung opsi pengaturan yang dapat diubah pengguna. Opsi serupa dengan variabel dan diatur oleh perintah option , yang hanya membutuhkan tiga argumen: nama variabel, deskripsi string variabel, dan nilai default variabel ( ON atau OFF ):


 #   `USE_ANOTHER_LIBRARY`   # "Do you want to use an another library?"   "OFF": option(USE_ANOTHER_LIBRARY "Do you want to use an another library?" OFF) 

Ekspresi logis


Sebelum melanjutkan dengan studi operator kondisional dan konstruksi siklik, perlu untuk memahami karya ekspresi logis. Ekspresi logis digunakan ketika memeriksa kondisi dan dapat mengambil salah satu dari dua nilai: true atau false. Misalnya, ungkapan 52 LESS 58 akan benar, karena 52 <58. Ekspresi 88 EQUAL 88 akan benar, 63 GREATER 104 akan salah. Anda dapat membandingkan tidak hanya angka, tetapi juga string, versi, file, daftar keanggotaan, dan ekspresi reguler. Daftar lengkap ekspresi logis dapat ditemukan di sini .


Pernyataan bersyarat


Operator bersyarat dalam CMake bekerja persis seperti dalam bahasa pemrograman lainnya. Dalam contoh ini, hanya operator kondisional pertama yang akan bekerja, yang memeriksa bahwa 5> 1. Kondisi kedua dan ketiga salah, karena 5 tidak boleh kurang dari atau sama dengan satu. Blok perintah elseif dan else adalah opsional, dan endif diperlukan dan menandakan penyelesaian pemeriksaan sebelumnya.


 #  "Of course, 5 > 1!": if(5 GREATER 1) message("Of course, 5 > 1!") elseif(5 LESS 1) message("Oh no, 5 < 1!") else() message("Oh my god, 5 == 1!") endif() 

Siklus


Loop dalam CMake mirip dengan loop dalam bahasa pemrograman lain. Dalam contoh di atas, nilai variabel VARIABLE diatur ke Airport , dan kemudian empat perintah bertingkat dieksekusi secara berurutan sampai nilai variabel VARIABLE sama dengan Airport . Perintah set(VARIABLE "Police station") keempat terakhir set(VARIABLE "Police station") menetapkan nilai variabel yang diperiksa di kantor Police station , sehingga loop akan berhenti segera sebelum mencapai iterasi kedua. Perintah endwhile menandakan selesainya daftar perintah yang bersarang di loop.


 #      "VARIABLE is still 'Airport'": set(VARIABLE Airport) while(${VARIABLE} STREQUAL Airport) message("VARIABLE is still '${VARIABLE}'") message("VARIABLE is still '${VARIABLE}'") message("VARIABLE is still '${VARIABLE}'") set(VARIABLE "Police station") endwhile() 

Contoh ini untuk setiap foreach bekerja sebagai berikut: pada setiap iterasi dari loop ini, variabel VARIABLE diberi nilai berikut dari daftar Give me the sugar please! dan kemudian perintah message(${VARIABLE}) dieksekusi, yang menampilkan nilai variabel VARIABLE . Ketika tidak ada nilai dalam daftar, loop mengakhiri eksekusi. Perintah endforeach menandakan penyelesaian daftar perintah yang bersarang di loop.


 #  "Give me the sugar please!"   : foreach(VARIABLE Give me the sugar please!) message(${VARIABLE}) endforeach() 

Ada 3 bentuk penulisan foreach . Siklus pertama dalam contoh ini menghasilkan bilangan bulat dari 0 hingga 10 sebagai pengganti daftar, siklus kedua menghasilkan dalam kisaran 3 hingga 15, dan siklus ketiga bekerja di segmen dari 50 hingga 90, tetapi dengan langkah 10.


 #  "0 1 2 3 4 5 6 7 8 9 10"   : foreach(VARIABLE RANGE 10) message(${VARIABLE}) endforeach() #  "3 4 5 6 7 8 9 10 11 12 13 14 15"   : foreach(VARIABLE RANGE 3 15) message(${VARIABLE}) endforeach() #  "50 60 70 80 90"   : foreach(VARIABLE RANGE 50 90 10) message(${VARIABLE}) endforeach() 

Fungsi dan makro


Sintaks CMake memungkinkan Anda untuk mendefinisikan perintah Anda sendiri yang dapat dipanggil persis seperti bawaan. Contoh berikut menunjukkan penggunaan fungsi dan makro: pertama, fungsi dan makro didefinisikan dengan perintah mereka sendiri, dan ketika dipanggil, perintah mereka dieksekusi secara berurutan.


 #   "print_numbers": function(print_numbers NUM1 NUM2 NUM3) message(${NUM1} " " ${NUM2} " " ${NUM3}) endfunction() #   "print_words": macro(print_words WORD1 WORD2 WORD3) message(${WORD1} " " ${WORD2} " " ${WORD3}) endmacro() #   "print_numbers",   "12 89 225": print_numbers(12 89 225) #   "print_words",   "Hey Hello Goodbye": print_words(Hey Hello Goodbye) 

Perintah function mengambil nama fungsi masa depan sebagai argumen pertama, dan argumen lainnya adalah nama-nama parameter yang dapat digunakan sebagai variabel normal. Parameter hanya dapat dilihat oleh fungsi yang didefinisikan, yang berarti kita tidak dapat mengakses parameternya di luar fungsi. Selain itu, semua variabel lain yang didefinisikan dan didefinisikan ulang dalam fungsi hanya dapat dilihat oleh dirinya sendiri.


Makro mirip dengan fungsi dengan pengecualian bahwa mereka tidak memiliki cakupan sendiri: semua variabel di dalam makro dianggap global. Anda dapat membaca lebih lanjut tentang perbedaan antara makro dan fungsi di sini .


Seperti disebutkan dalam komentar, makro di CMake mirip dengan makro di preprocessor C: jika Anda meletakkan perintah return di badan makro, Anda akan keluar dari fungsi panggilan (atau seluruh skrip), seperti contoh ini menunjukkan:


 #  ,   : macro(demonstrate_macro) return() endmacro() #  ,   : function(demonstrate_func) demonstrate_macro() message("The function was invoked!") endfunction() #  "Something happened with the function!" demonstrate_func() message("Something happened with the function!") 

Pada contoh di atas, fungsi demonst_func tidak akan punya waktu untuk mencetak pesan The function was invoked! , seperti sebelumnya, tempat memanggil macro demonstrate_macro akan diganti dan perintah keluar akan dieksekusi.


Argumen Parsing


Seperti dicatat dalam komentar, Mekanisme cmake_parse_arguments kuat memungkinkan argumen parsing diteruskan ke fungsi atau makro.


Perintah ini menerima awalan yang digunakan dalam definisi variabel (lihat paragraf berikutnya), daftar opsi yang digunakan tanpa nilai berikutnya, daftar kata kunci diikuti oleh nilai tunggal, daftar kata kunci diikuti oleh set nilai, dan daftar semua nilai yang diteruskan ke fungsi atau makro.


Pekerjaan mekanisme parsing argumen adalah untuk mengubah argumen yang diterima menjadi nilai variabel. Dengan demikian, perintah yang dipertimbangkan untuk setiap opsi dan kata kunci mendefinisikan variabelnya sendiri dari formulir <Prefix>_<OptionOrKeyword> , yang merangkum nilai tertentu. Untuk opsi, ini adalah nilai Boolean (true - opsi diindikasikan; jika tidak, false), dan untuk kata kunci, semua nilai yang ditransfer terletak setelahnya.


Fungsi custom_function berisi panggilan ke cmake_parse_arguments , dan kemudian mencetak nilai-nilai variabel tertentu. Selanjutnya, fungsi ini disebut dengan argumen LOW NUMBER 30 COLORS red green blue , setelah itu dicetak di layar:


 function(custom_function) #       : cmake_parse_arguments(CUSTOM_FUNCTION "LOW;HIGH" "NUMBER" "COLORS" ${ARGV}) #  "'LOW' = [TRUE]": message("'LOW' = [${CUSTOM_FUNCTION_LOW}]") # "'HIGH' = [FALSE]": message("'HIGH' = [${CUSTOM_FUNCTION_HIGH}]") #  "'NUMBER' = [30]": message("'NUMBER' = [${CUSTOM_FUNCTION_NUMBER}]") #  "'COLORS' = [red;green;blue]": message("'COLORS' = [${CUSTOM_FUNCTION_COLORS}]") endfunction() #   "custom_function"   : custom_function(LOW NUMBER 30 COLORS red green blue) 

Lingkup


Di bagian sebelumnya, Anda mengetahui bahwa beberapa konstruksi di CMake dapat menentukan cakupannya sendiri. Bahkan, semua variabel dianggap global secara default (akses ke mereka ada di mana-mana), dengan pengecualian yang telah didefinisikan dan didefinisikan ulang dalam fungsi. Ada juga variabel cache yang memiliki cakupannya sendiri, tetapi tidak sering digunakan.


Seperti disebutkan dalam komentar, variabel dapat didefinisikan dalam lingkup "induk" menggunakan perintah set(VARIABLE ... PARENT_SCOPE) . Contoh ini menunjukkan fitur ini:


 # ,   "VARIABLE"   # "In the parent scope..."    : function(demonstrate_variable) set(VARIABLE "In the parent scope..." PARENT_SCOPE) endfunction() #   "VARIABLE"    : demonstrate_variable() #      "VARIABLE" : message("'VARIABLE' is equal to: ${VARIABLE}") 

Jika PARENT_SCOPE dihapus dari definisi variabel VARIABLE , maka variabel hanya akan dapat diakses oleh fungsi demonstrate_variable , dan dalam lingkup global akan mengambil nilai kosong.


Kesimpulan


Ini menyimpulkan sintaks CMake. Artikel selanjutnya akan dirilis dalam beberapa hari dan akan memperkenalkan penggunaan sistem build CMake. Sampai ketemu lagi!

Source: https://habr.com/ru/post/id431428/


All Articles