CMake Dosyalarına Giriş

CMake Dosyalarına Giriş

CMake dosyaları, bir yazılım projesinin nasıl yapılandırılacağını, derleneceğini, test edileceğini ve paketleneceğini açıklayan metin dosyalarıdır. Ana dosya genellikle CMakeLists.txt adını taşır; CMake bu dosyayı okuyarak Make, Ninja, Visual Studio veya Xcode gibi araçların ihtiyaç duyduğu derleme dosyalarını üretir.

CMake Ne Yapar?

CMake genellikle kodunuzu doğrudan derleyen araç değildir. Bunun yerine bir derleme sistemi üreticisi olarak davranır: projenizin açıklamasını okur ve platformunuzun derleme aracının ihtiyaç duyduğu yerel dosyaları oluşturur.

Bu sayede tek bir CMake projesi, her ortam için derleme kurulumunu yeniden yazmaya gerek kalmadan Windows, macOS ve Linux üzerinde çalışabilir.

CMake Dosyaları Ne İşe Yarar?

Bir CMake dosyası derleme sistemine şunları söyler:

  • Hangi kaynak dosyaların derleneceğini.
  • Hangi kütüphanelerin veya yürütülebilir dosyaların oluşturulacağını.
  • Kullanıcıların açıp kapatabileceği seçenekleri.
  • Hangi bağımlılıkların aranacağını.
  • Test, kurulum kuralları ve paketlemenin nasıl yönetileceğini.

Bu sayede derleme mantığı tek bir yerde tutulur; farklı platformlar veya IDE'ler için ayrı ayrı çoğaltılmak zorunda kalınmaz.

İnsanlar Neden CMake Kullanır?

En büyük neden taşınabilirliktir. Derleme kurallarını bir kez yazarsınız; CMake bunları farklı işletim sistemlerindeki farklı araçlar için proje dosyalarına dönüştürür.

Büyük projeler için de kullanışlıdır çünkü şunları destekler:

  • Kaynak dışı (out-of-source) derlemeler.
  • Bağımlılık tespiti.
  • İsteğe bağlı özellikler.
  • Özel kod üretimi.
  • Paylaşımlı ve statik kütüphaneler.
  • Test ve paketleme.

Yaygın Dosyalar

DosyaAmaç
CMakeLists.txtAna proje talimatları dosyası
*.cmakeYeniden kullanılabilir yardımcı dosyalar, modüller, paket yapılandırması
CMakePresets.jsonPaylaşılabilir yapılandırma/derleme/test ön ayarları
cmake/ klasörüProjeye özgü .cmake yardımcı dosyaları

Basit Örnek

Çok küçük bir CMake projesi genellikle şöyle görünür:

cmake_minimum_required(VERSION 3.20)
project(HelloWorld)

add_executable(hello main.cpp)

Bu şunu söyler: belirli bir CMake sürümü gerektirir, projeyi adlandırır ve main.cpp'den hello adında bir yürütülebilir dosya oluşturur. CMake'in platformunuz için doğru derleme dosyalarını üretmesi için bu kadarı yeterlidir.


Derleme Hattı

CMake'in genel iş akışına nasıl uyduğunu anlamak karışıklığı önler:

Kaynak kodunuz + CMakeLists.txt
          │
          │  cmake ..          ← Yapılandırma adımı
          ▼
   Derleme sistemi dosyaları
   (Makefile / .sln / build.ninja)
          │
          │  cmake --build .   ← Derleme adımı
          ▼
   Derlenmiş ikili dosyalar
   (hello, libfoo.a, libbar.so)
          │
          │  ctest             ← Test adımı (isteğe bağlı)
          ▼
   Test sonuçları
          │
          │  cmake --install . ← Kurulum adımı (isteğe bağlı)
          ▼
   Kurulu dosyalar

Her zaman kaynak dışı derleyin — üretilen dosyaları kaynak ağacınızdan uzak tutun:

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

Bu sayede git clean kaynağınıza dokunmadan üretilen her şeyi temizler.


Temel Komutlar

cmake_minimum_required

