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
| Dosya | Amaç |
|---|---|
CMakeLists.txt | Ana proje talimatları dosyası |
*.cmake | Yeniden kullanılabilir yardımcı dosyalar, modüller, paket yapılandırması |
CMakePresets.json | Paylaşı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 Kelime | Anlam |
|---|---|
PRIVATE | Yalnızca myapp, mylib'e bağlanır |
PUBLIC | myapp ve myapp'e bağlanan her şey mylib'i alır |
INTERFACE | Yalnı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şken | Açıklama |
|---|---|
CMAKE_SOURCE_DIR | Kaynak ağacının kökü |
CMAKE_BINARY_DIR | Derleme ağacının kökü |
CMAKE_CURRENT_SOURCE_DIR | Mevcut CMakeLists.txt'nin kaynak dizini |
PROJECT_NAME | project() ile belirlenen ad |
PROJECT_VERSION | project() ile belirlenen sürüm |
CMAKE_BUILD_TYPE | Debug, Release, RelWithDebInfo, MinSizeRel |
CMAKE_CXX_STANDARD | C++ standardı: 11, 14, 17, 20, 23 |
BUILD_SHARED_LIBS | ON 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
| Paket | Hedef |
|---|---|
| OpenSSL | OpenSSL::SSL, OpenSSL::Crypto |
| Threads | Threads::Threads |
| zlib | ZLIB::ZLIB |
| Boost | Boost::filesystem, Boost::system, … |
| fmt | fmt::fmt |
| GTest | GTest::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)Loading comments...