Mobil ilovalarda shartli kompilyatsiya — mohiyati, direktivalar va ishlash prinsipi

Muallif: IT Sectr Nashr etilgan: 2026-06-01 O'qish vaqti: 9 daq

Shartli kompilyatsiya kompilyatorga qurish bosqichida ma'lum bo'lgan shartlarga qarab manba kodining qismlarini kiritish yoki o'tkazib yuborish imkonini beradi. The Swift Programming Language (2026) ma'lumotlariga ko'ra, #if direktivasi mashina kodi yaratilishidan oldin AST tahlil bosqichida qayta ishlanadi. Shartli kompilyatsiya dasturchilarga takrorlanmasdan bir nechta platforma va konfiguratsiyalar uchun yagona kod bazasini saqlash imkoniyatini beradi.

Asosiy

  • Shartli kompilyatsiya — platforma, konfiguratsiya yoki til versiyasi shartlariga ko'ra kodni tanlab kompilyatsiya qilish texnikasi.
  • Direktivalar #if, #elseif, #else, #endif — Swift, C, C++, Objective-C'da shartli kompilyatsiyaning asosiy konstruksiyalari.
  • Kotlin preprotsessor direktivalariga ega emas — ularning o'rniga BuildConfig, expect/actual va sourceSets ishlatiladi.
  • Afzalligi — mos kelmaydigan platformalar uchun kod kompilyatsiya qilinmaydi, bu esa binar fayl hajmini kamaytiradi va xatolarni bartaraf qiladi.
  • iOS/macOS umumiy kod — shartli kompilyatsiya Apple'ning o'zaro platforma frameworklari ishlab chiqishning asosidir.

Shartli kompilyatsiya nima

Shartli kompilyatsiya — kompilyator shartli kompilyatsiya direktivalarini tahlil qiladigan va chiqish binar fayliga faqat shartlari bajariladigan kod bloklarini kiritadigan mexanizm. Bu turli maqsadli platformalar va konfiguratsiyalarga moslashadigan yagona kod bazasiga ega bo'lish imkonini beradi.

Kontseptsiya C/C++ dan #ifdef, #ifndef, #endif preprotsessor direktivalari bilan kelgan. Zamonaviy tillarda (Swift, Rust, Go) mexanizm alohida preprotsessorsiz kompilyator darajasida ishlaydi, bu xavfsizlikni oshiradi: shartli bloklar kompilyatsiya qilinmasa ham sintaktik jihatdan to'g'ri bo'lishi kerak.

Apple WWDC “Embrace Swift” (2025) sessiyasi ma'lumotlariga ko'ra, Swift loyihalarining taxminan 40% i bir targetda iOS va macOS ni qo'llab-quvvatlash uchun shartli kompilyatsiyadan foydalanadi. UIKit va SwiftUI bilan loyihalarda UI kodi tez-tez #if os(iOS) va #if os(macOS) direktivalari bilan ajratiladi, bu biznes mantiqini qayta ishlatish imkonini beradi.

Asosiy afzallik — kompilyatsiya bosqichida xavfsizlik. Mos kelmaydigan platforma uchun kod nafaqat bajarilmaydi, balki kompilyatsiya ham qilinmaydi. Bu iOS-ga xos koddagi xatolar macOS uchun qurish paytida namoyon bo'lmasligini anglatadi va aksincha. Ijro vaqti tekshiruvlari bunday kafolatni bermaydi.

Swift'da shartli kompilyatsiya

Swift to'rtta asosiy direktivani taqdim etadi: #if, #elseif, #else, #endif. C preprotsessoridan farqli o'laroq, Swift barcha tarmoqlarda kodning sintaktik to'g'riligini talab qiladi — kompilyator barcha kodni tahlil qiladi, lekin mashina kodini faqat faol tarmoqlar uchun yaratadi.

Platforma tekshiruvlari os()

Swift o'rnatilgan tekshirish funksiyalarini qo'llab-quvvatlaydi: os(iOS), os(macOS), os(tvOS), os(watchOS), os(Linux), os(Windows). Bu funksiyalar ilova qurilayotgan maqsadli platformani tekshiradi. && va || bilan kombinatsiya murakkab shartlar yaratish imkonini beradi.

swift
// iOS, macOS va tvOS uchun yagona 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
    }
}

Kompilyator versiyasini tekshirish

Swift kompilyator versiyasini tekshirishni qo'llab-quvvatlaydi: #if swift(>=5.9). Bu bir nechta Swift versiyalarini qo'llab-quvvatlovchi kutubxonalar va frameworklar uchun foydali. Tilning yangi imkoniyatlari (masalan, Swift 5.9 da makroslar) bunday tekshirish bilan himoyalanishi mumkin.

swift
// Orqaga muvofiqlik
#if swift(>=5.9)
    @MainActor
    struct ModernView: View {
        var body: some View {
            Text("Zamonaviy SwiftUI")
        }
    }
#else
    struct ModernView: View {
        var body: some View {
            Text("Eski SwiftUI")
        }
    }