cmake_minimum_required(VERSION 3.20)

Her zaman bunu en başa koyun. Projenizin hangi özelliklere dayandığını belirtir ve eski CMake sürümlerinin sessizce hatalı sonuçlar üretmesini önler.

project

project(MyApp VERSION 1.2.3 LANGUAGES CXX C)

Proje adını, sürümünü ve dillerini tanımlar. CMake listelenen her dil için derleyicileri tespit eder. Sürüme ${PROJECT_VERSION} ile erişilebilir.

add_executable

add_executable(myapp main.cpp utils.cpp parser.cpp)

Listelenen kaynak dosyalardan bir ikili yürütülebilir dosya oluşturur.

add_library

add_library(mylib STATIC foo.cpp bar.cpp)   # .a / .lib
add_library(mylib SHARED foo.cpp bar.cpp)   # .so / .dll
add_library(mylib OBJECT foo.cpp bar.cpp)   # yalnızca derlenmiş nesneler, arşiv yok

target_link_libraries

target_link_libraries(myapp PRIVATE mylib)

myapp'i mylib'e bağlar. Anahtar kelime yayılımı kontrol eder:

Anahtar KelimeAnlam
PRIVATEYalnızca myapp, mylib'e bağlanır
PUBLICmyapp ve myapp'e bağlanan her şey mylib'i alır
INTERFACEYalnızca myapp'in tüketicileri mylib'i alır, myapp'in kendisi almaz

target_include_directories

target_include_directories(mylib PUBLIC include/)

include/ dizinini başlık arama yolu olarak kullanılabilir hale getirir. PUBLIC, mylib'e bağlanan her hedefin bu include yolunu otomatik olarak alacağı anlamına gelir.

target_compile_options

target_compile_options(myapp PRIVATE -Wall -Wextra -O2)

Belirli bir hedefe derleyici bayrakları iletir. Global olarak uygulayan eski add_compile_options() yerine bunu tercih edin.


Değişkenler

set(MY_VAR "merhaba")
message(STATUS "Değer: ${MY_VAR}")

CMake değişkenleri string veya listedir. Listeler dahili olarak noktalı virgülle ayrılır:

set(SOURCES main.cpp foo.cpp bar.cpp)
# Eşdeğeri: "main.cpp;foo.cpp;bar.cpp"

add_executable(myapp ${SOURCES})

Faydalı Yerleşik Değişkenler

DeğişkenAçıklama
CMAKE_SOURCE_DIRKaynak ağacının kökü
CMAKE_BINARY_DIRDerleme ağacının kökü
CMAKE_CURRENT_SOURCE_DIRMevcut CMakeLists.txt'nin kaynak dizini
PROJECT_NAMEproject() ile belirlenen ad
PROJECT_VERSIONproject() ile belirlenen sürüm
CMAKE_BUILD_TYPEDebug, Release, RelWithDebInfo, MinSizeRel
CMAKE_CXX_STANDARDC++ standardı: 11, 14, 17, 20, 23
BUILD_SHARED_LIBSON ise add_library() varsayılan olarak SHARED kullanır

Önbellek Değişkenleri

Önbellek değişkenleri CMake çalıştırmaları arasında kalıcıdır ve cmake-gui veya ccmake içinde görünür:

option(ENABLE_TESTS "Birim testleri derle" ON)

if(ENABLE_TESTS)
    add_subdirectory(tests)
endif()

Kullanıcılar yapılandırma sırasında bunları geçersiz kılabilir:

cmake .. -DENABLE_TESTS=OFF

Gerçek Dünya Proje Yapısı

MyProject/
├── CMakeLists.txt          ← kök
├── CMakePresets.json
├── cmake/
│   └── FindFoo.cmake       ← özel find modülü
├── include/
│   └── mylib/
│       └── api.h
├── src/
│   ├── CMakeLists.txt      ← kütüphane hedefi
│   ├── foo.cpp
│   └── bar.cpp
├── apps/
│   ├── CMakeLists.txt      ← yürütülebilir hedef
│   └── main.cpp
└── tests/
    ├── CMakeLists.txt      ← test hedefi
    └── test_foo.cpp

