Mobil uygulamalarda Conditional Compilation — özü, direktifleri ve çalışma prensibi

Yazar: IT Sectr Yayınlanma: 2026-06-01 Okuma süresi: 9 dk

Conditional Compilation, derleyicinin derleme zamanında bilinen koşullara bağlı olarak kaynak kodunun bazı kısımlarını dahil etmesine veya atlamasına olanak tanır. The Swift Programming Language (2026)'ya göre, #if direktifi makine kodu oluşturulmadan önce AST analizi sırasında işlenir. Conditional Compilation, geliştiricilere tekrarlama olmadan birden fazla platform ve yapılandırma için tek bir kod tabanını sürdürmelerini sağlar.

Ana noktalar

  • Conditional Compilation — platform, yapılandırma veya dil sürümü koşullarına göre kodun seçici olarak derlenmesi tekniği.
  • Direktifler #if, #elseif, #else, #endif — Swift, C, C++, Objective-C'deki ana koşullu derleme yapıları.
  • Kotlin'in ön işlemci direktifleri yoktur — bunun yerine BuildConfig, expect/actual ve sourceSets kullanılır.
  • Avantaj — uygun olmayan platformlar için kod derlenmez, ikili dosya boyutunu küçültür ve hataları ortadan kaldırır.
  • iOS/macOS ortak kod — Conditional Compilation, Apple'ın çapraz platform framework geliştirmesinin temelidir.

Conditional Compilation nedir

Conditional Compilation, derleyicinin koşullu derleme direktiflerini analiz ettiği ve koşulları karşılanan kod bloklarını çıktı ikili dosyasına dahil ettiği bir mekanizmadır. Bu, farklı hedef platformlara ve yapılandırmalara uyum sağlayan tek bir kod tabanına sahip olmayı sağlar.

Kavram, #ifdef, #ifndef, #endif ön işlemci direktifleriyle C/C++'tan gelir. Modern dillerde (Swift, Rust, Go), mekanizma ayrı bir ön işlemci olmadan derleyici seviyesinde çalışır ve güvenliği artırır: koşullu bloklar derlenmeseler bile sözdizimsel olarak doğru olmalıdır.

Apple WWDC oturumu “Embrace Swift” (2025)'e göre, Swift projelerinin yaklaşık %40'ı tek bir hedefte iOS ve macOS'u desteklemek için koşullu derleme kullanır. UIKit ve SwiftUI kullanan projelerde, UI kodu genellikle #if os(iOS) ve #if os(macOS) direktifleriyle bölünür ve iş mantığının yeniden kullanılmasına olanak tanır.

Ana avantaj derleme zamanı güvenliğidir. Uygun olmayan bir platform için kod yalnızca çalıştırılmaz, aynı zamanda derlenmez. Bu, iOS'a özgü koddaki hataların macOS için derlerken ortaya çıkmayacağı ve bunun tersi anlamına gelir. Çalışma zamanı kontrolleri bu tür garantiler sağlamaz.

Swift'te Conditional Compilation

Swift dört ana direktif sağlar: #if, #elseif, #else, #endif. C ön işlemcisinin aksine Swift, tüm dallarda kodun sözdizimsel doğruluğunu gerektirir — derleyici tüm kodu ayrıştırır ancak yalnızca aktif dallar için makine kodu üretir.

Platform kontrolleri os()

Swift yerleşik kontrol fonksiyonlarını destekler: os(iOS), os(macOS), os(tvOS), os(watchOS), os(Linux), os(Windows). Bu fonksiyonlar, uygulamanın derlendiği hedef platformu kontrol eder. && ve || ile kombinasyon, karmaşık koşullar oluşturmayı sağlar.

swift
// iOS, macOS ve tvOS için tek kod
import Foundation

class PlatformService {
    func getSystemVersion() -> String {
        #if os(iOS) || os(tvOS)
            return UIDevice.current.systemVersion
        #elseif os(macOS)
            let vers = ProcessInfo.processInfo.operatingSystemVersion
            return "\(vers.majorVersion).\(vers.minorVersion)"
        #else
            return "unknown"
        #endif
    }
}

Derleyici sürümü kontrolleri

Swift derleyici sürümü kontrolünü destekler: #if swift(>=5.9). Bu, birden fazla Swift sürümünü destekleyen kütüphaneler ve framework'ler için kullanışlıdır. Yeni dil özellikleri (Swift 5.9'daki makrolar gibi) böyle bir kontrollerle korunabilir.

swift
// Geriye dönük uyumluluk
#if swift(>=5.9)
    @MainActor
    struct ModernView: View {
        var body: some View {
            Text("Modern SwiftUI")
        }
    }
#else
    struct ModernView: View {
        var body: some View {
            Text("Legacy SwiftUI")
        }
    }
#endif

Modül kullanılabilirliği kontrolü canImport()