#endif

Modul mavjudligini tekshirish canImport()

canImport(ModuleName) funksiyasi ko'rsatilgan modul joriy qurish muhitida mavjud yoki yo'qligini tekshiradi. Bu eng moslashuvchan mexanizm: muayyan platformaga bog'liq emas. Masalan, CoreHaptics dan foydalanadigan kod faqat ushbu framework mavjud bo'lgan qurilmalarda kompilyatsiya qilinadi.

swift
#if canImport(CoreHaptics)
    import CoreHaptics

    class HapticManager {
        private var engine: CHHapticEngine?

        func playTapFeedback() {
            guard let engine else { return }
            // Taktil javobni implementatsiya qilish
        }
    }
#endif

Kotlin va Android'da alternativlar

Kotlin tili preprotsessor direktivalariga ega emas. Buning o'rniga Android ekosistemasi uchta alternativni taklif qiladi: BuildConfig maydonlari (ijro vaqti tekshiruvlari), sourceSets (butun fayllarni almashtirish) va expect/actual (Kotlin Multiplatform'da).

Gradle'da Source Sets

Gradle sourceSets turli flavorlar yoki qurish turlari uchun sinflarning turli implementatsiyalariga ega bo'lish imkonini beradi. src/debug/ katalogida debug uchun implementatsiya, src/release/ da — release uchun joylashgan. Qurish paytida Gradle tegishli sourceSet ni tanlaydi va faqat uning fayllarini kompilyatsiya qiladi.

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) {
        // Release da No-op
    }
}

Kotlin Multiplatform'da Expect/Actual

KMP expect (umumiy koda deklaratsiya) va actual (muayyan platforma uchun implementatsiya) mexanizmini taqdim etadi. Bu kompilyatsiya bosqichida ishlaydigan mexanizm: iOS uchun iOS sourceSet dan actual implementatsiya, Android uchun esa Android sourceSet dan kompilyatsiya qilinadi. Maqsad bo'lmagan implementatsiyalar kompilyatsiya qilinmaydi.

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

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

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

C/C++ preprotsessori va NDK

Android NDK orqali native kutubxonalarni ishlab chiqishda klassik C/C++ preprotsessori #ifdef, #ifndef, #define direktivalari bilan ishlatiladi. Swift dan farqli o'laroq, C preprotsessori matn darajasida ishlaydi — faol bo'lmagan tarmoqlardagi kod sintaktik jihatdan noto'g'ri bo'lishi mumkin.

NDK platforma bayroqlari

NDK har bir platforma uchun makroslarni belgilaydi: __ANDROID__ (Android), __APPLE__ (iOS/macOS), __linux__ (Linux). Arxitekturalar uchun: __arm__, __aarch64__, __x86_64__. Bu makroslar kompilyator tomonidan maqsadli platforma uchun qurish paytida avtomatik ravishda o'rnatiladi.

cpp
// Android va iOS uchun native 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 bilan ishlashda C/C++ preprotsessori matn almashtirish ekanligini yodda tutish muhim. Agar faol bo'lmagan tarmoqda sintaktik xato bo'lsa, kompilyator uni ko'rmaydi, lekin noto'g'ri #define sababli faol tarmoq buzilsa — xato namoyon bo'ladi. #define zanjirlarini minimallashtirish va constexpr konstantalaridan foydalanish tavsiya etiladi.

UniFFI va Mozilla Application Services orqali mobil ishlab chiqishda ham qo'llaniladigan Rust uchun Cargo.toml'da o'z mexanizmi — feature flags mavjud. Rust'dagi #[cfg(target_os = "android")] kabi bayroqlar Swift direktivalariga o'xshash ishlaydi: tekshirish preprotsessor emas, kompilyator darajasida amalga oshiriladi. Bu Rust ni bir kod bazasidan Android va iOS uchun kompilyatsiya qilinishi kerak bo'lgan native kutubxonalar uchun jozibador tanlovga aylantiradi.

Amaliy stsenariylar va anti-na'munalar

Shartli kompilyatsiya qat'iy belgilangan stsenariylarda samarali. Noto'g'ri foydalanilganda, sinash va saqlash qiyin bo'lgan yomon hidli kod yaratadi. To'g'ri stsenariylar va odatiy xatolarni ko'rib chiqaylik.

To'g'ri stsenariylar

Birinchi stsenariy — platforma abstraksiyasi: yagona fasad, uning ichida shartli kompilyatsiya platforma implementatsiyasini tanlaydi. Ikkinchi — nosozliklarni tuzatish va profillash: relizga kirmasligi kerak bo'lgan dasturchi vositalari. Uchinchi — orqaga muvofiqlik: minimal versiya yangilanmaguncha eski operatsion tizim versiyalarini qo'llab-quvvatlash.

