aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Oyun Sunucusu

CMake Nedir? C++ Sunucu Projesini Derleme Rehberi

Çok dosyalı bir C++ sunucu projesini elle g++ ile derlemeye çalıştıysanız, komut satırının nasıl bir kâbusa dönüştüğünü bilirsiniz: onlarca .cpp dosyası, include yolları, harici kütüphaneler ve her değişiklikte baştan derlenen bir proje. İşte tam burada CMake nedir sorusu devreye giriyor. CMake, projenizi nasıl derleyeceğinizi tek bir tarif dosyasında tanımlamanızı sağlayan, platformdan bağımsız bir build sistemi üreticisidir. Bu yazıda bir oyun/sohbet sunucusu örneği üzerinden CMake'i sıfırdan kuracağız.

CMake nedir ve neden gerekir?

CMake doğrudan bir derleyici değildir. Yazdığınız CMakeLists.txt dosyasını okur ve sisteminize uygun gerçek build dosyalarını (Linux'ta genellikle Makefile, Windows'ta Visual Studio projeleri, isterseniz Ninja dosyaları) üretir. Yani CMake bir "meta build sistemi"dir: tek bir tarif yazarsınız, o tarif her platformda çalışır.

  • Taşınabilirlik: Aynı CMakeLists.txt Linux VPS'inizde de, geliştirme yaptığınız Windows makinesinde de çalışır.
  • Bağımlılık yönetimi: Hangi dosyanın hangisine bağlı olduğunu CMake takip eder; sadece değişen dosyaları yeniden derler.
  • Kütüphane bağlama: pthread, OpenSSL, Boost gibi kütüphaneleri tek satırla projeye dâhil edersiniz.

Sunucu projeleri tam olarak bu üç ihtiyaca sahiptir: çok dosya, harici kütüphane ve farklı ortamlarda derlenebilme. Bu yüzden ciddi bir C++ sunucusunda CMake neredeyse standarttır.

Örnek proje yapısı

Diyelim ki basit bir TCP sunucusu yazıyoruz. Dosyaları mantıklı klasörlere ayıralım; bu hem okunabilirlik hem de CMake yapılandırması için önemli.

server/
├── CMakeLists.txt
├── include/
│   └── server/
│       ├── Server.hpp
│       └── Connection.hpp
├── src/
│   ├── main.cpp
│   ├── Server.cpp
│   └── Connection.cpp
└── build/        (derleme çıktıları buraya gider)

Header dosyalarını include/, kaynak dosyalarını src/ altında tutmak yaygın bir düzendir. build/ klasörü ise CMake'in ürettiği geçici dosyalar içindir ve genellikle .gitignore'a eklenir.

İlk CMakeLists.txt dosyası

Şimdi kök dizine CMakeLists.txt yazalım. Her satırı ne yaptığıyla birlikte ele alacağım.

