Sangat sulit untuk mendapatkan informasi yang berguna tentang CMake sebagai pemula. Sejauh ini, saya telah melihat beberapa tutorial tentang cara menyiapkan beberapa proyek yang sangat mendasar atau lainnya. Namun, tidak satupun dari ini menjelaskan alasan di balik apa pun yang ditampilkan di dalamnya, selalu meninggalkan banyak lubang untuk diisi.
Apa memanggil CMake pada CMakeLists berarti ? Apakah itu seharusnya dipanggil sekali per membangun pohon atau apa? Bagaimana cara menggunakan pengaturan berbeda untuk setiap build jika semuanya menggunakan file CMakeLists.txt yang sama dari sumber yang sama? Mengapa setiap subdirektori membutuhkan file CMakeListsnya sendiri? Apakah masuk akal untuk menggunakan CMake di CMakeLists.txt selain yang ada di root proyek? Jika ya, dalam kasus apa? Apa perbedaan antara menentukan cara membuat file yang dapat dieksekusi atau pustaka dari file CMakeLists di subdirektori mereka sendiri dengan melakukannya di file CMakeLists di root semua sumber? Dapatkah saya membuat proyek untuk Eclipse dan yang lainnya untuk Visual Studio, hanya mengubah -G
opsi saat memanggil CMake? Apakah itu cara penggunaannya?
Tak satu pun dari tutorial, halaman dokumentasi, atau pertanyaan / jawaban yang sejauh ini saya lihat memberikan wawasan yang berguna untuk memahami cara menggunakan CMake. Contoh-contohnya tidak menyeluruh. Tidak peduli tutorial apa yang saya baca, saya merasa seperti kehilangan sesuatu yang penting.
Ada banyak pertanyaan yang diajukan oleh pemula CMake seperti saya yang tidak menanyakan hal ini secara eksplisit, tetapi itu menjelaskan fakta bahwa, sebagai newbs, kami tidak tahu bagaimana menangani CMake atau apa yang membuatnya.
Jawaban:
Untuk apa CMake?
Menurut Wikipedia:
Dengan CMake, Anda tidak perlu lagi mempertahankan setelan terpisah khusus untuk lingkungan kompiler / build Anda. Anda memiliki satu konfigurasi, dan itu berfungsi untuk banyak lingkungan.
CMake dapat membuat solusi Microsoft Visual Studio, proyek Eclipse, atau labirin Makefile dari file yang sama tanpa mengubah apa pun di dalamnya.
Dengan adanya sekumpulan direktori dengan kode di dalamnya, CMake mengelola semua dependensi, perintah pembuatan, dan tugas lain yang perlu diselesaikan oleh proyek Anda sebelum dapat dikompilasi. Itu TIDAK benar-benar mengkompilasi apa pun. Untuk menggunakan CMake, Anda harus memberitahukannya (menggunakan file konfigurasi yang disebut CMakeLists.txt) executable apa yang perlu Anda kompilasi, library apa yang mereka tautkan, direktori apa yang ada di proyek Anda dan apa yang ada di dalamnya, serta detail apa pun seperti flag. atau apa pun yang Anda butuhkan (CMake cukup kuat).
Jika ini sudah diatur dengan benar, Anda kemudian menggunakan CMake untuk membuat semua file yang "lingkungan build asli" pilihan Anda perlu melakukan tugasnya. Di Linux, secara default, ini berarti Makefiles. Jadi begitu Anda menjalankan CMake, itu akan membuat banyak file untuk digunakan sendiri ditambah beberapa
Makefile
. Yang perlu Anda lakukan selanjutnya adalah mengetikkan "make" di konsol dari folder root setiap kali Anda selesai mengedit kode Anda, dan bam, file executable yang dikompilasi dan ditautkan dibuat.Bagaimana cara kerja CMake? Apa fungsinya?
Berikut adalah contoh pengaturan proyek yang akan saya gunakan di seluruh:
Isi setiap file akan ditampilkan dan dibahas nanti.
CMake mengatur proyek Anda sesuai dengan root
CMakeLists.txt
proyek Anda, dan melakukannya di direktori apa pun yang Anda jalankancmake
dari dalam konsol. Melakukan ini dari folder yang bukan root proyek Anda menghasilkan apa yang disebut build out-of-source , yang berarti file yang dibuat selama kompilasi (file obj, file lib, executable, Anda tahu) akan ditempatkan di folder tersebut , disimpan terpisah dari kode sebenarnya. Ini membantu mengurangi kekacauan dan lebih disukai untuk alasan lain juga, yang tidak akan saya bahas.Saya tidak tahu apa yang terjadi jika Anda mengeksekusi
cmake
selain rootCMakeLists.txt
.Dalam contoh ini, karena saya ingin semuanya ditempatkan di dalam
build/
folder, pertama-tama saya harus menavigasi ke sana, lalu meneruskan CMake direktori tempat rootCMakeLists.txt
berada.Secara default, ini mengatur semuanya menggunakan Makefiles seperti yang saya katakan. Berikut tampilan folder build sekarang:
Apa semua file ini? Satu-satunya hal yang perlu Anda khawatirkan adalah Makefile dan folder proyek .
Perhatikan folder
src/
danlib/
. Ini telah dibuat karenasimple/CMakeLists.txt
menunjuk ke sana menggunakan perintahadd_subdirectory(<folder>)
. Perintah ini memberitahu CMake untuk melihat di folder mengatakan selamaCMakeLists.txt
berkas dan mengeksekusi bahwa naskah, sehingga setiap subdirektori menambahkan cara ini harus memilikiCMakeLists.txt
berkas dalam. Dalam proyek ini,simple/src/CMakeLists.txt
menjelaskan cara membuat file yang dapat dieksekusi dansimple/lib/CMakeLists.txt
menjelaskan cara membuat pustaka. Setiap target yangCMakeLists.txt
dideskripsikan akan ditempatkan secara default di subdirektori di dalam pohon build. Jadi, setelah cepatdi konsol selesai dari
build/
, beberapa file ditambahkan:Proyek dibangun, dan dapat dieksekusi siap untuk dieksekusi. Apa yang Anda lakukan jika Anda ingin file yang dapat dieksekusi diletakkan di folder tertentu? Tetapkan variabel CMake yang sesuai, atau ubah properti target tertentu . Lebih lanjut tentang variabel CMake nanti.
Bagaimana cara memberi tahu CMake cara membangun proyek saya?
Berikut adalah isi dari setiap file di direktori sumber:
simple/CMakeLists.txt
:Versi minimum yang diperlukan harus selalu disetel, sesuai dengan peringatan yang diberikan CMake jika Anda tidak melakukannya. Gunakan apa pun versi CMake Anda.
Nama proyek Anda dapat digunakan nanti, dan menunjukkan fakta bahwa Anda dapat mengelola lebih dari satu proyek dari file CMake yang sama. Saya tidak akan membahasnya.
Seperti yang disebutkan sebelumnya,
add_subdirectory()
menambahkan folder ke proyek, yang berarti CMake mengharapkannya memiliki diCMakeLists.txt
dalam, yang kemudian akan dijalankan sebelum melanjutkan. Ngomong-ngomong, jika Anda kebetulan memiliki fungsi CMake yang ditentukan, Anda dapat menggunakannya dariCMakeLists.txt
subdirektori lain, tetapi Anda harus menentukannya sebelum Anda menggunakanadd_subdirectory()
atau tidak akan menemukannya. CMake lebih pintar tentang pustaka, jadi ini kemungkinan satu-satunya saat Anda akan mengalami masalah seperti ini.simple/lib/CMakeLists.txt
:Untuk membuat perpustakaan Anda sendiri, Anda memberinya nama dan kemudian daftar semua file yang dibuat. Mudah. Jika diperlukan file lain
foo.cxx
,, untuk dikompilasi, Anda akan menulisadd_library(TestLib TestLib.cxx foo.cxx)
. Ini juga berfungsi untuk file di direktori lain, misalnyaadd_library(TestLib TestLib.cxx ${CMAKE_SOURCE_DIR}/foo.cxx)
. Lebih lanjut tentang variabel CMAKE_SOURCE_DIR nanti.Hal lain yang dapat Anda lakukan dengan ini adalah menentukan bahwa Anda menginginkan perpustakaan bersama. Contoh:
add_library(TestLib SHARED TestLib.cxx)
. Jangan takut, di sinilah CMake mulai membuat hidup Anda lebih mudah. Baik itu dibagikan atau tidak, sekarang yang perlu Anda tangani untuk menggunakan pustaka yang dibuat dengan cara ini adalah nama yang Anda berikan di sini. Nama library ini sekarang TestLib, dan Anda dapat mereferensikannya dari mana saja dalam project. CMake akan menemukannya.Apakah ada cara yang lebih baik untuk membuat daftar dependensi? Pasti ya . Lihat di bawah untuk lebih lanjut tentang ini.
simple/lib/TestLib.cxx
:simple/lib/TestLib.h
:simple/src/CMakeLists.txt
:Perintah ini
add_executable()
bekerja persis samaadd_library()
, kecuali, tentu saja, ini akan menghasilkan file yang dapat dieksekusi. Eksekusi ini sekarang dapat dirujuk sebagai target untuk hal-hal sepertitarget_link_libraries()
. Karena tutorial.cxx menggunakan kode yang ditemukan di pustaka TestLib, Anda menunjukkan ini ke CMake seperti yang ditunjukkan.Demikian pula, file .h apa pun yang # disertakan oleh sumber apa pun
add_executable()
yang tidak ada dalam direktori yang sama dengan sumber harus ditambahkan. Jika bukan karenatarget_include_directories()
perintah,lib/TestLib.h
tidak akan ditemukan saat menyusun Tutorial, sehingga seluruhlib/
folder ditambahkan ke direktori include yang akan dicari #includes. Anda mungkin juga melihat perintahinclude_directories()
yang bertindak dengan cara yang sama, kecuali bahwa Anda tidak perlu menentukan target karena langsung menetapkannya secara global, untuk semua file yang dapat dieksekusi. Sekali lagi, saya akan menjelaskan CMAKE_SOURCE_DIR nanti.simple/src/tutorial.cxx
:Perhatikan bagaimana file "TestLib.h" disertakan. Tidak perlu menyertakan jalur lengkap: CMake menangani semua itu di balik layar berkat
target_include_directories()
.Secara teknis, di pohon sumber yang sederhana seperti ini dapat Anda lakukan tanpa
CMakeLists.txt
s bawahlib/
dansrc/
dan hanya menambahkan sesuatu sepertiadd_executable(Tutorial src/tutorial.cxx)
untuksimple/CMakeLists.txt
. Terserah Anda dan kebutuhan proyek Anda.Apa lagi yang harus saya ketahui untuk menggunakan CMake dengan benar?
(Topik AKA relevan dengan pemahaman Anda)
Menemukan dan menggunakan paket : Jawaban atas pertanyaan ini menjelaskannya lebih baik daripada yang pernah saya bisa.
Mendeklarasikan variabel dan fungsi, menggunakan aliran kontrol, dll .: Lihat tutorial ini yang menjelaskan dasar-dasar dari apa yang ditawarkan CMake, serta menjadi pengantar yang baik secara umum.
Variabel CMake : ada banyak, jadi yang berikut ini adalah kursus kilat untuk membawa Anda ke jalur yang benar. Wiki CMake adalah tempat yang baik untuk mendapatkan informasi yang lebih mendalam tentang variabel dan juga hal-hal lain.
Anda mungkin ingin mengedit beberapa variabel tanpa membangun kembali pohon build. Gunakan ccmake untuk ini (ini mengedit
CMakeCache.txt
file). Ingatlah untuk melakukanc
konfigurasi setelah selesai dengan perubahan dan kemudiang
enerate makefiles dengan konfigurasi yang diperbarui.Baca tutorial yang direferensikan sebelumnya untuk mempelajari tentang menggunakan variabel, tetapi cerita singkatnya:
set(<variable name> value)
mengubah atau membuat variabel.${<variable name>}
untuk menggunakannya.CMAKE_SOURCE_DIR
: Direktori root sumber. Dalam contoh sebelumnya, ini selalu sama dengan/simple
CMAKE_BINARY_DIR
: Direktori root build. Dalam contoh sebelumnya, ini sama dengansimple/build/
, tetapi jika Anda menjalankancmake simple/
dari folder sepertifoo/bar/etc/
, semua referensi keCMAKE_BINARY_DIR
dalam build tree itu akan menjadi/foo/bar/etc
.CMAKE_CURRENT_SOURCE_DIR
: Direktori tempat arusCMakeLists.txt
masuk. Artinya, ia berubah seluruhnya: mencetak ini darisimple/CMakeLists.txt
hasil/simple
, dan mencetaknya darisimple/src/CMakeLists.txt
hasil/simple/src
.CMAKE_CURRENT_BINARY_DIR
: Anda mendapatkan idenya. Jalur ini tidak hanya bergantung pada folder tempat build berada, tetapi juga pada lokasiCMakeLists.txt
skrip saat ini.Mengapa ini penting? File sumber jelas tidak akan ada di pohon build. Jika Anda mencoba sesuatu seperti
target_include_directories(Tutorial PUBLIC ../lib)
pada contoh sebelumnya, jalur tersebut akan relatif terhadap pohon build, artinya akan seperti menulis${CMAKE_BINARY_DIR}/lib
, yang akan melihat ke dalamsimple/build/lib/
. Tidak ada file .h di sana; paling banyak yang akan Anda temukanlibTestLib.a
. Anda ingin${CMAKE_SOURCE_DIR}/lib
sebagai gantinya.CMAKE_CXX_FLAGS
: Tanda untuk diteruskan ke kompilator, dalam hal ini kompilator C ++. Juga perlu diperhatikan adalahCMAKE_CXX_FLAGS_DEBUG
mana yang akan digunakan sebagai gantinya jikaCMAKE_BUILD_TYPE
disetel ke DEBUG. Ada lebih banyak yang seperti ini; lihat wiki CMake .CMAKE_RUNTIME_OUTPUT_DIRECTORY
: Beri tahu CMake di mana harus meletakkan semua file executable saat dibuat. Ini adalah pengaturan global. Anda dapat, misalnya, mengaturnyabin/
dan meletakkan semuanya dengan rapi di sana.EXECUTABLE_OUTPUT_PATH
serupa, tetapi usang, jika Anda tersandung padanya.CMAKE_LIBRARY_OUTPUT_DIRECTORY
: Demikian juga, pengaturan global untuk memberi tahu CMake di mana harus meletakkan semua file perpustakaan.Properti target : Anda dapat menyetel properti yang hanya memengaruhi satu target, baik itu yang dapat dieksekusi atau pustaka (atau arsip ... Anda mendapatkan idenya). Berikut adalah contoh yang bagus tentang cara menggunakannya (dengan
set_target_properties()
.Apakah ada cara mudah untuk menambahkan sumber ke target secara otomatis? Gunakan GLOB untuk mencantumkan semua yang ada di direktori tertentu di bawah variabel yang sama. Contoh sintaksnya adalah
FILE(GLOB <variable name> <directory>/*.cxx)
.Bisakah Anda menentukan jenis build yang berbeda? Ya, meskipun saya tidak yakin tentang cara kerjanya atau batasannya. Ini mungkin memerlukan beberapa if / then'ning, tetapi CMake memang menawarkan beberapa dukungan dasar tanpa mengkonfigurasi apa pun, seperti default untuk
CMAKE_CXX_FLAGS_DEBUG
, misalnya. Anda dapat menyetel jenis build Anda dari dalamCMakeLists.txt
file melaluiset(CMAKE_BUILD_TYPE <type>)
atau dengan memanggil CMake dari konsol dengan flag yang sesuai, misalnyacmake -DCMAKE_BUILD_TYPE=Debug
.Ada contoh bagus dari proyek yang menggunakan CMake? Wikipedia memiliki daftar proyek sumber terbuka yang menggunakan CMake, jika Anda ingin memeriksanya. Tutorial online sejauh ini mengecewakan saya dalam hal ini, namun pertanyaan Stack Overflow ini memiliki pengaturan CMake yang cukup keren dan mudah dipahami. Layak untuk dilihat.
Menggunakan variabel dari CMake dalam kode Anda : Berikut adalah contoh cepat dan kotor (diadaptasi dari beberapa tutorial lain ):
simple/CMakeLists.txt
:simple/TutorialConfig.h.in
:File yang dihasilkan dihasilkan oleh CMake,
simple/src/TutorialConfig.h
:Dengan penggunaan cerdas ini, Anda dapat melakukan hal-hal keren seperti mematikan perpustakaan dan semacamnya. Saya merekomendasikan untuk melihat tutorial itu karena ada beberapa hal yang sedikit lebih maju yang pasti akan sangat berguna pada proyek yang lebih besar, cepat atau lambat.
Untuk yang lainnya, Stack Overflow penuh dengan pertanyaan spesifik dan jawaban singkat, yang bagus untuk semua orang kecuali yang belum tahu.
sumber
make
bash untuk membuat proyek Anda.