
Pendahuluan
Artikel ini membahas penggunaan sistem bangun CMake yang digunakan dalam sejumlah besar proyek C / C ++. Sangat disarankan agar Anda membaca bagian pertama manual ini untuk menghindari kesalahpahaman pada sintaksis bahasa CMake, yang secara eksplisit muncul di seluruh artikel.
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 .
Prinsip kerja
Sistem build CMake adalah pembungkus di atas utilitas yang bergantung pada platform lainnya (misalnya, Ninja atau Make ). Jadi, dalam proses perakitan itu sendiri, tidak peduli seberapa paradoksal ini terdengar, itu tidak langsung berpartisipasi.
Sistem build CMake menerima file CMakeLists.txt
dengan deskripsi aturan build dalam bahasa formal CMake, dan kemudian menghasilkan file build intermediate dan asli dalam direktori yang sama yang diterima pada platform Anda.
File-file yang dihasilkan akan berisi nama-nama spesifik dari utilitas sistem, direktori dan kompiler, sementara perintah CMake hanya menggunakan konsep abstrak dari kompiler dan tidak terikat pada alat yang bergantung pada platform yang sangat berbeda pada sistem operasi yang berbeda.
Memeriksa Versi CMake
Perintah cmake_minimum_required
memeriksa versi CMake yang sedang berjalan: jika lebih kecil dari minimum yang ditentukan, maka CMake berakhir dengan kesalahan fatal. Contoh yang menunjukkan penggunaan khas dari perintah ini di awal file CMake:
Seperti disebutkan dalam komentar, perintah cmake_minimum_required
menetapkan semua flag kompatibilitas (lihat cmake_policy
). Beberapa pengembang sengaja mengatur CMake versi rendah, dan kemudian menyesuaikan fungsionalitas secara manual. Ini memungkinkan Anda untuk secara bersamaan mendukung versi kuno CMake dan di beberapa tempat memanfaatkan fitur baru.
Pada awal CMakeLists.txt
harus menentukan karakteristik proyek dengan tim proyek untuk desain yang lebih baik dengan lingkungan terintegrasi dan alat pengembangan lainnya.
Perlu dicatat bahwa jika kata kunci LANGUAGES
dihilangkan, maka bahasa defaultnya adalah C CXX
. Anda juga dapat menonaktifkan indikasi bahasa apa pun dengan menulis kata kunci NONE
sebagai daftar bahasa atau hanya meninggalkan daftar kosong.
Menjalankan file skrip
Perintah include
menggantikan baris panggilannya dengan kode file yang ditentukan, bertindak serupa dengan perintah C / C ++ preprocessor include
. Contoh ini menjalankan file skrip MyCMakeScript.cmake
perintah yang dijelaskan:
message("'TEST_VARIABLE' is equal to [${TEST_VARIABLE}]")
Dalam contoh ini, pesan pertama akan memberi tahu bahwa variabel TEST_VARIABLE
belum didefinisikan, namun, jika skrip MyCMakeScript.cmake
variabel ini, pesan kedua akan menginformasikan tentang nilai baru dari variabel uji. Dengan demikian, file skrip yang dimasukkan oleh perintah include
tidak membuat cakupannya sendiri, yang disebutkan dalam komentar di artikel sebelumnya .
Kompilasi file yang dapat dieksekusi
Perintah add_executable
mengkompilasi file yang dapat dieksekusi dengan nama yang diberikan dari daftar sumber. Penting untuk dicatat bahwa nama file akhir tergantung pada platform target (misalnya, <ExecutableName>.exe
atau hanya <ExecutableName>
). Contoh khas dari pemanggilan perintah ini:
Kompilasi perpustakaan
Perintah add_library
mengkompilasi perpustakaan dengan tampilan dan nama yang ditentukan dari sumber. Penting untuk dicatat bahwa nama pustaka akhir tergantung pada platform target (misalnya, lib<LibraryName>.a
atau <LibraryName>.lib
). Contoh khas dari pemanggilan perintah ini:
- Pustaka statis didefinisikan oleh kata kunci
STATIC
sebagai argumen kedua dan merupakan arsip file objek yang terkait dengan file yang dapat dieksekusi dan pustaka lainnya pada waktu kompilasi; - Pustaka dinamis ditentukan oleh kata kunci
SHARED
sebagai argumen kedua dan pustaka biner yang dimuat oleh sistem operasi selama eksekusi program; - Perpustakaan modular didefinisikan oleh kata kunci
MODULE
sebagai argumen kedua dan perpustakaan biner dimuat menggunakan teknik eksekusi oleh executable itu sendiri; - Pustaka objek didefinisikan oleh kata kunci
OBJECT
sebagai argumen kedua dan merupakan kumpulan file objek yang terkait dengan file yang dapat dieksekusi dan pustaka lainnya pada waktu kompilasi.
Menambahkan sumber ke sasaran
Ada beberapa kasus yang membutuhkan beberapa tambahan file sumber ke target. Untuk melakukan ini, perintah target_sources
, yang dapat menambahkan sumber ke target berkali-kali.
Argumen pertama ke perintah target_sources
adalah nama target yang sebelumnya ditentukan menggunakan perintah add_library
atau add_executable
, dan argumen berikutnya adalah daftar file sumber yang akan ditambahkan.
Panggilan berulang ke target_sources
menambahkan file sumber ke target sesuai urutan pemanggilannya, sehingga dua blok kode terbawah secara fungsional setara:
File yang dihasilkan
Lokasi file output yang dihasilkan oleh perintah add_executable
dan add_library
hanya ditentukan pada tahap pembuatan, namun, aturan ini dapat diubah dengan beberapa variabel yang menentukan lokasi akhir file biner:
File yang dapat dieksekusi selalu dianggap sebagai tujuan eksekusi, perpustakaan statis dianggap sebagai tujuan arsip, dan perpustakaan modular dianggap sebagai tujuan perpustakaan. Untuk platform "non-DLL", perpustakaan dinamis dianggap sebagai target perpustakaan, dan untuk "platform DLL", tujuan eksekusi. Variabel semacam itu tidak disediakan untuk pustaka objek, karena pustaka semacam ini dihasilkan di dalam direktori CMakeFiles
.
Penting untuk dicatat bahwa semua platform berbasis Windows, termasuk Cygwin, dianggap sebagai "platform DLL".
Tata letak perpustakaan
Perintah target_link_libraries
perpustakaan atau dieksekusi dengan perpustakaan lain yang disediakan. Argumen pertama untuk perintah ini adalah nama target yang dihasilkan oleh perintah add_executable
atau add_library
, dan argumen selanjutnya adalah nama target pustaka atau jalur lengkap ke pustaka. Contoh:
Perlu dicatat bahwa pustaka modular tidak dapat ditautkan dengan file yang dapat dieksekusi atau pustaka lain, karena pustaka tersebut dimaksudkan hanya untuk memuat dengan teknik eksekusi.
Bekerja dengan sasaran
Seperti disebutkan dalam komentar, target dalam CMake juga tunduk pada manipulasi manual, namun sangat terbatas.
Dimungkinkan untuk mengontrol sifat-sifat target yang dirancang untuk mengatur proses perakitan proyek. Perintah get_target_property
nilai properti target ke variabel yang disediakan. Contoh ini menampilkan nilai properti C_STANDARD
dari target C_STANDARD
di layar:
Perintah set_target_properties
menetapkan properti target yang ditentukan ke nilai yang ditentukan. Perintah ini menerima daftar sasaran untuk nilai properti yang akan ditetapkan, dan kemudian kata kunci PROPERTIES
, diikuti oleh daftar formulir < > < >
:
Contoh di atas mengatur properti target MyTarget
yang mempengaruhi proses kompilasi, yaitu: ketika mengkompilasi target MyTarget
CMake akan MyTarget
kompiler untuk menggunakan standar C11. Semua penamaan properti target yang dikenal tercantum di halaman ini .
Dimungkinkan juga untuk memverifikasi target yang ditentukan sebelumnya menggunakan if(TARGET <TargetName>)
konstruksi:
Menambahkan Subproyek
Perintah add_subdirectory
meminta CMake untuk segera memproses file subproyek yang ditentukan. Contoh di bawah ini menunjukkan penerapan mekanisme yang dijelaskan:
Dalam contoh ini, argumen pertama ke perintah add_subdirectory
adalah subproyek add_subdirectory
, dan argumen kedua adalah opsional dan menginformasikan CMake tentang folder yang ditujukan untuk file yang dihasilkan dari subproyek yang disertakan (misalnya, CMakeCache.txt
dan cmake_install.cmake
).
Perlu dicatat bahwa semua variabel dari lingkup induk diwarisi oleh direktori yang ditambahkan, dan semua variabel yang didefinisikan dan didefinisikan ulang dalam direktori ini hanya akan terlihat olehnya (jika kata kunci PARENT_SCOPE
tidak ditentukan oleh argumen perintah yang set
). Fitur ini disebutkan dalam komentar di artikel sebelumnya .
Pencarian Paket
Perintah find_package
menemukan dan memuat pengaturan proyek eksternal. Dalam kebanyakan kasus, ini digunakan untuk menghubungkan perpustakaan eksternal berikutnya seperti Boost dan GSL . Contoh ini memanggil perintah yang dijelaskan untuk mencari perpustakaan GSL dan kemudian menautkan:
Dalam contoh di atas, perintah find_package
menerima nama paket sebagai argumen pertama, dan kemudian versi yang diperlukan. Opsi REQUIRED
membutuhkan pencetakan kesalahan fatal dan mengakhiri CMake jika paket yang diperlukan tidak ditemukan. Yang sebaliknya adalah opsi QUIET
, membutuhkan CMake untuk melanjutkan pekerjaannya, bahkan jika paket itu tidak ditemukan.
Selanjutnya, MyExecutable
ditautkan ke perpustakaan GSL dengan perintah target_link_libraries
menggunakan variabel GSL::gsl
, yang merangkum lokasi GSL yang sudah dikompilasi.
Pada akhirnya, perintah target_include_directories
, memberi tahu kompiler tentang lokasi file header perpustakaan GSL. Harap perhatikan bahwa variabel GSL_INCLUDE_DIRS
digunakan untuk GSL_INCLUDE_DIRS
lokasi header yang saya jelaskan (ini adalah contoh pengaturan paket yang diimpor).
Anda mungkin ingin memeriksa hasil pencarian paket jika Anda menentukan opsi QUIET
. Ini dapat dilakukan dengan memeriksa <PackageName>_FOUND
, yang secara otomatis ditentukan setelah perintah find_package
. Misalnya, jika Anda berhasil mengimpor pengaturan GSL ke proyek Anda, variabel GSL_FOUND
akan menjadi benar.
Secara umum, perintah find_package
memiliki dua rasa peluncuran: modular dan konfigurasi. Contoh di atas menerapkan bentuk modular. Ini berarti bahwa ketika perintah dipanggil, CMake mencari file skrip dari form Find<PackageName>.cmake
dalam direktori CMAKE_MODULE_PATH
, dan kemudian meluncurkannya dan mengimpor semua pengaturan yang diperlukan (dalam hal ini, CMake meluncurkan file FindGSL.cmake
standar).
Cara memasukkan header
Anda dapat memberi tahu kompilator tentang lokasi header yang disertakan dengan menggunakan dua perintah: include_directories
dan target_include_directories
. Anda memutuskan mana yang akan digunakan, namun ada baiknya mempertimbangkan beberapa perbedaan di antara mereka (ide tersebut disarankan dalam komentar ).
Perintah include_directories
memengaruhi cakupan direktori. Ini berarti bahwa semua direktori header yang ditentukan oleh perintah ini akan digunakan untuk semua tujuan CMakeLists.txt
saat ini, serta untuk subproyek yang diproses (lihat add_subdirectory
).
Perintah target_include_directories
memengaruhi target yang ditentukan oleh argumen pertama, dan tidak memengaruhi target lain. Contoh di bawah ini menunjukkan perbedaan antara dua perintah:
add_executable(RequestGenerator RequestGenerator.c) add_executable(ResponseGenerator ResponseGenerator.c)
Dalam komentar disebutkan bahwa dalam proyek modern penggunaan perintah include_directories
dan link_libraries
tidak diinginkan. Alternatifnya adalah perintah target_include_directories
dan target_link_libraries
yang hanya bertindak pada tujuan tertentu, dan bukan pada seluruh cakupan saat ini.
Instalasi Proyek
Perintah install
menghasilkan aturan instalasi untuk proyek Anda. Perintah ini mampu bekerja dengan sasaran, file, folder, dan lainnya. Pertama, pertimbangkan untuk menetapkan tujuan.
Untuk menetapkan tujuan, Anda harus meneruskan kata kunci TARGETS
sebagai argumen pertama dari fungsi yang dijelaskan, diikuti oleh daftar tujuan yang akan ditetapkan, dan kemudian kata kunci DESTINATION
dengan lokasi direktori di mana tujuan yang ditentukan akan ditetapkan. Contoh ini menunjukkan pengaturan sasaran yang khas:
Proses untuk menggambarkan instalasi file serupa, kecuali bahwa TARGETS
harus menentukan FILES
daripada kata kunci TARGETS
. Contoh yang menunjukkan pemasangan file:
Proses untuk menggambarkan pemasangan folder serupa, kecuali Anda harus menentukan DIRECTORY
alih-alih kata kunci FILES
. Penting untuk dicatat bahwa selama instalasi seluruh isi folder akan disalin, dan bukan hanya namanya. Contoh menginstal folder adalah sebagai berikut:
Setelah menyelesaikan pemrosesan CMake dari semua file Anda, Anda dapat menginstal semua objek yang dijelaskan dengan sudo checkinstall
(jika CMake menghasilkan Makefile
), atau Anda dapat melakukan tindakan ini dengan lingkungan pengembangan terintegrasi yang mendukung CMake.
Contoh visual proyek
Panduan ini tidak akan lengkap tanpa menunjukkan contoh nyata menggunakan sistem bangun CMake. Pertimbangkan diagram proyek sederhana menggunakan CMake sebagai satu-satunya sistem build:
+ MyProject - CMakeLists.txt - Defines.h - StartProgram.c + core - CMakeLists.txt - Core.h - ProcessInvoker.c - SystemManager.c
File assembly utama CMakeLists.txt
menjelaskan kompilasi seluruh program: pertama, perintah add_executable
untuk mengkompilasi file yang dapat dieksekusi, kemudian perintah add_subdirectory
, yang merangsang pemrosesan subproyek, dan akhirnya, file yang dapat dieksekusi dihubungkan ke perpustakaan yang dikompilasi:
File core/CMakeLists.txt
dipanggil oleh file assembly utama dan mengkompilasi pustaka statis MyProgramCore
dimaksudkan untuk menghubungkan dengan file yang dapat dieksekusi:
Setelah serangkaian perintah cmake . && make && sudo checkinstall
cmake . && make && sudo checkinstall
sistem build CMake selesai dengan sukses. Perintah pertama mulai memproses file CMakeLists.txt
di direktori root proyek, perintah kedua akhirnya mengkompilasi file biner yang diperlukan, dan perintah ketiga menginstal MyProgram
dikompilasi yang MyProgram
ke dalam sistem.
Kesimpulan
Sekarang Anda dapat menulis sendiri dan memahami file CMake orang lain, dan Anda dapat membaca secara detail tentang mekanisme lain di situs web resmi .
Artikel selanjutnya dalam panduan ini akan fokus pada pengujian dan pembuatan paket menggunakan CMake dan akan dirilis dalam seminggu. Sampai ketemu lagi!