gokayburuc

Rust - Conditional Code Compilation

Rust'ta Koşullu Derleme: #[cfg] Niteliği ve cfg! Makrosu

Giriş

Rust, tek bir kod tabanından farklı platformlar ve yapılandırmalar için derleme yapmayı sağlayan güçlü bir koşullu derleme (conditional compilation) mekanizması sunar. Bu mekanizmanın merkezinde #[cfg] niteliği ve cfg! makrosu yer alır. Bu makale, her iki aracın nasıl çalıştığını, aralarındaki temel farkı ve ne zaman hangisinin kullanılacağını örnek bir kod üzerinden incelemektedir.

Örnek Kodun İncelenmesi

// This function only gets compiled if the target os is linux
#[cfg(target_os = "linux")]
fn are_you_on_linux() {
    println!("You are running linux!");
}

// this function only gets compiled if the target os is not linux
#[cfg(not(target_os = "linux"))]
fn are_you_on_linux() {
    println!("You are *not* running linux!");
}

pub fn execute_cfg_attribute() {
    are_you_on_linux();

    println!("Are you sure?");

    // cfg! expression gives a boolean result
    if cfg!(target_os = "linux") {
        println!("Yes. It's definitely linux");
    } else {
        println!("Yes. It's definitely *not* linux!");
    }
}

Linux Üzerinde Çıktı

You are running linux!
Are you sure?
Yes. It's definitely linux

Linux Dışında (örneğin Windows) Çıktı

You are *not* running linux!
Are you sure?
Yes. It's definitely *not* linux!

Adım Adım Analiz

  1. #[cfg(target_os = "linux")] niteliği: İlk are_you_on_linux fonksiyonu yalnızca hedef işletim sistemi Linux olduğunda derlenir. Diğer platformlarda bu fonksiyon kaynak koddan tamamen dışlanır; derleyici onu var olmayan bir kod gibi görür.

  2. #[cfg(not(target_os = "linux"))] niteliği: İkinci fonksiyon bunun tamamlayıcısıdır. not() koşulu, Linux dışındaki tüm platformlarda geçerli olur. Böylece iki fonksiyon aynı ismi taşısa da, her hedefte yalnızca biri mevcut olur ve isim çakışması yaşanmaz. Bu kalıp, platforma göre değişen API'ler için yaygın bir stratejidir.

  3. cfg! makrosu: execute_cfg_attribute içindeki if cfg!(...) ifadesi farklı bir davranış gösterir. cfg! derleme zamanında true veya false üreten bir makrodur, ancak çevresindeki kod yine de derlenir. Derleyici, dalın koşulunu sabitle bırakır ve optimizasyon aşamasında ölü dalı eler.

Kritik Ayrım: Nitelik mi, Makro mu?

#[cfg] ile cfg! arasındaki fark, koşullu derlemenin ne zaman gerçekleştirildiğine dairdir:

Pratik sonuç: Platforma özgü bir kod, hedefte mevcut olmayan bir API kullanıyorsa #[cfg] gerekir; aksi halde derleme başarısız olur. cfg! ise yalnızca değerin çalışma zamanı davranışını etkilemediği, kodun her platformda derlenebilir olduğu durumlara uygundur.

Yaygın cfg Koşulları

Koşullu derleme yalnızca işletim sistemiyle sınırlı değildir:

#[cfg(target_arch = "x86_64")]        // hedef CPU mimarisi
#[cfg(feature = "serde")]             // Cargo özelliği (feature)
#[cfg(test)]                          // yalnızca cargo test sırasında
#[cfg(debug_assertions)]              // hata ayıklama derlemelerinde
#[cfg(all(unix, not(target_os = "macos")))]
fn linux_specific() {}

Özellikle #[cfg(test)], test modunun üretim derlemesine sızmasını engellediği için günlük Rust geliştirmenin temel taşlarından biridir. all(), any() ve not() işleçleri ise koşulların mantıksal olarak birleştirilmesini sağlar.

Sonuç

#[cfg] niteliği ve cfg! makrosu, Rust'ın koşullu derleme araçlarının tamamlayıcı iki yüzüdür. Nitelik, platforma özgü kodu derleme öncesinde eleyerek tek bir kod tabanından çoklu hedef desteği sağlar; makro ise her iki dalın da derlendiği durumlarda derleme zamanı bilgisini çalışma zamanı mantığına taşır. Platforma özgü API kullanımında #[cfg]'nin eleme davranışı zorunludur; basit dal ayrımında cfg! yeterlidir. Her iki araç birlikte, C'deki önişlemci makrolarının (Örn. #ifdef) sağladığı işlevi, tip güvenliğini ve modül hijyenini koruyarak karşılar.

#rust