---
title: 'WebAssembly Hedefi'
source: 'https://academia.sh/tr/kurslar/rust-ileri/webassembly-hedefi'
course: 'Rust Ekosistemi ve İleri Konular'
language: tr
updated: '2026-09-13T05:09:27+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Koşullu derlemenin, hedefe göre değişen bir kararı kaynakta nasıl ayırdığını yerel hedefte koşturarak gösterir'
    - 'Dosya sistemine dayanan bir gövde ile dayanmayan bir gövdenin aynı sonucu ürettiğini karşılaştırarak kanıtlar'
    - 'Kaynağın taşınabilir görünmesinin taşınabilir olduğu anlamına gelmediğini, hedef bağımlılığının kaynaktan okunması gerektiğini açıklar'
---

# WebAssembly Hedefi

Aynı kaynağın koştuğu hedefe göre farklı bir gövdeye ihtiyaç duyması: standart kütüphanenin bir parçasına (dosya sistemi) dayanan bir gövde ile hiç dayanmayan bir gövde koşullu derlemeyle ayrılır, ikisi de yerel hedefte koşturulur ve aynı sonucu verir.

Önceki ders, sınırın iki **dil** arasında olduğu durumu ölçtü: bildirim doğruysa, hangi
işlemcide ya da işletim sisteminde koştuğunun önemi yoktu. Bu ders aynı bağımsızlığı
tersine çeviriyor. Burada dil aynı kalıyor — kaynağın tamamı Rust — ama koştuğu **hedef**
değişiyor ve bazı gövdeler bu değişikliğe kayıtsız kalamıyor. Bir tarayıcıda koşan bir
hedef, bir dosya sistemine, bir işletim sistemi iş parçacığına ya da bir saate her zaman
erişemez; bu ders o erişimin kaynakta nasıl **görünür** kılındığını ölçüyor.

Önceki dersteki sınır bir bildirimin doğruluğuna, buradaki sınır ise hedefin sunduğu
ortamın kendisine bağlı; ikisi de derleyicinin doğrudan sınayamadığı bir varsayıma
dayanıyor. Bu kısıt Rust'a özgü değil, tarayıcının kendi güvenlik modelinden geliyor. Bir tarayıcı
sekmesi, çalıştırdığı kodu diskten, ağdan ve işletim sisteminden yalıtılmış bir alanda
tutar; sayfanın kendi başına bir dosya açması, bir iş parçacığı oluşturması ya da bir
soket kurması, yalıtımın amacına aykırı düşer. Bu alana derlenen bir program, o alanın
sunduğu olanaklarla sınırlıdır — ve bu olanaklar, aynı programın bir sunucuda ya da bir
masaüstünde koşan sürümünün sahip olduklarından daha dardır. Rust'ın standart kütüphanesi
bu farkı gizlemez: dosya sistemi, iş parçacığı ve zaman gibi modüllerin bir kısmı, bu
yalıtılmış hedefte ya hiç yoktur ya da farklı davranır.

Bu derste yalnız yerel hedef derlenir. Başka bir hedef için gerçek bir derleme
yapılmıyor; hedefe göre değişen karar, koşullu derleme ile **yerel hedefte** gösteriliyor
— kaynaktaki iki gövdeden hangisinin bu makinede seçildiği koşturularak görülüyor, öteki
gövde ise hiç derlenmeden kaynakta duruyor. Bu seçim çalışma zamanında yapılmaz: `cfg`
tarafından yönetilen karar, program çalışmaya başlamadan önce, derleme sırasında verilir.
Aynı ikili dosyanın içinde iki gövdeden birini seçip çalışma anında diğerine geçmek
mümkün değildir — hangi hedef için derlendiyse, o hedefin gövdesi ikili dosyaya girer,
öteki hiç girmez.

## Hedefe Göre Ayrılan Gövde

`#[cfg(...)]` bir çalışma zamanı dallanması değildir; bir `if` ifadesiyle karıştırılmamalı.
`if` çalışma anında bir koşulu sınar ve iki dalın da ikili dosyada yer aldığı, yalnız
birinin çalıştırıldığı bir yapıdır. `cfg` ise derleme anında karar verir: koşulu
sağlamayan öğe, kaynak ağacından hiç kesilmiş gibi, derlemenin geri kalanına hiç
girmez. Bu farkın sonucu, aşağıdaki koşumda görülüyor.

