CMake ile Proje Yönetimi
Şimdiye kadar programları muhtemelen tek bir g++ main.cpp -o main komutuyla derledin. Küçük projeler için bu yeterli. Ama proje büyüyünce — 10 dosya, 5 kütüphane, farklı platformlar — bu yaklaşım çöker. İşte CMake tam bu noktada devreye girer.
CMake'i bir "derleme tarifi" yazma aracı olarak düşün. Bir restoran zinciri düşün: her şubede farklı fırın ve ocak var ama tarif aynı. CMake de aynı şekilde — sen tarifi yazarsın (CMakeLists.txt), CMake hangi platformda olursan ol uygun derleme komutlarını üretir.
CMake Nedir, Neden Makefile Yerine CMake?
CMake bir build system generator'dır. Doğrudan derleme yapmaz — derleme için gerekli dosyaları (Makefile, Ninja build dosyaları, Visual Studio projeleri...) üretir.
Makefile'ın sorunları:
Platform bağımlı (Windows'ta farklı, Linux'ta farklı)
Karmaşık söz dizimi
Kütüphane bulmak elle yapılır
Büyük projelerde yönetimi kabus
CMake'in avantajları:
Tek bir
CMakeLists.txtile tüm platformlarda çalışırKütüphaneleri otomatik bulur (
find_package)Modern, okunabilir söz dizimi
Endüstri standardı (Qt, OpenCV, LLVM, Unreal Engine... hepsi CMake kullanır)
CMakeLists.txt
│
┌──────────┼──────────┐
▼ ▼ ▼
Makefile Ninja VS Project
(Linux) (Linux) (Windows)
│ │ │
▼ ▼ ▼
g++ / clang ninja MSVCCMakeLists.txt — Temel Yapı
Her CMake projesi bir CMakeLists.txt dosyasıyla başlar. Bu dosya projenin "tarif defteri"dir.
Minimal Örnek
Önce basit bir proje yapısı:
projem/
├── CMakeLists.txt
└── main.cppmain.cpp:
#include <iostream>
int main() {
std::cout << "Merhaba CMake!\n";
return 0;
}CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(MerhabaCMake LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(merhaba main.cpp)Bu beş satır ne yapıyor:
`cmake_minimum_required`: Projenin gerektirdiği minimum CMake sürümü. Eski sürümlerde uyumsuzluk olmasın diye.
`project`: Projenin adı ve dili.
LANGUAGES CXXC++ demek.`set(CMAKE_CXX_STANDARD 17)`: C++17 standardını kullan.
`set(CMAKE_CXX_STANDARD_REQUIRED ON)`: C++17 desteği yoksa hata ver (düşürme).
`add_executable`:
merhabaadlı çalıştırılabilir dosyayımain.cpp'den oluştur.
Derleme Adımları
# Proje dizininde
mkdir build
cd build
cmake .. # CMakeLists.txt'yi isleyip Makefile uret
cmake --build . # Derlemeyi baslat (veya sadece make)
./merhaba # Calistirİlk cmake .. komutu yapılandırma yapar (configure), cmake --build . derleme yapar (build).
💡 `cmake --build .` komutu platform bağımsızdır. Linux'ta
make, Windows'tamsbuildçağırır. Her zaman bu komutu tercih et.
Out-of-Source Build — Build Dizini
Yukarıda build dizini oluşturduk. Bu "out-of-source build" denir ve çok önemli bir pratiktir. Kaynak dosyalar ile derleme çıktıları ayrı dizinlerde tutulur.
Neden önemli?
Kaynak kodun temiz kalır —
.o,.a,Makefilegibi dosyalar build dizinindebuilddizinini silmek temiz bir başlangıç sağlarFarklı konfigürasyonlar için farklı build dizinleri oluşturabilirsin
# Debug build
mkdir build-debug && cd build-debug
cmake -DCMAKE_BUILD_TYPE=Debug ..
# Release build
mkdir build-release && cd build-release
cmake -DCMAKE_BUILD_TYPE=Release ..Debug build'de optimizasyon kapalıdır ve debug bilgisi eklenir (-g). Release build'de optimizasyon açıktır (-O2 veya -O3).
⚠️ Asla kaynak dizinde `cmake .` çalıştırma. Oluşan dosyalar kaynak kodunla karışır ve temizlemesi zordur. Her zaman ayrı bir
builddizini kullan.
Çoklu Dosyalı Proje Yapısı
Gerçek projelerde tek bir .cpp dosyası olmaz. CMake ile birden fazla dosyayı yönetmek kolaydır.
hesap-makinesi/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ ├── hesaplayici.cpp
│ └── hesaplayici.h
└── build/src/hesaplayici.h:
#pragma once
class Hesaplayici {
public:
double topla(double a, double b);
double cikar(double a, double b);
double carp(double a, double b);
double bol(double a, double b);
};src/hesaplayici.cpp:
#include "hesaplayici.h"
#include <stdexcept>
double Hesaplayici::topla(double a, double b) { return a + b; }
double Hesaplayici::cikar(double a, double b) { return a - b; }
double Hesaplayici::carp(double a, double b) { return a * b; }
double Hesaplayici::bol(double a, double b) {
if (b == 0.0) throw std::runtime_error("Sifira bolme!");
return a / b;
}src/main.cpp:
#include <iostream>
#include "hesaplayici.h"
int main() {
Hesaplayici h;
std::cout << "3 + 5 = " << h.topla(3, 5) << "\n";
std::cout << "10 / 3 = " << h.bol(10, 3) << "\n";
return 0;
}CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(HesapMakinesi LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(hesap
src/main.cpp
src/hesaplayici.cpp
)
# Header dosyalarinin bulunabilmesi icin
target_include_directories(hesap PRIVATE src)add_executable içine tüm .cpp dosyalarını listeliyorsun. target_include_directories ise derleyiciye header dosyalarını nerede arayacağını söyler.
Kütüphane Oluşturma
Büyük projelerde kodu kütüphanelere ayırmak yaygındır:
cmake_minimum_required(VERSION 3.16)
project(HesapMakinesi LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Statik kutuphane olustur
add_library(hesap_lib STATIC
src/hesaplayici.cpp
)
target_include_directories(hesap_lib PUBLIC src)
# Calistirilabilir dosya
add_executable(hesap src/main.cpp)
# Kutuphaney baglа
target_link_libraries(hesap PRIVATE hesap_lib)add_library bir kütüphane oluşturur:
STATIC: Statik kütüphane (
.a/.lib)SHARED: Dinamik kütüphane (
.so/.dll)
target_link_libraries ile çalıştırılabilir dosyaya kütüphaneyi bağlarsın.
target_link_libraries — Bağımlılık Yönetimi
target_link_libraries, bir hedefin (target) hangi kütüphanelere bağımlı olduğunu belirtir. Üç erişim düzeyi vardır:
| Düzey | Anlamı |
|---|---|
PUBLIC | Bu hedef ve onu kullananlar için geçerli |
PRIVATE | Sadece bu hedef için geçerli |
INTERFACE | Sadece onu kullananlar için geçerli |
# hesap_lib PUBLIC include dizinine sahip
# hesap_lib'i kullanan herkes de bu include'u gorur
target_include_directories(hesap_lib PUBLIC src)
# pthread PRIVATE bagimlilik
# hesap sadece kendi icinde pthread kullanir
target_link_libraries(hesap PRIVATE pthread)Pratikte çoğu durumda PRIVATE yeterlidir. PUBLIC sadece kütüphane yazarken, dışarıya header expose ediyorsan gerekir.
find_package ile Kütüphane Ekleme
Sistem kütüphanelerini veya üçüncü parti kütüphaneleri bulmak için find_package kullanılır. CMake, bilinen kütüphaneler için hazır "find module"leri içerir.
cmake_minimum_required(VERSION 3.16)
project(ThreadOrnek LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Threads kutuphanesini bul
find_package(Threads REQUIRED)
add_executable(program main.cpp)
target_link_libraries(program PRIVATE Threads::Threads)REQUIRED bayrağı, kütüphane bulunamazsa CMake'in hata vermesini sağlar. Threads::Threads bir "imported target"tır — kütüphanenin tüm bilgilerini (include path, linker flags) taşır.
Popüler kütüphaneler ve CMake'teki adları:
find_package(Boost REQUIRED COMPONENTS filesystem system)
find_package(OpenCV REQUIRED)
find_package(fmt REQUIRED)
find_package(GTest REQUIRED)target_link_libraries(program PRIVATE
Boost::filesystem
opencv_core
fmt::fmt
GTest::gtest_main
)💡 Modern CMake "target-based" yaklaşımı kullanır. Eski
include_directories()velink_libraries()gibi global komutlar yerinetarget_include_directories()vetarget_link_libraries()kullan. "Target" başına bağımlılık net ve temizdir.
Derleyici Uyarıları ve Seçenekleri
CMake ile derleyici uyarılarını proje genelinde etkinleştirebilirsin:
add_executable(program main.cpp)
# Derleyici uyarilari
target_compile_options(program PRIVATE
-Wall -Wextra -Wpedantic
)
# Debug modda sanitizer ekle
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_options(program PRIVATE -fsanitize=address)
target_link_options(program PRIVATE -fsanitize=address)
endif()CMake Değişkenleri ile Konfigürasyon
# Secenekler
option(TESTLERI_DERLE "Test dosyalarini derle" OFF)
if(TESTLERI_DERLE)
add_executable(testler test/test_main.cpp)
target_link_libraries(testler PRIVATE hesap_lib)
endif()# Testleri aktif ederek derle
cmake -DTESTLERI_DERLE=ON ..Tam Bir Proje Örneği
Şimdiye kadar öğrendiklerimizi birleştiren tam bir proje:
proje/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ ├── matematik.cpp
│ └── matematik.h
└── build/cmake_minimum_required(VERSION 3.16)
project(MatematikApp
VERSION 1.0.0
LANGUAGES CXX
DESCRIPTION "Basit matematik kutuphanesi"
)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # IDE destegi icin
# Kutuphane
add_library(matematik STATIC src/matematik.cpp)
target_include_directories(matematik PUBLIC src)
target_compile_options(matematik PRIVATE -Wall -Wextra)
# Calistirilabilir
add_executable(app src/main.cpp)
target_link_libraries(app PRIVATE matematik)
target_compile_options(app PRIVATE -Wall -Wextra)
# Bilgi mesaji
message(STATUS "Proje: ${PROJECT_NAME} v${PROJECT_VERSION}")
message(STATUS "Build tipi: ${CMAKE_BUILD_TYPE}")mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
./appCMAKE_EXPORT_COMPILE_COMMANDS seçeneği compile_commands.json dosyası üretir. Bu dosya, VS Code, CLion gibi IDE'lerin kodu analiz etmesi ve otomatik tamamlama yapması için kullanılır.
Özet
CMake, platform bağımsız bir build system generator'dır.
CMakeLists.txtyazarsın, CMake platforma uygun derleme dosyalarını üretir.Temel komutlar:
cmake_minimum_required,project,add_executable,add_library,target_link_libraries,target_include_directories.Out-of-source build her zaman kullan:
mkdir build && cd build && cmake ... Kaynak kodunu temiz tut.target_link_libraries ile bağımlılıkları hedefe bağla.
PRIVATE/PUBLIC/INTERFACEerişim düzeyleriyle kapsamı kontrol et.find_package ile sistem ve üçüncü parti kütüphaneleri bul.
REQUIREDbayrağı ile bulunamazsa hata ver.Modern CMake "target-based" yaklaşım kullanır. Global komutlar (
include_directories,link_libraries) yerinetarget_önekli komutları tercih et.
AI Asistan
Sorularını yanıtlamaya hazır