---
title: 'Kütüphane Üretimi'
source: 'https://academia.sh/tr/kurslar/c-sistem-programlama/kutuphane-uretimi'
course: 'C ile Sistem Programlama'
language: tr
updated: '2026-09-26T03:02:44+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Gömülü bağlamanın kütüphane değerini kopyaladığını, işaretçi tabanlı bağlamanın paylaştığını ölçer'
    - 'static ve extern kapsamın aynı adlı değişkeni neden ayrı ya da tek nesneye bağladığını gösterir'
    - 'Bu ikisini aynı ölçüm çerçevesinde kopya ve ortak sınıflarıyla ayırt eder'
---

# Kütüphane Üretimi

Bir kütüphanenin programa gömülerek mi yoksa yüklemede okunarak mı bağlandığının, kütüphane sürümü değiştiğinde programın hangi değeri gördüğünü nasıl belirlediğini ölçer.

Bir hedef doğru derlenip nesne haline geldikten sonra tek başına çalışmaz — çoğu program
başka birimlerin ürettiği işlevlere ve verilere bağlanır. Bu bağlanma iki farklı biçimde
olabilir: kütüphanenin o anki değeri programın kendi gövdesine **kopyalanır**, ya da program
kütüphaneye bir **işaretçiyle** erişir ve her seferinde güncel değeri okur. Kütüphane
sonradan güncellendiğinde bu iki program birbirinden farklı bir şey görür.

Aynı ayrım, tek bir çeviri biriminin dışına açılmayan bir değişkenle dışa açılan bir
değişken arasında da yaşanır. `static` bir dosya kapsamı değişkeni her çeviri birimine
kendi kopyasını verir; `extern` bildirimiyle paylaşılan bir değişkenin ise tek bir tanımı
vardır ve onu kullanan her birim aynı nesneyi görür.

Bu ders, bir önceki dersteki **kopya** sınıfını farklı bir katmanda tekrar karşımıza
çıkarıyor. Orada kopya, bağımlılık listesine yazılmamış bir kaydın taşıdığı eski değerdi;
burada kopya, bağlanma anında alınıp bir daha güncellenmeyen bir kütüphane sürümüdür. İkisi
de aynı belirtiyi verir — beklenenden eski bir değer — ama biri derleme sisteminin karar
katmanında, diğeri bağlanma katmanında oluşur. Bu iki katmanı ayırt edebilmek, bir hatayı
ararken nereye bakılacağını daraltmanın ilk adımıdır.

## Gömülü Sürüm ve İşaretçi Tabanlı Erişim

Aşağıdaki model bir kütüphanenin sürümünü ve ona iki farklı yoldan bağlanan iki yapıyı
tanımlıyor: biri sürümü bağlama anında kendi alanına kopyalıyor, diğeri kütüphaneye giden
işaretçiyi saklıyor.

```c
// baglama.h — gomulu ve isaretci tabanli baglamanin surum gorunurlugu
#ifndef BAGLAMA_H
#define BAGLAMA_H

struct Kutuphane {
    int surum;
};

struct GomuluBagli {
    int gomulu_surum;   /* baglama aninda kopyalanan deger, sonrasinda bagimsiz */
};

struct IsaretciBagli {
    const struct Kutuphane *hedef;   /* deger degil, kutuphaneye giden yol saklanir */
};

void gomulu_bagla(struct GomuluBagli *g, const struct Kutuphane *k);
int gomulu_surum(const struct GomuluBagli *g);

void isaretci_bagla(struct IsaretciBagli *b, const struct Kutuphane *k);
int isaretci_surum(const struct IsaretciBagli *b);

#endif
```

```c
// baglama.c — gomulu baglama kopyalar, isaretci baglama her okumada yeniden okur
#include "baglama.h"

void gomulu_bagla(struct GomuluBagli *g, const struct Kutuphane *k) {
    g->gomulu_surum = k->surum;
}

int gomulu_surum(const struct GomuluBagli *g) {
    return g->gomulu_surum;
}

void isaretci_bagla(struct IsaretciBagli *b, const struct Kutuphane *k) {
    b->hedef = k;
}

int isaretci_surum(const struct IsaretciBagli *b) {
    return b->hedef->surum;
}
```

**PA3.** `gomulu_bagla` burada gerçek bir programın derleme anında yaptığı gömmeyi
temsil ediyor: kütüphanenin o anki değeri, program çalışmaya başlamadan önce sabitlenmiş
gibi davranıyor. Gerçek bir derleme sisteminde bu adım derleme sırasında olur; burada
zamanlamayı görünür kılmak için çalışma zamanında bir kopyalama işlemiyle modelleniyor.