Aşağıdaki koşum bir sensör kaydını okuyan iki gövde tanımlıyor. Biri dosya sisteminden
okuyor; öteki, tarayıcı hedefinde derlenecek bir gövdenin yerini tutuyor ve bu makinede
hiç derlenmiyor. Hangi gövdenin derleneceğine `#[cfg(...)]` özniteliği karar veriyor.

**DS11.** Sensör kaydı dört satırlık bir metin: `12`, `7`, `5`, `21` — toplamı `45`.

```rust
// wasm1.rs — hedefe gore ayrilan govde, yerel hedefte secilen dal
use std::fs;

#[cfg(not(target_family = "wasm"))]
fn kayitlari_oku() -> String {
    // Dosya sistemine dayanan govde: yalnizca dosya sistemi olan hedeflerde derlenir.
    fs::read_to_string("sensor.txt").expect("dosya okunamadi")
}

#[cfg(target_family = "wasm")]
fn kayitlari_oku() -> String {
    // Bu govde tarayici hedefinde derlenir; yerel hedefte hic derlenmez,
    // bu yuzden burada tanimlanmamis bir cagri tasimasi hicbir sey bozmaz.
    govde_wasm_hedefinde_baska_bir_kaynaktan_okur()
}

fn toplam(metin: &str) -> i32 {
    metin.lines().filter_map(|s| s.trim().parse::<i32>().ok()).sum()
}

fn main() {
    fs::write("sensor.txt", "12\n7\n5\n21\n").expect("dosya yazilamadi");
    let icerik = kayitlari_oku();
    println!("dosya sistemine dayanan govde toplami: {}", toplam(&icerik));
}
```

```
dosya sistemine dayanan govde toplami: 45
```

Kaynakta iki `kayitlari_oku` tanımı var, ama derlenen program yalnız birini içeriyor.
`#[cfg(not(target_family = "wasm"))]` işaretli gövde, bu makine wasm ailesinden
olmadığı için derlemeye girdi; `#[cfg(target_family = "wasm")]` işaretli gövde ise hiç
derlenmedi — içindeki çağrı hiçbir yerde tanımlı olmadığı hâlde derleyici bunu fark
etmedi, çünkü o gövdeyi hiç görmedi. **DS12.** Bu, cfg ile dışarıda bırakılan bir gövdenin
söz dizimi geçerli olduğu sürece hiçbir semantik denetimden geçmediğini gösteriyor;
"derlenmeyen" ile "yanlış" aynı şey değil, derlenmeyen gövde hakkında derleyici hiçbir
yargı vermiyor.

Bu, önceki dersteki yabancı işlev bildirimine benziyor görünse de ayrı bir güvence
taşıyor. `extern "C"` bildirimi, derleyicinin hiç görmediği ama gerçekten var olan ve
bağlanması gereken bir gövdeyi tarif ediyordu; bağlayıcı o adı bulamazsa derleme çöküyordu.
`#[cfg(target_family = "wasm")]` ile işaretli gövde ise bu makinede **hiç aranmıyor** —
içinde geçen `govde_wasm_hedefinde_baska_bir_kaynaktan_okur` adının bu programın hiçbir
yerinde tanımlı olmaması önemli değil, çünkü o ad hiçbir zaman bağlayıcıya ulaşmıyor.
Yabancı fonksiyon arayüzünde devredilen güvence bir bildirimin doğruluğuydu; burada
devredilen hiçbir şey yok, çünkü o gövde bu derlemenin bir parçası bile değil.

`kayitlari_oku` içindeki `.expect(...)` çağrısı da bilinçli bir seçim: dosya, aynı
`main` işlevi içinde bir satır önce yazıldığı için okuma başarısız olmayacağı biliniyor,
ama Rust bunu derleme zamanında bilemiyor — `read_to_string` her zaman bir `Result`
döndürür ve bu değer ele alınmak zorunda. `.expect(...)` bu değeri açıp, başarısızlık
durumunda panikle durmayı seçiyor; bu ders panik tetiklemediği için bu yol yalnızca
başarı durumunda izleniyor.