canImport(ModuleName) fonksiyonu, belirtilen modülün mevcut derleme ortamında kullanılabilir olup olmadığını kontrol eder. Bu en esnek mekanizmadır: belirli bir platforma bağlı değildir. Örneğin, CoreHaptics kullanan kod yalnızca bu framework'ün mevcut olduğu cihazlarda derlenir.

swift
#if canImport(CoreHaptics)
    import CoreHaptics

    class HapticManager {
        private var engine: CHHapticEngine?

        func playTapFeedback() {
            guard let engine else { return }
            // Dokunsal geri bildirim uygulaması
        }
    }
#endif

Kotlin ve Android'de alternatifler

Kotlin dilinin ön işlemci direktifleri yoktur. Bunun yerine, Android ekosistemi üç alternatif sunar: BuildConfig alanları (çalışma zamanı kontrolleri), sourceSets (tüm dosyaları değiştirme) ve expect/actual (Kotlin Multiplatform'da).

Gradle'da Source Sets

Gradle sourceSets, farklı flavor'lar veya derleme türleri için farklı sınıf uygulamalarına sahip olmayı sağlar. src/debug/ dizininde hata ayıklama uygulaması, src/release/ dizininde ise sürüm uygulaması bulunur. Derleme sırasında Gradle uygun sourceSet'i seçer ve yalnızca onun dosyalarını derler.

kotlin
// src/debug/kotlin/com/example/Logger.kt
object Logger {
    fun log(tag: String, message: String) {
        Log.d(tag, message)
    }
}

// src/release/kotlin/com/example/Logger.kt
object Logger {
    fun log(tag: String, message: String) {
        // Sürümde No-op
    }
}

Kotlin Multiplatform'da Expect/Actual

KMP, expect mekanizmasını (ortak kodda bildirim) ve actual (belirli bir platform için uygulama) sağlar. Bu, derleme zamanı mekanizmasıdır: iOS için iOS sourceSet'inden actual uygulama derlenir; Android için Android sourceSet'inden. Hedef olmayan uygulamalar derlenmez.

kotlin
// commonMain — expect bildirimi
expect fun getPlatformName(): String

// androidMain — Android için actual
actual fun getPlatformName(): String =
    "Android \${Build.VERSION.SDK_INT}"

// iosMain — iOS için actual
actual fun getPlatformName(): String =
    UIDevice.current.systemName() + " " + UIDevice.current.systemVersion

C/C++ ön işlemcisi ve NDK

Android NDK aracılığıyla yerel kütüphaneler geliştirirken, #ifdef, #ifndef, #define direktifleriyle klasik C/C++ ön işlemcisi kullanılır. Swift'in aksine, C ön işlemcisi metin düzeyinde çalışır — aktif olmayan dallardaki kod sözdizimsel olarak yanlış olabilir.

NDK platform bayrakları

NDK her platform için makrolar tanımlar: __ANDROID__ (Android), __APPLE__ (iOS/macOS), __linux__ (Linux). Mimariler için: __arm__, __aarch64__, __x86_64__. Bu makrolar, hedef platform için derleme yapılırken derleyici tarafından otomatik olarak ayarlanır.

cpp
// Android ve iOS için yerel kod
#include <cstdint>

#ifdef __ANDROID__
    int32_t getJniEnv(JNIEnv* env) {
        return env->GetVersion();
    }
#elif defined(__APPLE__)
    #include <TargetConditionals.h>
    int32_t getOsVersion() {
        #if TARGET_OS_IOS
            return "iOS";
        #elif TARGET_OS_OSX
            return "macOS";
        #endif
    }
#endif

NDK ile çalışırken, C/C++ ön işlemcisinin bir metin değiştirme olduğunu hatırlamak önemlidir. Aktif olmayan bir daldaki sözdizimsel hatayı derleyici görmez, ancak yanlış bir #define aktif bir dalı bozarsa — hata ortaya çıkar. #define zincirlerini en aza indirmek ve constexpr sabitleri kullanmak önerilir.

UniFFI ve Mozilla Application Services aracılığıyla mobil geliştirmede de kullanılan Rust için kendi mekanizması vardır — Cargo.toml'daki özellik bayrakları. Rust'ta #[cfg(target_os = “android”)] gibi bayraklar Swift direktiflerine benzer şekilde çalışır: kontrol ön işlemci değil, derleyici düzeyinde yapılır. Bu, Rust'ı tek bir kod tabanından Android ve iOS için derlenmesi gereken yerel kütüphaneler için çekici bir seçim haline getirir.

Pratik senaryolar ve anti-örüntüler

Conditional Compilation kesin olarak tanımlanmış senaryolarda etkilidir. Yanlış kullanıldığında, test edilmesi ve bakımı zor kod kokusu (code smell) oluşturur. Doğru senaryoları ve tipik hataları inceleyelim.

Doğru senaryolar

İlk senaryo — platform soyutlaması: içinde Conditional Compilation'ın platform uygulamasını seçtiği tek bir cephe. İkincisi — hata ayıklama ve profilleme: sürüme dahil edilmemesi gereken geliştirici araçları. Üçüncüsü — geriye dönük uyumluluk: minimum sürüm güncellenene kadar eski işletim sistemi sürümlerinin desteklenmesi.

SenaryoDilKoşul
Platform soyutlamasıSwift#if os(iOS)
Hata ayıklamaSwift/ObjC#if DEBUG
Geriye dönük uyumlulukSwift#if swift(>=5.7)
Yerel kütüphaneC/C++#ifdef __ANDROID__
A/B testiJava/KotlinBuildConfig.FLAVOR

Anti-örüntüler

En tehlikeli anti-örüntü — kod boyunca direktiflerin yayılması. Her iki dosyadan biri #if içeriyorsa, bu mimarinin yeniden düzenlenmesi gerektiğinin işaretidir. Doğru çözüm — platform kodunu protokollerin/arabirimlerin arkasına çıkarmak ve Bağımlılık Enjeksiyonu kullanmaktır.

  • Her dosyada #if — mimari bir anti-örüntü. Platform kodu protokollerin arkasında izole edilmelidir.
  • İç içe #if — hızla okunamaz hale gelir. İç içe geçme derinliği 2 seviyeyi geçmemelidir.
  • Tüm fonksiyonları kopyalamak — bir fonksiyon #if ve #else'de tamamen kopyalanmışsa, ortak bir bölüme çıkarılmalıdır.
  • Test etme — aktif olmayan dallardaki kod test edilmez. Tüm olası kombinasyonların CI derlemeleri gereklidir.
  • Sihirli bayraklar — yeni geliştirici ekibinin bilmediği belgelenmemiş bayraklar.

Sıkça sorulan sorular

Conditional Compilation çalışma zamanı kontrollerinden nasıl farklıdır?

Conditional Compilation derleme zamanında çalışır: aktif olmayan kod ikili dosyaya girmez. Çalışma zamanı kontrolleri (if / switch) her zaman derlenir, koşul yürütme sırasında kontrol edilir. Birincisi daha güvenli ve verimlidir, ikincisi daha esnektir (yeniden derleme olmadan değiştirilebilir).

Swift'te bir fonksiyon içinde #if kullanılabilir mi?

Evet, Swift fonksiyon içinde #if, döngüler içinde ve hatta ifadeler içinde direktiflere izin verir. Bu, Swift'in ilk sürümlerinde eksik olan özelliklerden biridir. Örneğin: let x = #if DEBUG 1 #else 0 #endif — geçerli kod.

Kotlin neden bir ön işlemci eklemedi?

Kotlin geliştiricileri, ön işlemciyi kırılgan kod kaynağı olarak görerek bilinçli bir şekilde reddettiler. Bunun yerine, expect/actual (derleme zamanı güvenliği) ve Gradle sourceSets (dosya düzeyinde izolasyon) sunarlar. Her iki yaklaşım da metin değiştirmeden daha güvenilirdir.

Aktif olmayan #if dallarındaki kod nasıl test edilir?

CI'da farklı bayrak kombinasyonlarıyla uygulamayı derleyin. Swift için: farklı Active Compilation Conditions ile ayrı Xcode şemaları yapılandırın. Android için: ayrı Build Variants yapılandırın ve her biri için testler çalıştırın. Otomasyon zorunludur.

#if koşulunda sözdizimsel hata olursa ne olur?

Swift'te #if koşulu bir derleyici direktifidir. Koşulun kendisi sözdizimsel olarak yanlışsa (örneğin, os() adında yazım hatası), derleyici bir derleme hatası verecektir. C/C++'ta, ön işlemci makroyu bulamaz ve koşul yanlış olur.

Özet

  • Conditional Compilation — çalışma zamanı kontrollerinin aksine, derleme zamanında hedef olmayan kodu hariç tutan bir derleme tekniği.
  • Swift, os(), canImport(), swift() ile #if'i destekler — tüm dalların sözdizimsel doğruluğunu gerektiren derleme zamanı güvenli direktifler.
  • Kotlin, bir ön işlemci yerine expect/actual ve Gradle sourceSets kullanır — daha güvenilir ancak daha az esnek yaklaşımlar.
  • NDK'da C/C++, platform makroları __ANDROID__, __APPLE__ ile klasik metin ön işlemcisi #ifdef / #ifndef kullanır.
  • Doğru kullanım — platform soyutlaması, hata ayıklama, geriye dönük uyumluluk. Yanlış kullanım — her dosyada #if, derin iç içelik, sihirli bayraklar.
  • CI zorunludur — tüm bayrak kombinasyonları otomatik olarak derlenmeli ve test edilmelidir, aksi takdirde aktif olmayan dallardaki kod ölü hale gelir.

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun