Pada Chapter sebelumnya kita mengompilasi proyek dua file .cpp dengan tiga perintah g++ berturut-turut. Bayangkan jika proyek berisi 50 file: kita harus mengetik puluhan perintah dan mengulang semuanya setiap kali ada satu file berubah. Build system mengatasi masalah ini dengan mengotomatiskan kompilasi dan mengelola dependensi antar file. CMake adalah build system paling populer di ekosistem C++; hampir semua library C++ modern (Boost, OpenCV, LLVM) memakai CMake. Pada Chapter ini kita akan mempelajari struktur dasar CMakeLists.txt, membangun proyek multi-file, dan menerapkan beberapa best practices yang akan dipakai sepanjang Course.
Mengapa Perlu CMake #
Beberapa alasan memilih CMake sebagai build system:
- Lintas platform: konfigurasi yang sama menghasilkan Makefile di Linux, Ninja file di macOS, dan Visual Studio solution di Windows.
- Deteksi compiler dan library: CMake dapat menemukan compiler yang terpasang, mendeteksi versi standar C++, dan mencari library eksternal melalui mekanisme
find_package. - Incremental build: hanya file yang berubah yang dikompilasi ulang, bukan seluruh proyek.
- Standar industri: mayoritas proyek C++ open source memakai CMake, sehingga kita dapat mengintegrasikan library pihak ketiga dengan mudah.
| Tugas | Tanpa CMake | Dengan CMake |
|---|---|---|
| Kompilasi 1 file | g++ -c file.cpp -o file.o | cmake --build . |
| Kompilasi 50 file | 50 baris perintah | Satu perintah |
| Ganti compiler | Edit tiap perintah | Ubah satu variabel |
| Tambah compiler flag | Edit tiap perintah | Satu tempat di CMakeLists.txt |
| Distribusi library | Manual | install() otomatis |
Memasang CMake #
CMake tersedia di hampir semua sistem operasi:
# Linux (Debian/Ubuntu)
sudo apt install cmake
# macOS (Homebrew)
brew install cmake
# Windows (Scoop)
scoop install cmakeVerifikasi pemasangan:
cmake --versionOutput yang Dihasilkan (contoh):
cmake version 3.30.2
CMake suite maintained and supported by Kitware (kitware.com/cmake).Versi minimal yang direkomendasikan untuk Course ini adalah CMake 3.16 (memiliki dukungan C++17 yang matang). Pada contoh di atas, versi 3.30 jauh melampaui kebutuhan.
Struktur CMakeLists.txt Minimum #
Setiap proyek CMake dimulai dengan satu berkas CMakeLists.txt di root proyek. Berikut contoh minimum:
cmake_minimum_required(VERSION 3.16)
project(dsa_demo
VERSION 1.0.0
LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_executable(dsa_demo main.cpp)Penjelasan tiap baris:
cmake_minimum_required(VERSION 3.16): menentukan versi minimum CMake. Versi lebih lama mungkin tidak mendukung beberapa perintah.project(dsa_demo VERSION 1.0.0 LANGUAGES CXX): mendeklarasikan nama proyek, versi, dan bahasa yang dipakai.CXXadalah kode CMake untuk C++.set(CMAKE_CXX_STANDARD 17): menetapkan standar C++17 untuk seluruh target di file ini. Setara dengan flag-std=c++17.set(CMAKE_CXX_STANDARD_REQUIRED ON): memaksa compiler mendukung standar yang ditetapkan. Jika tidak, konfigurasi gagal.set(CMAKE_CXX_EXTENSIONS OFF): menonaktifkan ekstensi compiler (mis. GNU extensions). Kode menjadi portable antar GCC, Clang, dan MSVC.add_executable(dsa_demo main.cpp): mendefinisikan target executable bernamadsa_demodari source filemain.cpp.
Proyek Multi-File #
Pada Chapter Proses Kompilasi kita membangun proyek dengan main_pipeline.cpp dan math_utils.cpp. Sekarang kita akan mengelola proyek serupa dengan CMake. Struktur folder yang dipakai:
statistik/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ ├── stat_utils.hpp
│ └── stat_utils.cpp
└── build/ (dibuat CMake, jangan commit ke VCS)Source File Proyek #
Berikut isi tiga file source yang dipakai. Header guard #ifndef ... #endif pada stat_utils.hpp mencegah double inclusion:
// File: src/stat_utils.hpp
#ifndef STAT_UTILS_HPP
#define STAT_UTILS_HPP
#include <vector>
long long hitungTotal(const std::vector<int>& data);
double hitungRataRata(const std::vector<int>& data);
int cariMaksimum(const std::vector<int>& data);
#endif// File: src/stat_utils.cpp
#include "stat_utils.hpp"
long long hitungTotal(const std::vector<int>& data) {
long long total = 0;
for (int v : data) {
total += v;
}
return total;
}
double hitungRataRata(const std::vector<int>& data) {
if (data.empty()) return 0.0;
return static_cast<double>(hitungTotal(data)) / static_cast<double>(data.size());
}
int cariMaksimum(const std::vector<int>& data) {
if (data.empty()) return 0;
int maks = data[0];
for (size_t i = 1; i < data.size(); ++i) {
if (data[i] > maks) maks = data[i];
}
return maks;
}// File: src/main.cpp
#include <iostream>
#include <vector>
#include "stat_utils.hpp"
int main() {
std::vector<int> data = {85, 92, 78, 90, 65};
std::cout << "--- Statistik ---\n";
std::cout << "Total : " << hitungTotal(data) << "\n";
std::cout << "Rata-rata : " << hitungRataRata(data) << "\n";
std::cout << "Maksimum : " << cariMaksimum(data) << "\n";
return 0;
}CMakeLists.txt untuk Proyek Multi-File #
cmake_minimum_required(VERSION 3.16)
project(statistik
VERSION 1.0.0
LANGUAGES CXX)
# Standar C++ yang dipakai seluruh target
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Default ke build type Release jika belum diset
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
# Aktifkan peringatan compiler untuk seluruh target berikut
add_compile_options(-Wall -Wextra)
# Definisikan executable beserta source file-nya
add_executable(statistik
src/main.cpp
src/stat_utils.cpp
)
# Tambahkan src/ sebagai include directory untuk target ini
target_include_directories(statistik PRIVATE src)Bedah Kode CMakeLists.txt #
add_executable(statistik src/main.cpp src/stat_utils.cpp): mendefinisikan target executablestatistikdari dua file source. Kita bisa menambah file lain kemudian dengan mendaftarkannya di sini.target_include_directories(statistik PRIVATE src): menambah direktorisrc/ke path include untuk targetstatistik. Dengan ini,#include "stat_utils.hpp"dapat menemukan file tanpa perlu path relatif penuh.PRIVATEberarti direktori ini hanya dipakai untuk targetstatistik, tidak diteruskan ke target lain yang mungkin menautkannya nanti.add_compile_options(-Wall -Wextra): menambah flag compiler untuk seluruh target yang didefinisikan setelah baris ini. Setara dengan flag yang kita pakai pada Chapter sebelumnya.if(NOT CMAKE_BUILD_TYPE) ... endif(): memastikan default build type adalahRelease(optimasi diaktifkan) ketika pengguna tidak menentukan build type lain saat konfigurasi.
Melakukan Build #
Konfigurasi CMake dilakukan dalam dua tahap: configure (membuat file build) dan build (menjalankan compiler). Direkomendasikan menggunakan folder build/ terpisah agar file build tidak mencemari folder source.
# Dari root proyek (folder yang berisi CMakeLists.txt)
cmake -S . -B build
cmake --build buildPenjelasan:
-S .: direktori source (current directory).-B build: direktori output build (akan dibuat jika belum ada).cmake --build build: menjalankan compiler sesuai file build yang sudah dibuat pada tahap sebelumnya.
Setelah build berhasil, jalankan binary hasilnya:
./build/statistikOutput yang Dihasilkan:
--- Statistik ---
Total : 410
Rata-rata : 82
Maksimum : 92Output tersebut identik dengan output yang dihasilkan kompilasi langsung dengan g++ pada Chapter Proses Kompilasi. CMake mengotomatiskan tiga perintah g++ sebelumnya menjadi satu perintah cmake --build.
Variabel dan Target #
CMake menyediakan beberapa perintah untuk mengelola variabel dan target:
| Perintah | Kegunaan | Contoh |
|---|---|---|
set(NAMA nilai) | Menetapkan variabel | set(VERSION 1.0.0) |
target_compile_definitions() | Menambah -D define | target_compile_definitions(statistik PRIVATE DEBUG=1) |
target_compile_options() | Menambah flag compiler | target_compile_options(statistik PRIVATE -O3) |
target_link_libraries() | Menautkan library | target_link_libraries(statistik PRIVATE mylib) |
option(NAMA "deskripsi" ON/OFF) | Pilihan konfigurasi boolean | option(BUILD_TESTS "Aktifkan testing" OFF) |
Contoh Penggunaan Variabel #
option(ENABLE_DEBUG_LOG "Aktifkan log debug" OFF)
if(ENABLE_DEBUG_LOG)
target_compile_definitions(statistik PRIVATE DEBUG_LOG=1)
message(STATUS "Debug logging diaktifkan")
endif()Pengguna dapat mengatur opsi saat configure:
cmake -S . -B build -DENABLE_DEBUG_LOG=ONBest Practices CMake #
Beberapa praktik yang akan dipakai sepanjang Course:
- Pisahkan folder
build/: jangan pernah configure di root source; file build akan mencemari struktur. - Pakai
target_*alih-alihadd_*global:target_include_directories,target_compile_options, dantarget_link_librarieslebih terkontrol daripadainclude_directoriesdanadd_compile_options. - Set
CMAKE_CXX_STANDARDdi root: satu sumber kebenaran untuk standar C++. - Jangan pakai
file(GLOB ...)untuk source list: CMake tidak akan mendeteksi penambahan file baru secara otomatis. Daftar file secara eksplisit padaadd_executable(). - Pakai
CMAKE_BUILD_TYPE: pilihDebug,Release,RelWithDebInfo, atauMinSizeRelsesuai kebutuhan. - Tambah
install()rule jika berbagi library: untuk Course, kita jarang memerlukan ini, tetapi penting untuk proyek nyata.
Integrasi dengan Editor #
VS Code dengan ekstensi CMake Tools mengintegrasikan CMake langsung ke editor. Setelah memasang ekstensi, kita dapat:
- Memilih preset build (Debug/Release) dari status bar.
- Menjalankan configure dan build lewat Command Palette.
- Men-debug target lewat tombol Run and Debug yang otomatis memilih executable.
File .vscode/settings.json dapat memetakan preset CMake ke konfigurasi editor:
{
"cmake.buildDirectory": "${workspaceFolder}/build",
"cmake.configureOnOpen": true,
"cmake.defaultVariants": {
"buildType": {
"default": "Release",
"choices": {
"Debug": { "short": "Debug", "buildType": "Debug" },
"Release": { "short": "Release", "buildType": "Release" }
}
}
}
}Ringkasan #
Pada Chapter ini kita telah mempelajari dasar CMake:
- Peran CMake: mengotomatiskan kompilasi multi-file, lintas platform.
- Struktur
CMakeLists.txt: daricmake_minimum_requiredhinggaadd_executable. - Variabel global:
CMAKE_CXX_STANDARD,CMAKE_BUILD_TYPE. - Perintah
target_*: cara modern mengelola flag dan dependency per target. - Best practices: hindari
file(GLOB), pisahkan folderbuild/, pakaitarget_*.
CMake akan menjadi alat yang dipakai pada Chapter proyek di Section akhir Course. Untuk sebagian besar Chapter DSA, kita akan tetap memakai kompilasi langsung dengan g++ karena lebih cepat untuk file tunggal. Pada Section berikutnya, kita akan masuk ke Fondasi C++ untuk DSA: variabel, tipe data, operator, hingga template dan memory management.