Yukarıdaki koşum `target_family = "wasm"` yazımını seçiyor; dilin tanıdığı öznitelik
adlarından biri de `target_arch = "wasm32"`dir ve ikisi aynı şeyi sormaz. `target_family`,
bir hedefin ait olduğu geniş aileyi (wasm ailesi, unix ailesi gibi) sorar; `target_arch`
ise işlemci mimarisinin adını (`wasm32`, `x86_64` gibi) sorar. Bu derste aile sorulmuştu,
çünkü ölçülen ayrım mimariye değil, hedefin sunduğu ortam sınıfına dayanıyordu — dosya
sistemi bulunmayan bir hedef, tek bir mimariyle sınırlı değildir. Hangi öznitelik adının
seçildiği kaynaktan okunabilir bir karardır ve gövdenin hangi soruya göre ayrıldığını
söyler.

## Dosya Sistemine Dayanmayan Karşılık

Bir gövdenin `cfg` ile ayrılması, o gövdenin varlığını sürdürmesi gerektiği anlamına
gelmez. Aynı sensör kaydı, dosya sistemine hiç dokunmadan da elde edilebilir — bu ders
için değer kaynağın içine gömülü. Bu iki seçenek arasındaki fark bir uygulama ayrıntısı
değildir: ilki verinin **çalışma zamanında** bir kaynaktan geldiğini varsayar, ikincisi
verinin **derleme zamanında** zaten bilindiğini varsayar. Hangi varsayımın geçerli
olduğu, çözülen problemin kendisine bağlıdır — sensör kaydı gerçekten değişen bir veriyse
dosya (ya da onun yerini tutan başka bir kaynak) gerekir; sabit bir yapılandırma değeriyse
gömülü sabit yeterlidir.

```rust
// wasm2.rs — dosya sistemine hic dayanmayan, hedeften bagimsiz govde
const GOMULU_KAYITLAR: &str = "12\n7\n5\n21\n";

fn toplam(metin: &str) -> i32 {
    metin.lines().filter_map(|s| s.trim().parse::<i32>().ok()).sum()
}

fn main() {
    let toplam_deger = toplam(GOMULU_KAYITLAR);
    println!("gomulu govde toplami: {}", toplam_deger);
}
```

```
gomulu govde toplami: 45
```

İki gövde de aynı sonucu (`45`) verdi, ama farklı yollardan. Dosya sistemine dayanan
gövdenin çalışması için ortamın bir dosya sistemi **sunması** gerekiyordu — bu makinede
sunuluyor, ama bir tarayıcı hedefinde bu varsayım genellikle geçerli değildir, çünkü
tarayıcı sayfası doğrudan bir dosya sistemine erişemez. Gömülü gövde ise hiçbir dış
kaynağa bağlı değil; verisi kaynağın kendisinde, derleme anında sabitleniyor. **DS13.**
Aynı sonucu üreten bu iki yazım, hedef bağımsız bir görevi (dört sayıyı toplamak) hedefe
bağlı bir kaynaktan (dosya) ve hedeften bağımsız bir kaynaktan (gömülü sabit) besleyerek
gösteriyor.

Verinin kaynağa gömülmesi burada `const` bildirimiyle yapıldı; değer derleme sırasında
ikili dosyanın bir parçası olur, çalışma zamanında hiçbir dış kaynak istemez. Bu yazım
yalnızca tarayıcı hedefiyle sınırlı bir çözüm değildir — bir dosya sisteminin **hiç
bulunmadığı**, yalnızca sabit bir bellek düzeninin var olduğu ortamlar için de aynı
yaklaşım kullanılır. Sıradaki ders bu ortamı doğrudan ele alacak; oradaki kısıt tarayıcının
yalıtılmış alanının değil, standart kütüphanenin kendisinin yokluğudur.

## İkinci Bir Ayrım: İş Parçacığı

Dosya sistemi tek örnek değil. Aynı kalıp, birden çok iş parçacığı açma yeteneği için de
geçerli — bir tarayıcı sayfasının çalıştırdığı kod, işletim sisteminin sıradan iş
parçacığı oluşturma çağrısına her zaman erişemez. Bir iş parçacığı açmak, işletim
sisteminden yeni bir yürütme birimi ayırmasını ve bu birimi zamanlamasını ister; bu,
dosya açmaktan farklı bir hizmet ama aynı sınıftan bir istek — ikisi de tek başına
kaynağın içinde yürütülemez, ortamın bir şey **sağlamasını** bekler. Aşağıdaki koşum aynı
`cfg` düzenini bir kez daha kuruyor: yerel hedefte derlenen gövde bir iş parçacığı açıp
sonucunu topluyor, wasm ailesi için yazılmış gövde ise yine bu makinede hiç derlenmiyor.

