Platform
Programlama

1. Compile, link, build nedir? - C++

C++ derslerine başlamadan önce özellikle compiling, linking, building gibi kavramları tanıyarak başlayalım.

resul · Editör, Yazar· 12 Temmuz 2026· 8 dk okuma

Neden bu seri en iyisi?

Çünkü zeka ve gayretimin mahsulü olacak olan bu seriyi ben yazmaktayım. O yüzden en iyisi.

Neden C++?

Öğrenme eğrisi her ne kadar diğer dillere göre dik olsa da bunun da bir nedeni elbette var. Daha düşük seviyeli yani çoğu şeyi manuel ayarladığımızdan dolayı diğer dillere göre zor gözükebilir. Ancak C++ dilini tercih etmemizin birincil nedeni performans ve topluluk desteği. Şuanda yazılım ile alakalı olan çoğu proje-eser, işletim sistemlerinden tutun AAA oyunlara kadar her yerde en yaygın olan dil C++'dır.

Diğerlerinden farkı?

Diyelim ki bir .cpp dosyası oluşturduk. Dosyaya bazı kodlar yazıyoruz kaydedip çalıştır diyoruz. Aslında orada gerçekleşen bazı şeyler var. Mesela önce derleyici kaynak kodu nesne koduna çeviriyor ardından bağlayıcı (linker) bu kodu gereken kütüphanelerle birleştirip çalıştırılabilir bir program haline getiriyor. Windows ortamında bu programın .exe dosyası olduğunu düşünebilirsiniz. Siz programı ancak bu adımdan sonra çift tıklayıp çalıştırırarak naptığını görebilirsiniz.

Diğer dillerde örneğin Python’da bir .py dosyasını çalıştırmak için Python yorumlayıcısı yeterlidir. Yorumlayıcı, kaynak kodu önce bayt koduna dönüştürür, ardından bu bayt kodunu Python sanal makinesi (PVM) ile çalıştırır.

Java’da ise .java uzantılı kaynak kod, Java derleyicisi tarafından .class dosyasına dönüştürülür. Bu dosyadaki kod makine kodu değil, bayt kodudur(bayt kodunu insan anlayamaz işlemci de çalıştıramaz). Üretilen bu şey, Java’nın sanal makinesi olan JVM üzerinden çalıştırılır.

C++ içinse kod ilk önce makine koduna (0lar ve 1ler) derlenir ve yazdığınız tüm kod dosyaları birbirine bağlama (linker) aşamasından geçirilerek çalıştırılabilir bir program elde edilir.

Bu seri C++ için bi iskelet olarak düşünün yani bi temel olarak. Ama “temel” derken 1998-2003 standartlarına göre bir C++ da anlatmayacağım çünkü ben 2005liyim ag. Eskiden C++ kodunda değişkenler için NULL, ham dizi (boyutunu ve yaşam süresini kendisi yönetemez ancak std::vector yönetir mesela), elle oluşturma ve silme ve hiç start verilmemiş bir değişken görmek çok olasıydı. Burada bunların (eski C++) yerine C++17 ve C++20 yani Modern C++ öğretcem ancak Modern C++ 2017 veya 2020 de değil 2011 ile başladı, yine de en güncel halini öğrenmek daha mantıklı. Modern derken; değişkeni baştan başlatmak (en baştan), belirsiz davranışlardan kaçınmak, const ve auto kullanmak, ham dizi yerine std::vector ("containers" ileride anlatcam) kullanmak gibi şeyler demek istedim. Amaç, ileri seviyeye geçmek isteyen biri için sağlam bir altyapı kurmak

Kavramlardan kafam karıştı??

Kodlamaya daha yeni başlamışsan veya C++ ilk defa öğreneceksen hatta biraz biliyor olsan da başlangıç seviyesindeysen bu çok normal. Bir kaç ders sonra buraya döndüğünde en azından çoğu şeyi anlamış olacaksın. Belli seviyeye gelmişler için bu yazıyı yazmak zorundaydım çünkü en azından neyi öğreneceklerini-tekrar edeceklerini bilmeleri gerekirdi.

Modern C++ ne demek?

Mesela aynı değişken yani örneğin int değişkeni hala aynı int değişkeni. Yani dil yapısı aynı, hatta çoğu şey temelde aynı. Ama biraz stil değişti diyebiliriz. Eskiden “derleyici nasıl olsa anlar” diye önem verilmeden yazılırmış (Mış diyorum çünkü pek kullanmadım eskisini). Şimdiyse şöyle ki: daha az hata ve daha fazla derleyici yardımı oluyor. Yani amaç hatanın çalışma anında değil, derleme anında çıkması. Çünkü test sürecini de kolaylaştırıyor diyebiliriz.

Gereken araçlar

Lazım olan tek şey bir derleyici ve bir kod editörü. Tek kod dosyasının olduğu işlerde bu ikisi yeter ancak dosya sayısı artınca make,ninja ve cmake gibi kod dosyalarını yönetmemizi kolaylaştıran sistemler de gerekecek. Şimdilik sadece derleyici ve kod editörü lazım diye düşünün.