Bu iki yapı, gerçek bir derleme ortamındaki iki kütüphane bağlama biçiminin karşılığıdır.
`GomuluBagli`, **statik bağlı** bir kütüphaneyi temsil ediyor: kütüphanenin derlenmiş
kodu, programın kendi yürütülebilir dosyasının içine doğrudan kopyalanır ve program bir
daha kütüphaneye bakmaz. Kütüphane sonradan güncellenip ayrıca derlense bile, zaten
statik bağlı programın gövdesinde donmuş kalan kopya değişmez — programın kendisi yeniden
bağlanmadıkça, güncel sürüm ona hiç ulaşmaz. `IsaretciBagli` ise **paylaşılan** (dinamik)
bağlı bir kütüphaneyi temsil ediyor: yürütülebilir dosya kütüphanenin kendi kodunu taşımaz,
yalnız ona giden bir yolu tutar ve her erişimde kütüphaneye gider. Kütüphane güncellenip
yeniden üretildiğinde, programın kendisi hiç yeniden derlenmeden bir sonraki çalıştırmada
güncel sürümü görür — çünkü okuma programın gövdesine gömülü bir kopyadan değil, kütüphanenin
kendisinden yapılır.

**PA4.** Statik ve paylaşılan bağlamanın gerçek ortamdaki farkı yükleme zamanlamasında ve
disk üzerindeki ayrı bir kütüphane dosyasının varlığındadır; bu model o zamanlama farkını
tek bir çalışma zamanı akışı içinde, `gomulu_bagla` çağrısının kütüphaneyi güncellemeden
önce yapılmasıyla temsil ediyor. Ölçülen sonuç — statik bağlının eski kaldığı, paylaşılanın
günceli gördüğü — zamanlamanın kendisinden değil, kopyalama ile referans tutmanın farkından
doğuyor, dolayısıyla model gerçek yükleme mekanizmasını atlasa da sonucu değiştirmiyor.

## static ve extern Kapsam

Bir kütüphane birden çok çeviri birimine bölündüğünde, her birimin kendi dosyasına özel
sayaçları ile bütün birimlerin paylaştığı tek bir sayaç arasındaki fark aynı çerçevede
ölçülebilir.

Bu karşıtlık **başlıkta** kurulur, kaynak dosyada değil: bir değişkenin `paylas.h` gibi
birden çok kaynak dosyanın dahil ettiği bir başlıkta `extern` olarak bildirilmesi, o
değişkenin tek bir tanımı olacağının ve onu dahil eden her birimin **aynı nesneyi**
göreceğinin sözünü verir. Aynı başlığa `static` bir bildirim yazmak bu sözü veremezdi —
`static`, kapsamını doğrudan bulunduğu çeviri birimiyle sınırlar; bir başlığa yazılıp her
kaynak dosyaya dahil edilseydi, her dahil eden birim kendi **ayrı** kopyasını üretirdi,
paylaşılan tek bir nesne değil. Bu yüzden paylaşım isteniyorsa bildirim başlıkta `extern`
olmalı ve tanım tam olarak bir kaynak dosyada bulunmalıdır; birime özel tutmak isteniyorsa
bildirim kaynak dosyanın kendisinde `static` olarak kalmalı ve hiç başlığa taşınmamalıdır.

Bu ayrımı yanlış kurmanın iki farklı sonucu var. Bir değişken paylaşılması gerekirken
yanlışlıkla `static` bırakılırsa — örneğin başlığa hiç `extern` bildirimi eklenmeden her
kaynak dosyanın kendi kopyasını tanımlaması istenirse — birimler birbirinden habersiz ayrı
sayaçlar tutar ve `ortak_sayac` gibi paylaşılan bir toplam hiç oluşmaz; her birim kendi
gördüğü kısmi sayıyı doğru sanır. Tam tersi yönde bir hata da mümkündür: aynı adlı bir
değişken birden fazla kaynak dosyada `extern` olmadan, doğrudan tanımlanırsa — yani her
kaynak dosya kendi başına o ismi paylaşılan bir nesne gibi tanımlamaya çalışırsa —
bağlayıcı aynı adı birden fazla yerde tanımlanmış bulur ve bu genelde bir bağlama hatasıyla
sonuçlanır. Başlıktaki `extern` bildirimi bu ikinci hatayı da önler, çünkü başlığı dahil
eden her birime yalnız bir **bildirim** verir, bir **tanım** değil; tanım tam olarak bir
kaynak dosyada kalır.