**DS14.** Hesaplanan değer `6 * 7`, yani `42`; iş parçacığının döndürdüğü değer ana
gövdeye `join` çağrısıyla toplanıyor.

```rust
// wasm3.rs — is parcasina dayanan govde, yerel hedefte secilen dal
use std::thread;

#[cfg(not(target_family = "wasm"))]
fn deger_uret() -> i32 {
    // Is parcasi acan govde: coklu is parcasi destegi olmayan hedeflerde derlenmez.
    let is_parcasi = thread::spawn(|| 6 * 7);
    is_parcasi.join().expect("is parcasi cokmus olamaz")
}

#[cfg(target_family = "wasm")]
fn deger_uret() -> i32 {
    wasm_hedefinde_ayri_bir_yontemle_hesaplanir()
}

fn main() {
    println!("is parcasina dayanan govde: {}", deger_uret());
}
```

```
is parcasina dayanan govde: 42
```

Bu koşumda da fark aynı yerde: `thread::spawn` çağrısı ayrı bir iş parçacığı açılmasını
işletim sisteminden ister ve bu istek her hedefte karşılanamaz. `#[cfg(not(target_family
= "wasm"))]` etiketi bu bağımlılığı üstlenen gövdeyi işaretliyor; aynı hesabı doğrudan,
hiçbir iş parçacığı açmadan yapan bir gövde de yazılabilirdi (`6 * 7` tek satırda
hesaplanır) ve o gövde her hedefte aynı şekilde çalışırdı. Buradaki nokta önceki
ölçümle aynı: hedefe bağlı olan, hesabın kendisi değil, hesabı **nasıl** yürüttüğüdür.

Bu iki örnek (dosya, iş parçacığı) arasında bir de fark var: dosya sisteminin yokluğu
genellikle bir hata değeriyle kendini gösterir — çağrı bir `Result` döndürür ve başarısız
olursa bu değer üzerinden anlaşılır. İş parçacığı açma yeteneğinin durumu hedefe göre
değişir; bazı hedeflerde işlev hiç bulunmaz ve kaynak o işlevi kullanan haliyle
derlenmez, bazı hedeflerde ise farklı bir kısıtla (örneğin tek bir iş parçacığıyla
sınırlı olarak) çalışabilir. İki durumda da ortak olan, bu farkın kaynakta bir yerde
görünür olması gerektiğidir — ya bir `cfg` etiketiyle, ya da dönen değerin ele alınma
biçimiyle.

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

Yukarıdaki iki koşum da bu makinede aynı sonucu verdi — ama bu, dosya sistemine dayanan
gövdenin her hedefte çalışacağı anlamına gelmez. Kaynağın kendisi, hangi kısmının hedefe
bağlı olduğunu zaten söylüyor: `#[cfg(not(target_family = "wasm"))]` etiketi, altındaki
gövdenin wasm ailesi dışındaki hedeflerde derleneceğini, `#[cfg(target_family = "wasm")]`
etiketi ise karşıt gövdenin yalnız wasm hedefinde derleneceğini beyan ediyor. Bu bilgiye
ulaşmak için o hedefte bir koşum çalıştırmaya gerek yok; etiketin kendisi, koşuma
bakmadan okunabilen bir bildirim.

Bunun tersi de doğru: `cfg` etiketi taşımayan bir gövde, otomatik olarak her hedefte
çalışacağı anlamına gelmez. `toplam` işlevi bu derste hiçbir `cfg` taşımıyor ve iki
gövde tarafından da paylaşılıyor — çünkü yalnız metin ayrıştırma ve toplama yapıyor, dış
bir kaynağa dokunmuyor. Ama bir işlev `cfg` taşımadığı hâlde içinde iş parçacığı açan,
gerçek zamanı okuyan ya da bir soket bağlantısı kuran bir çağrı taşısaydı, bu bağımlılık
kaynaktan **görünmezdi** — derleyici böyle bir çağrıyı reddetmez, yalnızca o hedefte
derlerken ya derleme hatası verir ya da çalışma zamanında beklenmeyen bir sonuç üretir.
Kaynağın taşınabilir görünmesi, taşınabilir olduğunu göstermez; hangi varsayımın hedefe
bağlı olduğu ancak kaynaktaki `cfg` etiketlerinden ve kullanılan standart kütüphane
parçalarından okunabilir, bir koşumdan değil.