Derleyici seçenekleri: (birazdan göstereceğim örnekle nasıl derlendiğini görebilirsin.)
-GCC (tavsiye) (Windows için MinGW-w64 adıyla kurulur)
-Clang (biraz alttaki g++ ile başlayan komutta "-" ile başlayanlar bir bayrak(flag)tır. Kural gibi düşünün. Clang'in bayrakları/kuralları GCC ile neredeyse aynı. terminale g++ yerine clang++ yazılır)
-MSVC (Microsoft'un kendi derleyicisi, komutu g++ yerine "cl" dir. Bayrakları hiç benzemez onu kullanmıyorum-kullanmıcam.)

Editör seçenekleri:
-VS Code
-Clion (bu çok önemli değil ben CLion daha çok severim.)

Standart olarak c++20 kullanacağız. -std=c++20

Örneğin tek bir kod dosyasından (main.cpp) bir proje yaptık aynı dosya dizininde bir terminal açarak (doğrudan kod editöründe genelde bulunur) şunları yazarak derleriz:

cpp
g++ -std=c++20 -Wall -Wextra -Wpedantic main.cpp -o main

Şimdi bu ne demek ona geçelim. Satırdaki her parça ayrı iş yapar. W harfini içeren şeyleri yazmak zorunda değilsiniz ama yine de ne olduklarına değinelim.

g++ C++ derleyicisini çağırır. GCC’nin C++ sürücüsüdür (gcc c içinken g++ c++ içindir). Bu komutta hem derler hem bağlar. Ortaya çalışan program çıkar.
-std=c++20 dili C++20 kurallarıyla derler. Bunu yazmazsan derleyici daha eski bir standarda-versiyona düşebilir.
-Wall W = warning (uyarı), all = yaygın uyarı seti. Derleyicinin işe yarayan uyarılarını açar.
-Wextra bu setin dışında kalan ek uyarıları açar.
-Wpedantic standart dışı bir uzantı kullanırsan uyarır. Derleyicinin hata veya uyarı vermeden kabul ettiği, başka derleyicide sorun çıkartabilecek şeyleri gösterir.
main.cpp derlenecek kaynak dosyadır.
-o main çıkan dosyanın adını main yapar. Bunu yazmazsan MinGW a.exe üretir. -o main deyince Windows’ta dosya main.exe olur. Yani ortaya çıkan program ismi belirlenir.

En sade şekilde

terminal
g++ -std=c++20 main.cpp -o main

olur.

Bunlar programı çalıştırmaz, yalnızca oluşturur. Gidip kendi elinle çift tıklarsın yada

terminal
.\main.exe

yazarsın programın olduğu dizin terminaline. Linux ve macos’ta uzantı yoktur. Orada komut ./main olur.

Normalde kod önce bir nesne dosyasına dönüşür. Bu kodun derlenmiş halidir ancak derlenmiş hali olan bu nesne dosyaları çalıştırılabilir bir program değildir. Yukarıda -o yu gördük onun yerine -c yazarsak, mesela

terminal
g++ -std=c++20 -c main.cpp

bu bize .o uzantılı nesne dosyasını verir.

terminal
g++ main.o -o main

bu da .o uzantısı elde ettikten sonra çalıştırılabilir program elde etmemizi sağlar.

Derleyici ve bağlayıcı (Compiler and Linker)

İşlemci yazdığınız C++ kodunu okumaz burası insanların anladığı kısımdır. Derleyici bu insanlar için anlamlı, makine için anlamsız kodu; insanlar için anlamsız, makine için anlamlı olan 0 ve 1 lere dönüştürür yani makine koduna. Tek dosyada da bağlayıcı çalışır: g++ main.cpp -o main derler, sonra senin yerine bağlar. Bağlayıcının işi çok dosyada görünür hale gelir. Projede 15000 satır olsa aynı yere mi yazacaksınız? 2-3 dosya olsa ve 2. dosya 1. dosyadaki bir fonksiyonu çağırsa, derleyici her dosyayı ayrı .o yapar; o .o ları birleştiren bağlayıcıdır. Yani yapı kısaca şu şekildedir:

workline
main.cpp → derleyici → main.o → bağlayıcı → main.exe

Fazla dosyayla ise şöyledir:

workline

main.cpp   → main.o
math.cpp   → math.o
player.cpp → player.o
                 ↓
              bağlayıcı → program.exe

Örneğin main.cpp, math.cpp içindeki bir fonksiyonu çağırıyorsa derleyici main.cpp’yi yine derler. Bağlayıcı o fonksiyonun (math.cpp içindeki) derlenmiş halini bulamazsa undefined reference görürsün. Bu derleme hatası değil, bağlama hatası olır.

Bu seride programı ortaya çıkarmayı şöyle sadeleştireceğiz:

Compile = bir çevirim birimini nesne koduna çevirmek
Link = o parçaları (ve kütüphaneleri) birleştirip program yapmak
Build ≈ Compile + Link

Build'i şimdilik böyle düşünebilirsin. Compile + Link in yanı sıra makrolar, başlıklar vs. de dahil ancak şuanlık değinmeyeceğim. Build tam olarak bu ikisinin toplamı değildir yani. Öğretici olması açısından yaklaşık dedim.

Build’i kolaylaştıran araç takımları vardır. Dosya çoğalınca her seferinde elle derleyip bağlamak zahmetli gelir. O halde bir araç ekleriz; hangi dosyanın ne zaman derleneceğini ve en sonda nasıl bağlanacağını o yönetir.

Make (Build Aracı)

Mesela 3 tane dosyamız olsun içinde kodlar olan: main.cpp , player.cpp , enemy.cpp bunları ayrı ayrı derleyip en son onları bağlarsınız (linking) örneğin:

terminal
g++ -std=c++20 -c main.cpp
g++ -std=c++20 -c player.cpp
g++ -std=c++20 -c enemy.cpp
g++ main.o player.o enemy.o -o game

3 tane dosyayla kısa gözüktü demi? Ama şimdi bunun 500 dosya olduğunu düşünün. Her seferinde değiştirdiğin her dosya için ayrı ayrı yazmak zorunda kalmak istemezsin. Make bize diyor ki projenin içine bir Makefile dosyası oluştur, içini aç ve şunları yaz. Hedef adı ile -o ile verdiğin dosya adı aynı olsun:

makefile

game: main.o player.o enemy.o
	g++ main.o player.o enemy.o -o game

main.o: main.cpp
	g++ -std=c++20 -c main.cpp

player.o: player.cpp
	g++ -std=c++20 -c player.cpp

enemy.o: enemy.cpp
	g++ -std=c++20 -c enemy.cpp

sonra aynı dosyanın olduğu dizinde bir terminal çalıştırıp

terminal
make

bunu çalıştırırsan içini okur ve derler (derlemek + bağlamak + ekstra bazı işler= build etmek). Hedef game, çıkan dosya da game. Windows’ta MinGW bu dosyayı game.exe diye yazar; Make yine game hedefini bilir. Ayrıca her birini ayrı ayrı derlemez sadece değişiklik yapılanı derler sonra build eder. Yani Make derlemenin ne zaman çalışacağını belirlerken, g++ kodu derler.

Ninja (Diğer Build Aracı)

Ninja da Make gibi bir build aracıdır yani derlemez. Hangi komutun hangi sırayla çalışacağını alıp hızlı çalıştırır. Dosya build.ninja olarak geçer.

Bunları bilmek yerine

makefile veya ninja kafanı karıştırmış olabilir. Bunun yerine daha iyi bir hizmet var CMake dediğimiz. Bu hizmet make yada ninja yerine geçen bir şey değil ama bu hizmet sana istediğin Makefile'ı üretir yada build.ninja'yı üretir. CMake bir makefile üretmek yada ninja ile bir şeyler yapmaktan daha kolaydır yapısal anlamda. Mesela projenizde build veya derlemeye dair hiç bişey eklemediniz. Yani sadece kod dosyalarınız var ve yalnızca bir CMakeLists.txt üretirsiniz ve içine

CMakeLists
cmake_minimum_required(VERSION 3.20)

project(MyGame)

add_executable(MyGame
    main.cpp
    player.cpp
    enemy.cpp
)

Burada

terminal
g++ -c main.cpp

yazmazsınız. Şu dosyalardan (main.cpp, player.cpp, enemy.cpp) MyGame adında bir program çıksın diyorsun.

CMakeLists.txt hazırladıktan sonra bu .txt dosyasının olduğu dizinde terminal açarsınız.

Sonra derlerken şunları yazarsınız:

makefile ile istersen

terminal
cmake -S . -B build -G "Unix Makefiles"
cmake --build build

ninja ile istersen

terminal
cmake -S . -B build -G Ninja
cmake --build build

Yani yapı zinciri şu şekilde

workline

CMakeLists.txt
      ↓
    CMake
      ↓
Makefile  veya  build.ninja
      ↓
 Make          Ninja
      ↓
     g++
      ↓
   program

Bu ders bu kadardı. Anlaması veya sindirmesi zor olabilir. Önemli değil diğer derslerde verilen örnekleri adım adım uygularsanız bu kısmı da anlarsınız. Unutmayın bu yapıyı anlamanız önemli o yüzden her dersten sonra tekrar tekrar bakabilirsiniz buraya.

Serinin haritası

Önce programın nasıl üretildiğini anlattık, sonra değişkenlerin bellekte nasıl durduğu, sonra türler, sabitler, operatörler, koşullar, döngüler, fonksiyonlar ve std::vector den bahsetmeyi düşünüyorum.Özellikle üçüncü ders (değişkenler) bu işin temelini oluşturuyor. Orada {} alışkanlığını bir kez doğru öğrenirsek, sonraki her konu daha kolay sindirilecektir. Unutmayın her ders bir alışkanlık oluştursun, sadece tanım ezberletmesin. O yüzden örnekleri ve ödevleri iyi yapınız.

Editör · Yazarresul
cppprogramlama