CMake adalah build system generator — bukan build system itu sendiri. CMake membaca file CMakeLists.txt dan menghasilkan file build (Makefile di Linux, project file Visual Studio di Windows, file Xcode di macOS). Pendekatan ini membuat satu CMakeLists.txt bisa dipakai di banyak platform tanpa modifikasi. Mayoritas proyek C/C++ modern (LLVM, OpenCV, Boost, KDE) memakai CMake. Pada chapter ini kita akan menulis CMakeLists.txt minimal, mengonfigurasi build, dan mengamati bagaimana CMake menghasilkan Makefile di balik layar.
CMakeLists.txt Minimal #
Struktur proyek sama dengan chapter sebelumnya: dua file C dan satu header. Kita tambah CMakeLists.txt:
greet.h, greet.c -- library greet
main.c -- program utama
CMakeLists.txt -- script CMakeBerikut CMakeLists.txt minimal untuk proyek ini:
cmake_minimum_required(VERSION 3.10)
project(greet-demo C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
add_executable(app main.c greet.c)
target_compile_options(app PRIVATE -Wall -Wextra)Mari kita telaah baris-baris CMakeLists.txt di atas:
- Baris 1 (
cmake_minimum_required(VERSION 3.10)): mensyaratkan CMake versi minimum 3.10. Bila versi CMake lebih lama, CMake akan menolak dengan error. Flag ini melindungi proyek dari perubahan perilaku antar versi CMake. - Baris 2 (
project(greet-demo C)): mendefinisikan nama proyekgreet-demodan bahasaC. CMake akan mencari compiler C yang sesuai (gccatauclang). Bila kita juga punya kode C++, sebutkanC CXX. - Baris 4 (
set(CMAKE_C_STANDARD 11)): menetapkan standar C yang dipakai ke C11. VariabelCMAKE_C_STANDARDmenyebabkan CMake menambahkan flag-std=c11(atau-std=gnu11bilaCMAKE_C_EXTENSIONSaktif) ke command line compiler. - Baris 5 (
set(CMAKE_C_STANDARD_REQUIRED ON)): memaksa compiler mendukung C11. Bila compiler tidak mendukung C11, konfigurasi gagal. Tanpa flag ini, compiler yang tidak mendukung C11 akan diam-diam fallback ke standar lawas. - Baris 7 (
add_executable(app main.c greet.c)): mendeklarasikan target executable bernamaappyang dibangun darimain.cdangreet.c. CMake otomatis mengompilasi tiap.cmenjadi.o, lalu men-link semuanya menjadiapp. - Baris 9 (
target_compile_options(app PRIVATE -Wall -Wextra)): menambahkan flag-Wall -Wextrake targetapp. KeywordPRIVATEberarti flag hanya berlaku untuk target ini (tidak diturunkan ke target lain yang men-linkapp). Alternatif:PUBLIC(flag diturunkan) atauINTERFACE(flag hanya diturunkan, tidak dipakai internal).
Konfigurasi dan Build #
CMake memisahkan dua tahap: configure (membaca CMakeLists.txt, mendeteksi compiler, menghasilkan Makefile) dan build (menjalankan Makefile). Pola standar adalah out-of-source build — file build diletakkan di subdirektori, tidak mencampur source:
cmake -B buildOutput yang Dihasilkan:
-- The C compiler identification is GNU 14.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done (0.1s)
-- Generating done (0.0s)
-- Build files have been written to: /tmp/test_cmake/buildMari kita telaah baris-baris output konfigurasi di atas:
-- The C compiler identification is GNU 14.2.0: CMake mengidentifikasi compiler C yang tersedia di sistem (di sini GCC 14.2.0). CMake menguji compiler dengan mengompilasi file C kecil dan memeriksa output__GNUC__macro.-- Detecting C compiler ABI info: CMake mendeteksi ABI target (32-bit/64-bit, calling convention). Informasi ini dipakai untuk menentukan flag seperti-m64atau path library yang benar.-- Check for working C compiler: /usr/bin/cc - skipped: CMake memverifikasi compiler bisa menghasilkan executable.-skippedmenandakan verifikasi sudah dilakukan di tahap sebelumnya (caching hasil).-- Detecting C compile features: CMake menguji fitur compiler — misalnya apakah compiler mendukung C11_Static_assert,_Generic, atau<stdatomic.h>. Hasil tes disimpan diCMakeCache.txtagar tidak perlu diulang.-- Configuring done (0.1s): konfigurasi selesai tanpa error. Semua target, variabel, dan dependensi sudah diproses.-- Generating done (0.0s): file build (Makefile untuk Unix Makefiles generator) sudah ditulis ke direktoribuild/.-- Build files have been written to: /tmp/test_cmake/build: konfirmasi path output build.
Tahap kedua adalah build:
cmake --build buildOutput yang Dihasilkan:
[ 33%] Building C object CMakeFiles/app.dir/main.c.o
[ 66%] Building C object CMakeFiles/app.dir/greet.c.o
[100%] Linking C executable app
[100%] Built target appOutput ini adalah output Makefile yang dihasilkan CMake. Persentase [ 33%], [ 66%], [100%] adalah fitur Makefile CMake yang menampilkan progress build. Mari kita jalankan executable:
./build/appOutput yang Dihasilkan:
Halo Budi!
Halo Siti!Mengamati Makefile yang Dihasilkan #
CMake dengan Unix Makefiles generator (default di Linux) menghasilkan build/Makefile yang bisa kita periksa:
head -30 build/MakefileOutput yang Dihasilkan:
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 4.4
# Default target executed when no arguments are given to make.
default_target: all
.PHONY : default_target
# Allow only one "make -f Makefile2" at a time, but pass parallelism.
.NOTPARALLEL:
#=============================================================================
# Special targets provided by cmake.
# Disable implicit rules so canonical targets will work.
.SUFFIXES:
# Disable VCS-based implicit rules.
% : %,vHeader # CMAKE generated file: DO NOT EDIT! menandakan file ini dihasilkan otomatis — bila kita mengubahnya manual, perubahan akan ditimpa saat cmake dijalankan ulang. Konvensi: jangan edit file build CMake secara langsung, edit CMakeLists.txt lalu jalankan cmake -B build ulang.
compile_commands.json untuk IDE #
CMake bisa menghasilkan compile_commands.json — database yang berisi command line kompilasi tiap file. File ini dipakai oleh clangd, VSCode C/C++ extension, dan IDE lain untuk fitur autocomplete dan go-to-definition:
cmake -B build_cc -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
head -20 build_cc/compile_commands.jsonOutput yang Dihasilkan:
[
{
"directory": "/tmp/test_cmake/build_cc",
"command": "/usr/bin/cc -std=gnu11 -Wall -Wextra -o CMakeFiles/app.dir/main.c.o -c /tmp/test_cmake/main.c",
"file": "/tmp/test_cmake/main.c",
"output": "CMakeFiles/app.dir/main.c.o"
},
{
"directory": "/tmp/test_cmake/build_cc",
"command": "/usr/bin/cc -std=gnu11 -Wall -Wextra -o CMakeFiles/app.dir/greet.c.o -c /tmp/test_cmake/greet.c",
"file": "/tmp/test_cmake/greet.c",
"output": "CMakeFiles/app.dir/greet.c.o"
}
]Setiap entry memiliki directory (cwd saat kompilasi), command (command line compiler lengkap), file (path absolut source), dan output (path object file). Editor seperti VSCode memakai file untuk mencocokkan source yang sedang kita edit, lalu menjalankan command di background untuk memperoleh preprocessor info yang akurat untuk fitur autocomplete.
Build Configuration #
CMake mendukung beberapa build type: Debug, Release, RelWithDebInfo, MinSizeRel. Kita atur lewat variabel CMAKE_BUILD_TYPE saat konfigurasi:
cmake -B build_release -DCMAKE_BUILD_TYPE=Release
cmake --build build_releaseOutput yang Dihasilkan:
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done (0.1s)
-- Generating done (0.0s)
-- Build files have been written to: /tmp/test_cmake/build_release
[ 33%] Building C object CMakeFiles/app.dir/main.c.o
[ 66%] Building C object CMakeFiles/app.dir/greet.c.o
[100%] Linking C executable app
[100%] Built target appBuild type menentukan flag compiler default — Release menambah -O3 -DNDEBUG, Debug menambah -O0 -g, RelWithDebInfo menambah -O2 -g -DNDEBUG. Kita akan membahas perbedaan flag ini lebih detail pada chapter Build Configurations.