```c
// paylas.h — ortak sayaci disa acan bildirim
#ifndef PAYLAS_H
#define PAYLAS_H

extern int ortak_sayac;    /* extern: tek tanim, her birim ayni nesneyi paylasir */

void durum_artir(void);
int durum_sayaci(void);

#endif
```

```c
// durum.c — statik sayac bu birime ozel, extern sayac paylasilan
#include "paylas.h"

static int birim_sayaci = 0;   /* static: bu ceviri birimine ozel kopya */
int ortak_sayac = 0;            /* extern bildiriminin tek tanimi burada */

void durum_artir(void) {
    birim_sayaci++;
    ortak_sayac++;
}

int durum_sayaci(void) {
    return birim_sayaci;
}
```

`main` içeren birim de kendi `static` sayacını tutuyor; adı `durum.c` içindekiyle aynı
olsa da `static` kapsam bunu ayrı bir nesne yapıyor, derlemeyi bozmuyor.

```c
// olcum.c — gomulu/isaretci baglama ve static/extern kapsam tek kosumda
#include <stdio.h>
#include "baglama.h"
#include "paylas.h"

static int birim_sayaci = 0;   /* bu birime ozel; durum.c'deki ayni adli degiskenden ayri */

int main(void) {
    struct Kutuphane kutuphane = { 1 };
    struct GomuluBagli gomulu;
    struct IsaretciBagli isaretcili;

    gomulu_bagla(&gomulu, &kutuphane);
    isaretci_bagla(&isaretcili, &kutuphane);

    kutuphane.surum = 2;   /* kutuphane baglamadan sonra 2. surume cikti */

    printf("gomulu bagli surum: %d\n", gomulu_surum(&gomulu));
    printf("isaretci bagli surum: %d\n", isaretci_surum(&isaretcili));

    durum_artir();
    durum_artir();
    birim_sayaci++;
    ortak_sayac++;

    printf("durum.c birim sayaci: %d\n", durum_sayaci());
    printf("main birim sayaci: %d\n", birim_sayaci);
    printf("ortak sayac: %d\n", ortak_sayac);
    return 0;
}
```

```text
gomulu bagli surum: 1
isaretci bagli surum: 2
durum.c birim sayaci: 2
main birim sayaci: 1
ortak sayac: 3
```

`gomulu` yapısı, bağlama anında okuduğu 1 değerinde kaldı — kütüphane sonradan 2. sürüme
çıktığında bundan habersizdir, çünkü elinde tuttuğu şey bir **kopya**. `isaretcili` yapısı
ise aynı kütüphane nesnesine giden yolu sakladığı için güncel değeri okudu; bu, gömülü
bağlamanın karşıtı olan **ortak** görünürlüğün bir modelidir — bu dersin kendisi
ölçmüyor, yalnız karşılaştırma için burada duruyor.

Bu iki sonuç, statik ve paylaşılan bağlamanın kütüphane güncellemesine verdiği yanıtı
birebir yansıtıyor. `gomulu` statik bağlı bir programın davranışını modelliyor: kütüphane
2. sürüme çıktı, ama program zaten kendi gövdesine 1. sürümün kopyasını gömmüştü ve bu
kopya bir daha değişmedi — kütüphanenin yeni sürümünü görmesinin tek yolu, programın
kütüphaneye **yeniden bağlanarak** kendisinin de yeniden üretilmesidir. `isaretcili` ise
paylaşılan bağlı bir programın davranışını modelliyor: program kendisi hiç yeniden
derlenmedi, ama kütüphaneye giden yolu her okuduğunda kütüphanenin **o anki** durumunu
gördüğü için güncellemeyi otomatik olarak yakaladı. Bu fark, iki bağlama biçimi arasında
seçim yaparken göz önünde tutulması gereken temel değiş tokuşu özetliyor: statik bağlama
öngörülebilir ve kütüphanenin dışarıdan değişmesine karşı bağışıktır, ama güncellemeyi
almak için yeniden bağlanma ister; paylaşılan bağlama güncellemeyi otomatik alır, ama bu
otomatikliğin bedeli, kütüphanenin ne zaman değiştiğinin programın kendi kontrolü dışında
olmasıdır.