cmake_minimum_required(VERSION 3.16)
project(GameServer VERSION 1.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(server
    src/main.cpp
    src/Server.cpp
    src/Connection.cpp
)

target_include_directories(server PRIVATE include)

Satır satır bakalım:

  • cmake_minimum_required: Kullanmak istediğiniz en düşük CMake sürümünü belirtir. Modern özellikler için 3.16 makul bir tabandır.
  • project(...): Proje adını, sürümünü ve dilini (CXX = C++) tanımlar.
  • set(CMAKE_CXX_STANDARD 17): C++17 standardını kullanır. STANDARD_REQUIRED ON ile bu standart yoksa derleme hata verir, sessizce eskiye düşmez.
  • add_executable: server adında çalıştırılabilir bir hedef (target) oluşturur ve onu hangi kaynaklardan üreteceğini söyler.
  • target_include_directories: Derleyiciye header'ları include/ altında aramasını söyler. PRIVATE bu ayarın sadece bu hedefe ait olduğunu belirtir.

Projeyi derleme: out-of-source build

CMake ile derlemenin önerilen yolu, build dosyalarını kaynak ağacından ayrı tutmaktır. Bu yüzden ayrı bir build/ klasöründe çalışırız:

mkdir build
cd build
cmake ..
cmake --build .

cmake .. komutu üst klasördeki CMakeLists.txt'i okuyup build sistemini üretir (bu adıma configure denir). cmake --build . ise üretilen Makefile'ı ya da Ninja dosyasını çalıştırarak gerçek derlemeyi yapar. Bu komut platformdan bağımsızdır; doğrudan make çağırmaktan daha taşınabilirdir. Sonuçta build/ içinde server adlı çalıştırılabilir dosya oluşur.

Kütüphane bağlama ve modüllere ayırma

Sunucular nadiren tek başınadır. Çoğu zaman thread'ler (pthread), şifreleme (OpenSSL) veya başka kütüphaneler gerekir. CMake bunu find_package ve target_link_libraries ile çözer:

find_package(Threads REQUIRED)
target_link_libraries(server PRIVATE Threads::Threads)

find_package(Threads REQUIRED) sistemdeki thread kütüphanesini bulur; REQUIRED sayesinde bulunamazsa configure aşaması durur. Ardından Threads::Threads hedefini server'a bağlarız. Bu "modern CMake" yaklaşımıdır: kütüphaneleri çıplak isimle değil, hedef olarak bağlarsınız; böylece include yolları ve derleyici bayrakları otomatik gelir.

Projeniz büyüdükçe kodun bir kısmını ayrı bir kütüphaneye çıkarmak mantıklı olur. Örneğin ağ katmanını yeniden kullanılabilir bir kütüphane yapabilirsiniz:

add_library(netcore
    src/Server.cpp
    src/Connection.cpp
)
target_include_directories(netcore PUBLIC include)

add_executable(server src/main.cpp)
target_link_libraries(server PRIVATE netcore Threads::Threads)

Burada netcore bir kütüphane hedefidir ve PUBLIC include sayesinde, ona bağlanan herkes include/ yolunu otomatik miras alır. Bu, büyük projelerde tekrarı önleyen güçlü bir desendir.

Debug, Release ve pratik ipuçları

Sunucuyu geliştirirken hata ayıklama bilgisi, yayına alırken optimizasyon istersiniz. CMake bunu build türleriyle yönetir:

cmake -DCMAKE_BUILD_TYPE=Release ..

Debug sembolleri ekler ve optimizasyonu kapatır; Release ise -O2 gibi optimizasyonları açar. Birkaç pratik öneri:

  • Uyarıları açın: target_compile_options(server PRIVATE -Wall -Wextra) ile gizli hataları erken yakalarsınız.
  • build/ klasörünü her zaman .gitignore'a ekleyin; üretilen dosyaları sürüm kontrolüne sokmayın.
  • Daha hızlı derleme için Ninja kullanın: cmake -G Ninja .. tek satır fark eder ama paralel derlemede çok daha hızlıdır.

Sık Sorulan Sorular

CMake ile Make arasındaki fark nedir?

Make doğrudan bir build aracıdır ve Makefile'ları çalıştırır. CMake ise bu Makefile'ları (ya da Ninja, Visual Studio projeleri gibi başka formatları) sizin için üretir. Yani CMake daha üst seviyede, platformdan bağımsız çalışır; Make ise onun ürettiği çıktıyı işler.

Her dosyayı add_executable'a tek tek mi yazmalıyım?

Evet, en güvenilir yol budur. file(GLOB ...) ile dosyaları otomatik toplamak mümkün olsa da, yeni dosya eklediğinizde CMake bunu fark etmeyebilir. Kaynakları açıkça listelemek önerilen yaklaşımdır.

build klasörünü sürüm kontrolüne eklemeli miyim?

Hayır. build/ tamamen üretilen, makineye özel dosyalar içerir. Onu .gitignore'a ekleyin; herkes kendi makinesinde cmake .. ile yeniden üretebilir.

Sunucu projeniz için sağlam bir build kurulumuna mı ihtiyacınız var? İster sıfırdan CMake yapılandırması, ister mevcut bir C++ projesinin derlenmesi olsun, birlikte düzene sokabiliriz. Benimle iletişime geçin.

Bu kategorideki tüm yazılar →

Devamı için