Untuk apa CMake?
Menurut Wikipedia:
CMake adalah perangkat lunak [...] untuk mengelola proses pembangunan perangkat lunak menggunakan metode compiler-independent. Ini dirancang untuk mendukung hierarki direktori dan aplikasi yang bergantung pada banyak pustaka. Ini digunakan bersama dengan lingkungan build asli seperti make, Apple's Xcode, dan Microsoft Visual Studio.
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:
simple/
CMakeLists.txt
src/
tutorial.cxx
CMakeLists.txt
lib/
TestLib.cxx
TestLib.h
CMakeLists.txt
build/
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 jalankan cmake
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 root CMakeLists.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 root CMakeLists.txt
berada.
cd build
cmake ..
Secara default, ini mengatur semuanya menggunakan Makefiles seperti yang saya katakan. Berikut tampilan folder build sekarang:
simple/build/
CMakeCache.txt
cmake_install.cmake
Makefile
CMakeFiles/
(...)
src/
CMakeFiles/
(...)
cmake_install.cmake
Makefile
lib/
CMakeFiles/
(...)
cmake_install.cmake
Makefile
Apa semua file ini? Satu-satunya hal yang perlu Anda khawatirkan adalah Makefile dan folder proyek .
Perhatikan folder src/
dan lib/
. Ini telah dibuat karena simple/CMakeLists.txt
menunjuk ke sana menggunakan perintah add_subdirectory(<folder>)
. Perintah ini memberitahu CMake untuk melihat di folder mengatakan selama CMakeLists.txt
berkas dan mengeksekusi bahwa naskah, sehingga setiap subdirektori menambahkan cara ini harus memiliki CMakeLists.txt
berkas dalam. Dalam proyek ini, simple/src/CMakeLists.txt
menjelaskan cara membuat file yang dapat dieksekusi dan simple/lib/CMakeLists.txt
menjelaskan cara membuat pustaka. Setiap target yang CMakeLists.txt
dideskripsikan akan ditempatkan secara default di subdirektori di dalam pohon build. Jadi, setelah cepat
make
di konsol selesai dari build/
, beberapa file ditambahkan:
simple/build/
(...)
lib/
libTestLib.a
(...)
src/
Tutorial
(...)
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
:
cmake_minimum_required(VERSION 2.6)
project(Tutorial)
# Add all subdirectories in this project
add_subdirectory(lib)
add_subdirectory(src)
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 di CMakeLists.txt
dalam, yang kemudian akan dijalankan sebelum melanjutkan. Ngomong-ngomong, jika Anda kebetulan memiliki fungsi CMake yang ditentukan, Anda dapat menggunakannya dari CMakeLists.txt
subdirektori lain, tetapi Anda harus menentukannya sebelum Anda menggunakan add_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
:
add_library(TestLib TestLib.cxx)
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 menulis add_library(TestLib TestLib.cxx foo.cxx)
. Ini juga berfungsi untuk file di direktori lain, misalnya add_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
:
#include <stdio.h>
void test() {
printf("testing...\n");
}
simple/lib/TestLib.h
:
#ifndef TestLib
#define TestLib
void test();
#endif
simple/src/CMakeLists.txt
:
# Name the executable and all resources it depends on directly
add_executable(Tutorial tutorial.cxx)
# Link to needed libraries
target_link_libraries(Tutorial TestLib)
# Tell CMake where to look for the .h files
target_include_directories(Tutorial PUBLIC ${CMAKE_SOURCE_DIR}/lib)
Perintah ini add_executable()
bekerja persis sama add_library()
, kecuali, tentu saja, ini akan menghasilkan file yang dapat dieksekusi. Eksekusi ini sekarang dapat dirujuk sebagai target untuk hal-hal seperti target_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 karena target_include_directories()
perintah, lib/TestLib.h
tidak akan ditemukan saat menyusun Tutorial, sehingga seluruh lib/
folder ditambahkan ke direktori include yang akan dicari #includes. Anda mungkin juga melihat perintah include_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
:
#include <stdio.h>
#include "TestLib.h"
int main (int argc, char *argv[])
{
test();
fprintf(stdout, "Main\n");
return 0;
}
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 bawah lib/
dan src/
dan hanya menambahkan sesuatu seperti add_executable(Tutorial src/tutorial.cxx)
untuk simple/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 melakukan c
konfigurasi setelah selesai dengan perubahan dan kemudian g
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 dengan simple/build/
, tetapi jika Anda menjalankan cmake simple/
dari folder seperti foo/bar/etc/
, semua referensi ke CMAKE_BINARY_DIR
dalam build tree itu akan menjadi /foo/bar/etc
.
CMAKE_CURRENT_SOURCE_DIR
: Direktori tempat arus CMakeLists.txt
masuk. Artinya, ia berubah seluruhnya: mencetak ini dari simple/CMakeLists.txt
hasil /simple
, dan mencetaknya dari simple/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 lokasi CMakeLists.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 dalam simple/build/lib/
. Tidak ada file .h di sana; paling banyak yang akan Anda temukan libTestLib.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 adalah CMAKE_CXX_FLAGS_DEBUG
mana yang akan digunakan sebagai gantinya jika CMAKE_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, mengaturnya bin/
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 dalam CMakeLists.txt
file melalui set(CMAKE_BUILD_TYPE <type>)
atau dengan memanggil CMake dari konsol dengan flag yang sesuai, misalnya cmake -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
:
project (Tutorial)
# Setting variables
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 1)
# Configure_file(<input> <output>)
# Copies a file <input> to file <output> and substitutes variable values referenced in the file content.
# So you can pass some CMake variables to the source code (in this case version numbers)
configure_file (
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
"${PROJECT_SOURCE_DIR}/src/TutorialConfig.h"
)
simple/TutorialConfig.h.in
:
// Configured options and settings
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
File yang dihasilkan dihasilkan oleh CMake, simple/src/TutorialConfig.h
:
// Configured options and settings
#define Tutorial_VERSION_MAJOR 1
#define Tutorial_VERSION_MINOR 1
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.