CMake adalah generator build system lintas platform—alih-alih menulis Makefile manual untuk Linux dan .vcxproj untuk Windows, kita menulis satu CMakeLists.txt yang dapat menghasilkan Makefile, Ninja, atau Visual Studio project. CMake juga mengelola dependency, library search, dan platform check secara otomatis. Bab ini menyusun perintah CMake yang paling sering kita pakai untuk membangun program C.
Perintah Dasar #
| Perintah | Kegunaan |
|---|---|
cmake_minimum_required(VERSION 3.16) | Wajib di awal—minimum versi CMake |
project(name C) | Deklarasi nama proyek dan bahasa |
set(VAR value) | Set variabel |
message(STATUS "text") | Cetak pesan status |
option(NAME "desc" ON) | Opsi konfigurasi ON/OFF |
if(COND) ... elseif() ... else() ... endif() | Kondisional |
foreach(var IN LISTS list1) ... endforeach() | Loop |
while(COND) ... endwhile() | Loop while |
include(file) | Sertakan file CMake lain |
add_subdirectory(dir) | Tambah direktori subproyek |
find_package(Name) | Cari library eksternal |
Target dan Build #
| Perintah | Kegunaan |
|---|---|
add_executable(name src1.c src2.c) | Definisi executable |
add_library(name STATIC src...) | Library statik .a |
add_library(name SHARED src...) | Library shared .so/.dll |
add_library(name MODULE src...) | Plugin yang di-load saat runtime |
add_library(name INTERFACE) | Header-only library |
target_sources(name PRIVATE src...) | Tambah source ke target |
target_link_libraries(name PUBLIC lib) | Link library ke target |
target_include_directories(name PUBLIC dir) | Tambah include path |
target_compile_options(name PRIVATE -Wall) | Tambah flag compiler |
target_compile_definitions(name PRIVATE NAME=val) | Definisikan macro -D |
target_link_directories(name PUBLIC dir) | Tambah path library |
target_link_options(name PRIVATE -flto) | Tambah flag linker |
Visibility Keyword #
Perintah target_* menerima visibility keyword PRIVATE, PUBLIC, atau INTERFACE. Perbedaannya:
| Keyword | Target sendiri | Dependents |
|---|---|---|
PRIVATE | Ya | Tidak |
PUBLIC | Ya | Ya |
INTERFACE | Tidak | Ya |
Sebagai contoh, jika library libfoo memakai pthread secara internal tetapi tidak mengeksposnya di header, gunakan PRIVATE. Jika libfoo header memakai tipe dari bar.h, gunakan PUBLIC agar dependents juga mendapatkan include bar.h.
Variabel Bawaan #
| Variabel | Isi |
|---|---|
CMAKE_C_STANDARD | Standar C yang dipakai (11, 17, 23) |
CMAKE_C_STANDARD_REQUIRED | ON = standar wajib tersedia |
CMAKE_C_EXTENSIONS | ON = pakai ekstensi (gnu11), OFF = iso (c11) |
CMAKE_BUILD_TYPE | Debug, Release, RelWithDebInfo, MinSizeRel |
CMAKE_C_COMPILER | Path compiler C |
CMAKE_SOURCE_DIR | Direktori source root |
CMAKE_BINARY_DIR | Direktori build |
CMAKE_CURRENT_SOURCE_DIR | Direktori source saat ini |
CMAKE_INSTALL_PREFIX | Prefix install (/usr/local default) |
PROJECT_NAME | Nama proyek dari project() |
Variabel Build Type #
Setiap CMAKE_BUILD_TYPE mengaktifkan flag otomatis:
| Build Type | Flag tipikal |
|---|---|
Debug | -O0 -g |
Release | -O3 -DNDEBUG |
RelWithDebInfo | -O2 -g -DNDEBUG |
MinSizeRel | -Os -DNDEBUG |
Program Demo #
Program berikut sama dengan demo Makefile—main.c memakai util.c dan util.h. Kode sumbernya valid dan teruji.
/* File: main.c - Demo CMake */
#include <stdio.h>
#include "util.h"
int main(void) {
cetak_salam("Budi");
printf("2 + 3 = %d\n", tambah(2, 3));
return 0;
}/* File: util.h */
#ifndef UTIL_H
#define UTIL_H
void cetak_salam(const char *nama);
int tambah(int a, int b);
#endif/* File: util.c */
#include <stdio.h>
#include "util.h"
void cetak_salam(const char *nama) {
printf("Halo, %s!\n", nama);
}
int tambah(int a, int b) { return a + b; }CMakeLists.txt Minimal #
Berikut CMakeLists.txt minimal yang meng-compile program demo menjadi executable cmdemo:
cmake_minimum_required(VERSION 3.16)
project(cmdemo C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
add_executable(cmdemo main.c util.c)
target_compile_options(cmdemo PRIVATE -Wall -Wextra -g)
install(TARGETS cmdemo RUNTIME DESTINATION bin)Langkah Build Standar #
CMake mengikuti pola “out-of-source build”—kita menjalankan CMake di direktori build terpisah sehingga source tree tetap bersih.
mkdir build && cd build
cmake ..
make
./cmdemoOutput yang Dihasilkan (langkah cmake .. menghasilkan ringkasan konfigurasi, make menjalankan compiler, lalu program dijalankan):
-- 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/gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/cc/test/cmdemo/build
[ 33%] Building C object CMakeFiles/cmdemo.dir/main.c.o
[ 66%] Building C object CMakeFiles/cmdemo.dir/util.c.o
[100%] Linking C executable cmdemo
[100%] Built target cmdemo
Halo, Budi!
2 + 3 = 5Mari kita telaah baris-baris CMakeLists.txt di atas:
- Baris 1 (
cmake_minimum_required(VERSION 3.16)): Wajib di awal file. CMake versi 3.16 (rilis 2019) cukup untuk fitur modern seperti generator expression dantarget_*commands. Versi yang lebih tua mungkin tidak mendukung sintaks terbaru. - Baris 2 (
project(cmdemo C)): Mendeklarasikan nama proyek dan bahasa. ParameterCmemberi tahu CMake untuk hanya mengaktifkan compiler C, bukan C++. Tanpa parameter bahasa, CMake default mendeteksi keduanya. - Baris 4-6 (
set(CMAKE_C_STANDARD 11)dst.): Mengatur standar C secara global.CMAKE_C_STANDARD_REQUIRED ONmemastikan compiler benar-benar mendukung standar tersebut—jika tidak, build gagal.CMAKE_C_EXTENSIONS OFFmemakai mode ISO (mis.c11alih-alihgnu11). - Baris 8 (
add_executable(cmdemo main.c util.c)): Membuat target executable bernamacmdemodari dua file source. Nama target sekaligus menjadi nama file executable yang dihasilkan. - Baris 9 (
target_compile_options(cmdemo PRIVATE -Wall -Wextra -g)): Hanya targetcmdemoyang mendapat flag ini. Jika ada target lain (mis. unit test), flag ini tidak ikut—menggunakanPUBLICakan menyebar ke dependents. - Baris 11 (
install(TARGETS cmdemo RUNTIME DESTINATION bin)): Mendeklarasikan target instalasi. Saat kita menjalankanmake install, executable akan dipasang ke${CMAKE_INSTALL_PREFIX}/bin.
Find Package dan Library Eksternal #
Untuk library seperti libm, zlib, atau pthread, gunakan find_package atau find_library:
find_library(MATH_LIBRARY m)
target_link_libraries(cmdemo PRIVATE ${MATH_LIBRARY})
# Atau, untuk pthread:
find_package(Threads REQUIRED)
target_link_libraries(cmdemo PRIVATE Threads::Threads)
# Untuk zlib:
find_package(ZLIB REQUIRED)
target_link_libraries(cmdemo PRIVATE ZLIB::ZLIB)Multi-Configuration Generator #
Beberapa generator (Visual Studio, Xcode, Ninja Multi-Config) mendukung multi-configuration—kita bisa memilih build type saat build, bukan saat configure.
cmake -G "Ninja Multi-Config" ..
cmake --build . --config Release
cmake --build . --config DebugUntuk generator single-config (Unix Makefiles), set CMAKE_BUILD_TYPE saat configure:
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake -DCMAKE_BUILD_TYPE=Debug ..