`durum.c` birimindeki `static` sayaç yalnız kendi çağrılarını saydı ve 2'de kaldı; `main`
birimindeki aynı adlı `static` sayaç ise ondan tamamen bağımsız, kendi 1 değerini taşıyor.
`ortak_sayac` ise her iki birimin de arttırdığı tek nesne olduğu için ikisinin toplamı olan
3'e ulaştı.

Aynı `static`/`extern` ayrımı fonksiyonlar için de geçerlidir, yalnız bu derste değişken
üzerinden gösteriliyor çünkü kopyalanan değerin görünürlüğü değişkende daha doğrudan
izlenebilir. Bir fonksiyon `static` bildirilirse, o fonksiyon yalnız kendi çeviri biriminden
çağrılabilir; aynı adı taşıyan başka bir `static` fonksiyon başka bir birimde tanımlanabilir
ve ikisi birbirine karışmaz, çünkü bağlayıcı ikisini de dışa açık bir sembol olarak görmez.
Bu, büyük bir kod tabanında yardımcı fonksiyon adlarının çakışmasını önlemenin ucuz bir
yoludur: bir birime özel kalması gereken her yardımcı fonksiyon `static` bırakılır, yalnız
gerçekten paylaşılması gereken fonksiyonlar başlığa `extern` bildirimiyle (ya da bildirimsiz,
çünkü fonksiyonlar C'de varsayılan olarak `extern`'dür) taşınır. Bu seçim erken yapılmazsa
sonradan geri almak ucuz değildir: bir fonksiyon önce paylaşılan olarak yayılır, başka
birimler onu çağırmaya başlar, sonra birim içine kapatılmak istenirse artık onu çağıran her
yerin de değişmesi gerekir — bu yüzden görünürlük kararı, kütüphanenin arayüzünü ilk kez
çizerken, sonradan değil baştan verilir.

## Sınırlayıcı Ölçüm

Bu model kütüphanenin gerçekte nasıl yüklendiğini değil, yalnız iki bağlama biçiminin
**hangi değere eriştiğini** ölçüyor. Gerçek bir ortamda gömülü bağlama derleme sırasında,
işaretçi tabanlı bağlama ise programın başlatılması sırasında kurulur; burada ikisi de tek
bir çalışma zamanı akışı içinde, zamanlamaları görünür kılınarak modelleniyor. Kütüphanenin
arayüzü — yani `struct Kutuphane` içindeki alanların sırası ve türleri — iki taraf arasında
değişirse, işaretçi tabanlı bağlamanın eski değil güncel değeri okuması artık bir güvence
değildir; bu, tanımsız davranışa açılan bir sınırdır ve burada koşturulmaz.

Statik ve paylaşılan bağlamanın gerçek dünyadaki sonucu genelde bir güvenlik ya da hata
düzeltmesinin dağıtımında ortaya çıkar. Kütüphanenin bir sürümünde bir hata düzeltilip
kütüphane yeniden üretildiğinde, paylaşılan bağlı bir program bu düzeltmeyi kendisi hiç
dokunulmadan, bir sonraki çalıştırmasında devralır — düzeltme kütüphaneyle birlikte
dağıtılır. Statik bağlı bir program ise aynı düzeltmeyi almaz; kendi gövdesine gömdüğü eski
kod çalışmaya devam eder, ve düzeltmenin ona ulaşması için programın kendisinin kütüphaneye
yeniden bağlanıp yeniden dağıtılması gerekir. Bu, iki bağlama biçimi arasındaki seçimin
yalnız bir performans ya da dosya boyutu meselesi olmadığını, aynı zamanda bir bakım ve
dağıtım sorumluluğu meselesi olduğunu gösteriyor: paylaşılan bağlama güncellemeyi merkezi
bir noktadan (kütüphanenin kendisinden) yayarken, statik bağlama her programın kendi
kopyasının ayrı ayrı güncellenmesini gerektiriyor.

Bir önceki dersin sorusu bağımlılığın **yazılıp yazılmadığıydı**; bu ders bağımlılık
doğru yazılmış olsa bile, ona **nasıl** bağlanıldığının görünürlüğü değiştirdiğini
gösteriyor — iki soru birbirini tamamlıyor, aynı aşamada durmuyor.