Bu derste ölçülen iki örnek (dosya sistemi, iş parçacığı) tükenmez bir liste değil, aynı
sınırın iki yüzü. Gerçek zamanın okunması da benzer bir sınıra girer: bir hedefin sistem
saatine erişimi olmayabilir ya da bu erişim farklı bir yolla sağlanabilir. Üç örneğin
ortak yanı, hepsinin işletim sisteminden ya da donanımdan bir **hizmet istemesidir** —
dosya sistemi bir depolama hizmeti, iş parçacığı bir zamanlama hizmeti, saat bir donanım
sayacı hizmeti ister. Yalıtılmış bir hedef bu hizmetlerin bir kısmını hiç sunmaz ya da
farklı bir arayüzden sunar; kaynak, hangi işlevin hangi hizmeti istediğini `cfg`
etiketleriyle ya da kullanılan modülün kendisiyle işaretlediği ölçüde okunabilir kalır.
Üçü de bu derste koşturulmuyor; yalnızca dosya sistemi ve iş parçacığı örnekleri
koşturuldu, saat örneği aynı sınıfa ait olduğu için yalnızca anılıyor.

Bu okunabilirlik, gerçek çok hedefli kaynakların (birden çok işletim sistemi ve mimaride
derlenmesi beklenen kütüphanelerin) neden `cfg` etiketleriyle dolu göründüğünün de
nedenidir; bu ders boyunca kurulan iki örnek, o kaynaklardaki düzenlerin küçük ölçekli
bir modelinden ibaret. Bir kaynağı bir hedefe taşımadan önce güvenilir bir yöntem, kaynaktaki `cfg`
etiketlerini ve dış hizmet isteyen çağrıları taramaktır — bu derste yapılan tam olarak
budur, yalnızca tek bir hedef çiftinde (yerel hedef ile wasm ailesi) ve tek bir gövde
üzerinde.

## Özet

- Hedefe göre değişen bir karar, `#[cfg(...)]` öznitelikleriyle kaynakta iki ayrı gövdeye
  bölünebilir; yerel hedefte yalnız biri derlenir, öteki hiç derlenmeden kaynakta durur —
  `cfg` bir `if` gibi çalışma anında dallanmaz, derleme anında karar verir
- Tarayıcı hedefi için gerçek bir derleme yapılmadı; hedefe bağlı karar kaynak
  üzerinden **modellendi**
- Dosya sistemine dayanan gövde ile dayanmayan gövde aynı sensör toplamını (`45`) verdi;
  fark sonuçta değil, hangi ortam varsayımına dayandıklarında
- Bir tarayıcı hedefinin dosya sistemi gibi bazı ortam olanaklarını sunmaması, bu hedefin
  verdiği güvencenin dilin kendisinden değil hedeften geldiğini gösterir — sınıf **dilin
  dışında**
- Dosya sistemi ile iş parçacığı açma aynı sınırın iki ayrı örneği: ikisi de işletim
  sisteminden bir hizmet ister ve bu hizmet her hedefte aynı biçimde sunulmaz
- Kaynağın taşınabilir görünmesi taşınabilir olduğu anlamına gelmez; hedef bağımlılığı
  `cfg` etiketlerinden ve kullanılan standart kütüphane parçalarından, koşumdan değil,
  kaynaktan okunur

## Sonraki Adım

Bu derste sınır, aynı dilin iki hedefi arasındaydı; fark, ortamın hangi olanakları
sunduğuydu — dosya sistemi de iş parçacığı da işletim sisteminin **var olduğu**
varsayımına dayanıyordu, yalnızca o varsayımın karşılanıp karşılanmadığı hedeften
hedefe değişiyordu. Sıradaki ders bu sınırı bir uca taşıyor: standart kütüphanenin **hiç**
bulunmadığı, işletim sisteminin kendisinin olmadığı bir ortam. Orada gömülü sabit gibi
hedeften bağımsız bir yazım bile, artık bellek ayırmanın kendisinin var olup olmadığı
sorusuyla karşılaşacak — bu derste "hedefe bağlı" olan yalnız birkaç işlevdi, orada
"hedefe bağlı" olan, programın bütün gövdesinin nasıl yazılacağını belirleyen bir
kısıttır.