Kök CMakeLists.txt:

cmake_minimum_required(VERSION 3.20)
project(MyProject VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

option(BUILD_TESTS "Testleri derle" ON)

add_subdirectory(src)
add_subdirectory(apps)

if(BUILD_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()

src/CMakeLists.txt:

add_library(mylib STATIC foo.cpp bar.cpp)

target_include_directories(mylib PUBLIC
    $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)

target_compile_options(mylib PRIVATE -Wall -Wextra)

apps/CMakeLists.txt:

add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE mylib)

Bağımlılık Bulma

find_package

Bir kütüphane bulmak için alışılagelmiş yöntem:

find_package(OpenSSL REQUIRED)
target_link_libraries(myapp PRIVATE OpenSSL::SSL OpenSSL::Crypto)

REQUIRED, paket bulunamazsa CMake'in hata vermesini sağlar. Modern CMake paketleri ham OPENSSL_LIBRARIES değişkenleri yerine içe aktarılmış hedefler (OpenSSL::SSL gibi) sunar — içe aktarılmış hedefleri tercih edin.

Yaygın Paketler ve Hedefleri

PaketHedef
OpenSSLOpenSSL::SSL, OpenSSL::Crypto
ThreadsThreads::Threads
zlibZLIB::ZLIB
BoostBoost::filesystem, Boost::system, …
fmtfmt::fmt
GTestGTest::gtest, GTest::gtest_main

FetchContent — Bağımlılıkları Otomatik İndirme

Kütüphaneleri sistem genelinde kurmaya gerek yok; CMake onları yapılandırma sırasında indirebilir:

include(FetchContent)

FetchContent_Declare(
    googletest
    GIT_REPOSITORY https://github.com/google/googletest.git
    GIT_TAG        v1.14.0
)
FetchContent_MakeAvailable(googletest)

target_link_libraries(my_tests PRIVATE GTest::gtest_main)

İlk yapılandırmada repo derleme dizinine klonlanır ve derlenir. Sonraki yapılandırmalar önbelleğe alınmış kopyayı kullanır.


Üretici İfadeler (Generator Expressions)

Üretici ifadeler yapılandırma zamanında değil, derleme zamanında değerlendirilir. $<...> şeklinde görünürler ve yapılandırmaya özgü ayarlar için vazgeçilmezdir:

# Yalnızca Debug derlemelerinde -g ekle
target_compile_options(myapp PRIVATE $<$<CONFIG:Debug>:-g>)

# Derleme ve kurulum için farklı include yolları
target_include_directories(mylib PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
)

# Yalnızca Windows'ta bir kütüphaneye bağlan
target_link_libraries(myapp PRIVATE $<$<PLATFORM_ID:Windows>:ws2_32>)

CTest ile Test

# Kök veya tests/CMakeLists.txt içinde
enable_testing()

add_executable(test_foo test_foo.cpp)
target_link_libraries(test_foo PRIVATE mylib GTest::gtest_main)

include(GoogleTest)
gtest_discover_tests(test_foo)

Testleri çalıştırmak için:

cd build
ctest --output-on-failure
ctest -R test_foo          # belirli bir desenle eşleşen testleri çalıştır
ctest -j4                  # 4 testi paralel çalıştır

Kurulum (Install)

install(TARGETS mylib myapp
    RUNTIME DESTINATION bin        # yürütülebilir dosyalar
    LIBRARY DESTINATION lib        # paylaşımlı kütüphaneler
    ARCHIVE DESTINATION lib        # statik kütüphaneler
)

install(DIRECTORY include/
    DESTINATION include
)

Derle ve kur:

cmake --build .
cmake --install . --prefix /usr/local

CMake Ön Ayarları (CMakePresets.json)

Ön ayarlar, ekipteki herkesin aynı ayarları kullanması için yaygın yapılandırma/derleme seçeneklerini sürüm kontrolüne işlemenizi sağlar:

{
  "version": 6,
  "configurePresets": [
    {
      "name": "debug",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/debug",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "BUILD_TESTS": "ON"
      }
    },
    {
      "name": "release",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/release",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release",
        "BUILD_TESTS": "OFF"
      }
    }
  ],
  "buildPresets": [
    { "name": "debug",   "configurePreset": "debug" },
    { "name": "release", "configurePreset": "release" }
  ]
}

Kullanımı:

cmake --preset debug
cmake --build --preset debug
ctest --preset debug

Çapraz Derleme (Cross-Compilation)

Farklı bir mimari için derlemek üzere bir araç zinciri dosyası iletin:

cmake .. -DCMAKE_TOOLCHAIN_FILE=toolchain-arm.cmake

Minimal bir ARM araç zinciri dosyası:

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_C_COMPILER   arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)

set(CMAKE_FIND_ROOT_PATH /usr/arm-linux-gnueabihf)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Yaygın Hatalar

Hedef düzeyi yerine dizin düzeyi komutları kullanmak

# Kötü — dizindeki ve altındaki her şeyi etkiler
include_directories(include/)
add_compile_options(-Wall)

# İyi — yalnızca bu hedefe kapsamlı
target_include_directories(mylib PUBLIC include/)
target_compile_options(mylib PRIVATE -Wall)

Kaynak dosyaları glob ile toplamak

# Kötü — yeni dosya eklediğinizde CMake yeniden çalışmaz
file(GLOB SOURCES src/*.cpp)

# İyi — dosyaları açıkça listeleyin ki CMake eklemeleri fark etsin
add_executable(myapp src/main.cpp src/foo.cpp src/bar.cpp)

C++ standardını belirtmemek

# Kırılgan — derleyicinin varsayılanına güveniyor
add_executable(myapp main.cpp)

# Doğru
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)   # -std=gnu++17 değil, -std=c++17 kullan

Yolları sabit kodlamak

# Kötü — yalnızca bir makinede çalışır
target_include_directories(myapp PRIVATE /home/kullanici/libs/boost/include)

# İyi — find_package veya FetchContent kullanın
find_package(Boost REQUIRED COMPONENTS filesystem)
target_link_libraries(myapp PRIVATE Boost::filesystem)

Hızlı Başvuru Kılavuzu

cmake_minimum_required(VERSION 3.20)
project(Ad VERSION 1.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Hedefler
add_executable(uygulama src/main.cpp)
add_library(kutuphane STATIC src/lib.cpp)

# Özellikler
target_include_directories(kutuphane PUBLIC include/)
target_compile_options(kutuphane PRIVATE -Wall -Wextra)
target_link_libraries(uygulama PRIVATE kutuphane)

# Bağımlılıklar
find_package(OpenSSL REQUIRED)
target_link_libraries(uygulama PRIVATE OpenSSL::SSL)

# Testler
enable_testing()
add_test(NAME benim_testim COMMAND uygulama --run-tests)

# Kurulum
install(TARGETS uygulama kutuphane RUNTIME DESTINATION bin ARCHIVE DESTINATION lib)
install(DIRECTORY include/ DESTINATION include)

Yapılandır → Derle → Test → Kur

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
        │
        ▼  CMakeLists.txt'yi okur, derleyicileri tespit eder, paketleri bulur
cmake --build build --parallel
        │
        ▼  kaynak dosyaları derler, hedefleri bağlar
ctest --test-dir build --output-on-failure
        │
        ▼  kayıtlı testleri çalıştırır, hataları raporlar
cmake --install build --prefix /usr/local
        │
        ▼  ikili dosyaları, başlıkları ve kütüphaneleri hedefe kopyalar

Bu hattı ve hedef merkezli modeli — target_* komutlarının global durumu kirletmek yerine adlandırılmış hedeflere özellik eklediği modeli — bir kez kavradığınızda, CMake büyük kod tabanlarında çok daha kolay anlaşılır ve sürdürülebilir hale gelir.

Comments

(0)
Top commentsNewest first

0/3000 • Press Ctrl + Enter to submit

Loading comments...

CMake Dosyalarına Giriş | SourceDev