StsenariyTilShart
Platforma abstraksiyasiSwift#if os(iOS)
Nosozliklarni tuzatishSwift/ObjC#if DEBUG
Orqaga muvofiqlikSwift#if swift(>=5.7)
Native kutubxonaC/C++#ifdef __ANDROID__
A/B testlashJava/KotlinBuildConfig.FLAVOR

Anti-na'munalar

Eng xavfli anti-na'muna — direktivalarning butun kod bo'ylab tarqalishi. Har ikkinchi faylda #if bo'lsa, bu arxitektura qayta qurishni talab qilayotganining signalidir. To'g'ri yechim — platforma kodini protokollar/interfeyslar ortiga chiqarish va Dependency Injection dan foydalanish.

  • Har bir faylda #if — arxitektura anti-na'munasi. Platforma kodi protokollar bilan izolyatsiya qilinishi kerak.
  • Ichma-ich #if — tez o'qib bo'lmaydigan holga keladi. Ichma-ichlik chuqurligi 2 darajadan oshmasligi kerak.
  • Butun funksiyalarni takrorlash — agar funksiya to'liq #if va #else da ko'chirilgan bo'lsa, uni umumiy qismga chiqarish kerak.
  • Sinash — faol bo'lmagan tarmoqlardagi kod sinovdan o'tkazilmaydi. Barcha mumkin bo'lgan kombinatsiyalarni CI da qurish zarur.
  • Sehrli bayroqlar — yangi dasturchilar jamoasi bilmagan hujjatsiz bayroqlar.

Tez-tez beriladigan savollar

Shartli kompilyatsiya ijro vaqti tekshiruvlaridan nima bilan farq qiladi?

Shartli kompilyatsiya kompilyatsiya bosqichida ishlaydi: faol bo'lmagan kod binar faylga kirmaydi. Ijro vaqti tekshiruvlari (if / switch) har doim kompilyatsiya qilinadi, shart ijro paytida tekshiriladi. Birinchisi xavfsizroq va samaraliroq, ikkinchisi moslashuvchanroq (qayta qurmasdan o'zgartirish mumkin).

Swift'da funksiya ichida #if ishlatish mumkinmi?

Ha, Swift funksiyalar ichida, sikllarda va hatto ifodalar ichida #if direktivalariga ruxsat beradi. Bu Swift ning dastlabki versiyalarida mavjud bo'lmagan imkoniyatlardan biridir. Masalan: let x = #if DEBUG 1 #else 0 #endif — to'g'ri kod.

Nega Kotlin preprotsessor qo'shmadi?

Kotlin yaratuvchilari preprotsessordan ongli ravishda voz kechdilar, chunki uni mo'rt kod manbai deb hisoblaydilar. Buning o'rniga ular expect/actual (kompilyatsiya bosqichida xavfsizlik) va Gradle sourceSets (fayl darajasida izolyatsiya) ni taklif qiladilar. Ikkala yondashuv ham matn almashtirishdan ishonchliroq.

Faol bo'lmagan #if tarmoqlaridagi kodni qanday sinash kerak?

Ilovani CI da turli bayroq kombinatsiyalari bilan qurish. Swift uchun: turli Active Compilation Conditions bilan alohida Xcode sxemalarini sozlash. Android uchun: alohida Build Variants ni sozlash va har biri uchun testlarni ishga tushirish. Avtomatlashtirish majburiy.

#if sharti sintaktik xato bo'lsa nima bo'ladi?

Swift'da #if sharti kompilyator direktivasidir. Agar shartning o'zi sintaktik jihatdan noto'g'ri bo'lsa (masalan, os() nomida xatolik), kompilyator kompilyatsiya xatosi beradi. C/C++ da preprotsessor oddiygina makrosni topmaydi va shart yolg'on bo'ladi.

Xulosa

  • Shartli kompilyatsiya — qurish bosqichida maqsadli bo'lmagan kodni istisno qiladigan kompilyatsiya texnikasi, ijro vaqti tekshiruvlaridan farqli ravishda.
  • Swift os(), canImport(), swift() bilan #if ni qo'llab-quvvatlaydi — barcha tarmoqlarning sintaktik to'g'riligini talab qiladigan kompilyatsiya vaqti xavfsiz direktivalari.
  • Kotlin preprotsessor o'rniga expect/actual va Gradle sourceSets dan foydalanadi — ishonchliroq, lekin kamroq moslashuvchan yondashuvlar.
  • NDK da C/C++ __ANDROID__, __APPLE__ platforma makroslari bilan klassik matn preprotsessori #ifdef / #ifndef dan foydalanadi.
  • To'g'ri qo'llash — platforma abstraksiyasi, nosozliklarni tuzatish, orqaga muvofiqlik. Noto'g'ri qo'llash — har bir faylda #if, chuqur ichma-ichlik, sehrli bayroqlar.
  • CI majburiy — barcha bayroq kombinatsiyalari avtomatik ravishda qurilishi va sinovdan o'tkazilishi kerak, aks holda faol bo'lmagan tarmoqlardagi kod o'lik bo'ladi.

Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz

IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.

Loyihani muhokama qilish

Shuningdek o'qing