Bu iki soru aynı hataya iki farklı açıklama getirebilir. Bir program beklenmedik şekilde
eski bir değer taşıyorsa, önce bağımlılığın derleme sisteminin listesinde yazılı olup
olmadığına bakılır; liste doğruysa ama değer yine de eski kalıyorsa, ikinci soru devreye
girer — bağlanma biçimi gömülü mü, işaretçi tabanlı mı? Gömülü bağlanan bir değer, listeye
doğru yazılmış bir bağımlılığın bile eski bir kopyasını taşıyabilir, çünkü kopyalama zaten
bağlanma anında, kütüphane değişmeden önce gerçekleşmiştir. Bu iki neden birbirine benzer
sonuç üretir — her ikisinde de program eski bir değer görür — ama kaynakları farklıdır ve
farklı düzeltmeler gerektirir: biri bağımlılık listesinin tamamlanmasını, diğeri bağlanma
biçiminin işaretçi tabanlıya çevrilmesini ister.

Bu iki neden arasında ayrım yapmanın pratik bir yolu, kütüphaneyi değiştirip programı
**yeniden derlemeden** yeniden çalıştırmaktır. Bağlanma gömülüyse, kütüphanedeki değişiklik
hiçbir fark yaratmaz — program hâlâ eski, gömülü değeri taşır, çünkü kopyalama derleme
anında bitmiştir ve kütüphanenin sonradan değişmesi programın belleğindeki kopyaya ulaşamaz.
Bağlanma işaretçi tabanlıysa, aynı adım yeni değeri hemen ortaya çıkarır, çünkü program her
seferinde kütüphaneye tekrar erişir. Bu tek adım, listeye yazılmama sorununu tekrarlamaktan
farklıdır: listeye yazılmama sorununda kütüphane hiç doğru okunmaz, bağlanma biçimi
sorununda kütüphane doğru okunur ama okuma anı yanlış zamana denk gelir.

Statik ve paylaşılan bağlamanın üçüncü bir sonucu, kütüphanenin arayüzü değiştiğinde ortaya
çıkar. `struct Kutuphane` gibi bir yapının alan sırası ya da türü değişirse, statik bağlı bir
program bu değişiklikten habersiz kalabilir çünkü kendi gövdesine eski arayüzün bir kopyasını
gömmüştür; yeniden derlenmediği sürece hatayı fark etmez, ama yeniden derlendiğinde derleme
anında hata verir ve sorun görünür hâle gelir. Paylaşılan bağlı bir program ise arayüz
değişikliğini derleme anında değil çalışma anında karşılayabilir — kütüphane yeni arayüzle
yeniden üretilip programın gövdesi değişmeden bırakılırsa, program eski arayüzü beklerken
kütüphane yeni arayüzü sunar ve bu uyumsuzluk derleme hatası değil çalışma zamanı hatası
olarak ortaya çıkar. Bu farkın adı **arayüz uyumluluğudur**: statik bağlamada uyumsuzluk
erken ve gürültülü biçimde durur, paylaşılan bağlamada geç ve sessiz biçimde sürebilir.

## Özet

- Gömülü bağlama, kütüphanenin değerini bağlama anında kopyalar; kütüphane sonradan
  değişse bile program eski değeri taşımaya devam eder — bu dersin ölçtüğü sınıf **kopya**.
- İşaretçi tabanlı bağlama kütüphaneye giden yolu saklar ve her okumada güncel değeri
  görür; bu, gömülü bağlamanın karşıtı olan ortak görünürlüğün bir modelidir.
- `static`/`extern` karşıtlığı başlıkta kurulur: paylaşım isteniyorsa bildirim başlıkta
  `extern` olmalı ve tanım tek bir kaynak dosyada olmalı; birime özel tutmak isteniyorsa
  bildirim hiç başlığa taşınmadan kaynak dosyada `static` kalmalıdır — `static` her dahil
  eden birime ayrı bir kopya verir, `extern` tek bir paylaşılan nesneye bağlar.
- Kütüphanenin arayüzü iki taraf arasında uyuşmazsa işaretçi tabanlı bağlamanın güncel
  değeri güvenli okuması garanti değildir.
- Statik bağlama bir güncellemeyi almak için programın yeniden bağlanmasını ister;
  paylaşılan bağlama güncellemeyi kütüphanenin kendisinden merkezi olarak dağıtır.

## Sonraki Adım

Bir kütüphanenin doğru bağlandığını bilmek, onu kullanan kodun doğru çalıştığını
göstermez. Bir sonraki ders, bir birimi geri kalan programdan **yalıtarak** sınamanın,
bir değişikliğin başka bir teste sızıp sızmadığını nasıl ölçtüğünü ele alıyor.
