Conditional Compilation কম্পাইলারকে বিল্ড সময়ে পরিচিত শর্তের উপর ভিত্তি করে সোর্স কোডের অংশগুলি অন্তর্ভুক্ত বা বাদ দেওয়ার অনুমতি দেয়। The Swift Programming Language (2026) অনুসারে, #if নির্দেশিকা মেশিন কোড জেনারেশনের আগে AST বিশ্লেষণের সময় প্রক্রিয়া করা হয়। Conditional Compilation ডেভেলপারদের নকল ছাড়াই একাধিক প্ল্যাটফর্ম এবং কনফিগারেশনের জন্য একটি একক কোডবেস বজায় রাখার ক্ষমতা দেয়।
মূল বিষয়
Conditional Compilation একটি প্রক্রিয়া যেখানে কম্পাইলার শর্তসাপেক্ষ কম্পাইলেশন নির্দেশিকাগুলি বিশ্লেষণ করে এবং আউটপুট বাইনারিতে কেবল সেই কোড ব্লকগুলি অন্তর্ভুক্ত করে যাদের শর্ত পূরণ হয়। এটি একটি একক কোডবেস রাখার অনুমতি দেয় যা বিভিন্ন লক্ষ্য প্ল্যাটফর্ম এবং কনফিগারেশনের সাথে খাপ খায়।
ধারণাটি C/C++ থেকে প্রিপ্রসেসর নির্দেশিকা #ifdef, #ifndef, #endif সহ এসেছে। আধুনিক ভাষায় (Swift, Rust, Go), প্রক্রিয়াটি আলাদা প্রিপ্রসেসর ছাড়াই কম্পাইলার স্তরে কাজ করে, যা নিরাপত্তা বাড়ায়: শর্তসাপেক্ষ ব্লকগুলি বাক্যগতভাবে সঠিক হতে হবে এমনকি যদি সেগুলি কম্পাইল না হয়।
Apple WWDC সেশন “Embrace Swift” (2025) অনুসারে, প্রায় 40% Swift প্রজেক্ট একটি একক টার্গেটে iOS এবং macOS সমর্থন করতে শর্তসাপেক্ষ কম্পাইলেশন ব্যবহার করে। UIKit এবং SwiftUI সহ প্রজেক্টের জন্য, UI কোড প্রায়ই #if os(iOS) এবং #if os(macOS) নির্দেশিকা দ্বারা বিভক্ত হয়, যা বিজনেস লজিক পুনরায় ব্যবহারের অনুমতি দেয়।
মূল সুবিধা হল কম্পাইল-টাইম নিরাপত্তা। অনুপযুক্ত প্ল্যাটফর্মের কোড কেবল নির্বাহিত হয় না, বরং কম্পাইলও হয় না। এর অর্থ হল iOS-নির্দিষ্ট কোডের ত্রুটিগুলি macOS-এর জন্য বিল্ড করার সময় প্রকাশ পাবে না, এবং এর বিপরীত। রানটাইম চেকগুলি এমন গ্যারান্টি দেয় না।
Swift চারটি মূল নির্দেশিকা প্রদান করে: #if, #elseif, #else, #endif। C প্রিপ্রসেসরের বিপরীতে, Swift সমস্ত শাখায় কোডের বাক্যগত শুদ্ধতা প্রয়োজন — কম্পাইলার সমস্ত কোড পার্স করে কিন্তু কেবল সক্রিয় শাখাগুলির জন্য মেশিন কোড জেনারেট করে।
Swift অন্তর্নির্মিত চেক ফাংশন সমর্থন করে: os(iOS), os(macOS), os(tvOS), os(watchOS), os(Linux), os(Windows)। এই ফাংশনগুলি লক্ষ্য প্ল্যাটফর্ম পরীক্ষা করে যার জন্য অ্যাপ্লিকেশন তৈরি করা হচ্ছে। && এবং || এর সাথে সংমিশ্রণ জটিল শর্ত তৈরি করার অনুমতি দেয়।
// iOS, macOS এবং tvOS-এর জন্য একীভূত কোড
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
}
}
Swift কম্পাইলার সংস্করণ চেক সমর্থন করে: #if swift(>=5.9)। এটি লাইব্রেরি এবং ফ্রেমওয়ার্কগুলির জন্য উপযোগী যা একাধিক Swift সংস্করণ সমর্থন করে। নতুন ভাষা বৈশিষ্ট্যগুলি (যেমন Swift 5.9-এ ম্যাক্রো) এই ধরনের চেক দ্বারা সুরক্ষিত করা যেতে পারে।
// পশ্চাদগামী সামঞ্জস্যতা
#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
canImport(ModuleName) ফাংশন পরীক্ষা করে যে নির্দিষ্ট মডিউল বর্তমান বিল্ড পরিবেশে উপলব্ধ কিনা। এটি সবচেয়ে নমনীয় প্রক্রিয়া: এটি একটি নির্দিষ্ট প্ল্যাটফর্মের সাথে আবদ্ধ নয়। উদাহরণস্বরূপ, CoreHaptics ব্যবহার করা কোড কেবল সেই ডিভাইসগুলিতে কম্পাইল হবে যেখানে এই ফ্রেমওয়ার্ক উপলব্ধ।
#if canImport(CoreHaptics)
import CoreHaptics
class HapticManager {
private var engine: CHHapticEngine?
func playTapFeedback() {
guard let engine else { return }
// স্পর্শ প্রতিক্রিয়া বাস্তবায়ন
}
}
#endif
Kotlin ভাষায় প্রিপ্রসেসর নির্দেশিকা নেই। পরিবর্তে, Android ইকোসিস্টেম তিনটি বিকল্প অফার করে: BuildConfig ফিল্ড (রানটাইম চেক), sourceSets (সম্পূর্ণ ফাইল প্রতিস্থাপন), এবং expect/actual (Kotlin Multiplatform-এ)।
Gradle sourceSets বিভিন্ন ফ্লেভার বা বিল্ড টাইপের জন্য আলাদা ক্লাস বাস্তবায়নের অনুমতি দেয়। src/debug/ ডিরেক্টরিতে ডিবাগ বাস্তবায়ন থাকে, src/release/ এ — রিলিজ বাস্তবায়ন। বিল্ডের সময়, Gradle উপযুক্ত sourceSet নির্বাচন করে এবং কেবল তার ফাইলগুলি কম্পাইল করে।
// 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) {
// রিলিজে No-op
}
}
KMP expect প্রক্রিয়া (সাধারণ কোডে ঘোষণা) এবং actual (নির্দিষ্ট প্ল্যাটফর্মের জন্য বাস্তবায়ন) প্রদান করে। এটি একটি কম্পাইল-টাইম প্রক্রিয়া: iOS-এর জন্য iOS sourceSet থেকে actual বাস্তবায়ন কম্পাইল হয়, Android-এর জন্য — Android sourceSet থেকে। অ-লক্ষ্য বাস্তবায়নগুলি কম্পাইল হয় না।
// commonMain — expect ঘোষণা
expect fun getPlatformName(): String
// androidMain — Android-এর জন্য actual
actual fun getPlatformName(): String =
"Android \${Build.VERSION.SDK_INT}"
// iosMain — iOS-এর জন্য actual
actual fun getPlatformName(): String =
UIDevice.current.systemName() + " " + UIDevice.current.systemVersion
Android NDK-এর মাধ্যমে নেটিভ লাইব্রেরি বিকাশ করার সময়, #ifdef, #ifndef, #define নির্দেশিকা সহ ক্লাসিক C/C++ প্রিপ্রসেসর ব্যবহার করা হয়। Swift-এর বিপরীতে, C প্রিপ্রসেসর টেক্সট স্তরে কাজ করে — নিষ্ক্রিয় শাখাগুলিতে কোড বাক্যগতভাবে ভুল হতে পারে।
NDK প্রতিটি প্ল্যাটফর্মের জন্য ম্যাক্রো সংজ্ঞায়িত করে: __ANDROID__ (Android), __APPLE__ (iOS/macOS), __linux__ (Linux)। আর্কিটেকচারের জন্য: __arm__, __aarch64__, __x86_64__। এই ম্যাক্রোগুলি কম্পাইলার দ্বারা লক্ষ্য প্ল্যাটফর্মের জন্য বিল্ড করার সময় স্বয়ংক্রিয়ভাবে সেট করা হয়।
// Android এবং iOS-এর জন্য নেটিভ কোড
#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-এর সাথে কাজ করার সময়, মনে রাখা গুরুত্বপূর্ণ যে C/C++ প্রিপ্রসেসর একটি টেক্সট প্রতিস্থাপন। যদি নিষ্ক্রিয় শাখায় বাক্যগত ত্রুটি থাকে, কম্পাইলার এটি দেখতে পাবে না, কিন্তু যদি ভুল #define একটি সক্রিয় শাখা ভেঙে দেয় — ত্রুটিটি প্রকাশ পাবে। #define চেইন কমানো এবং constexpr ধ্রুবক ব্যবহার করার পরামর্শ দেওয়া হয়।
Rust-এর জন্য, যা UniFFI এবং Mozilla Application Services-এর মাধ্যমে মোবাইল বিকাশেও ব্যবহৃত হয়, এর নিজস্ব প্রক্রিয়া রয়েছে — Cargo.toml-এ ফিচার ফ্ল্যাগ। Rust-এ #[cfg(target_os = “android”)]-এর মতো ফ্ল্যাগগুলি Swift নির্দেশিকার মতো কাজ করে: চেক কম্পাইলার স্তরে করা হয়, প্রিপ্রসেসর স্তরে নয়। এটি Rust-কে নেটিভ লাইব্রেরির জন্য একটি আকর্ষণীয় পছন্দ করে তোলে যা একটি কোডবেস থেকে Android এবং iOS-এর জন্য কম্পাইল করতে হবে।
Conditional Compilation কঠোরভাবে সংজ্ঞায়িত দৃশ্যকল্পে কার্যকর। ভুলভাবে ব্যবহার করলে, এটি কোড স্মেল তৈরি করে যা পরীক্ষা এবং রক্ষণাবেক্ষণ করা কঠিন। আসুন সঠিক দৃশ্যকল্প এবং সাধারণ ভুলগুলি বিবেচনা করি।
প্রথম দৃশ্যকল্প — প্ল্যাটফর্ম অ্যাবস্ট্রাকশন: একটি একক ফ্যাসাড যার ভিতরে Conditional Compilation প্ল্যাটফর্ম বাস্তবায়ন নির্বাচন করে। দ্বিতীয় — ডিবাগিং এবং প্রোফাইলিং: ডেভেলপার সরঞ্জাম যা রিলিজে যাওয়া উচিত নয়। তৃতীয় — পশ্চাদগামী সামঞ্জস্যতা: পুরানো OS সংস্করণগুলির জন্য সমর্থন যতক্ষণ না ন্যূনতম সংস্করণ আপডেট হয়।
| দৃশ্যকল্প | ভাষা | শর্ত |
|---|---|---|
| প্ল্যাটফর্ম অ্যাবস্ট্রাকশন | Swift | #if os(iOS) |
| ডিবাগিং | Swift/ObjC | #if DEBUG |
| পশ্চাদগামী সামঞ্জস্যতা | Swift | #if swift(>=5.7) |
| নেটিভ লাইব্রেরি | C/C++ | #ifdef __ANDROID__ |
| A/B পরীক্ষণ | Java/Kotlin | BuildConfig.FLAVOR |
সবচেয়ে বিপজ্জনক অ্যান্টিপ্যাটার্ন — সমগ্র কোড জুড়ে নির্দেশিকার বিস্তার। যদি প্রতি দ্বিতীয় ফাইলে #if থাকে, এটি ইঙ্গিত দেয় যে আর্কিটেকচারের রিফ্যাক্টরিং প্রয়োজন। সঠিক সমাধান — প্রোটোকল/ইন্টারফেসের পিছনে প্ল্যাটফর্ম কোড বের করা এবং ডিপেন্ডেন্সি ইঞ্জেকশন ব্যবহার করা।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
Conditional Compilation কম্পাইল সময়ে কাজ করে: নিষ্ক্রিয় কোড বাইনারিতে যায় না। রানটাইম চেক (if / switch) সর্বদা কম্পাইল হয়, শর্ত নির্বাহের সময় পরীক্ষা করা হয়। প্রথমটি বেশি নিরাপদ এবং কার্যকর, দ্বিতীয়টি বেশি নমনীয় (পুনর্নির্মাণ ছাড়াই পরিবর্তন করা যেতে পারে)।
হ্যাঁ, Swift ফাংশনের ভিতরে #if, লুপ এবং এমনকি এক্সপ্রেশনের ভিতরেও নির্দেশিকা অনুমতি দেয়। এটি এমন একটি বৈশিষ্ট্য যা Swift-এর প্রাথমিক সংস্করণে অনুপস্থিত ছিল। উদাহরণস্বরূপ: let x = #if DEBUG 1 #else 0 #endif — বৈধ কোড।
Kotlin ডেভেলপাররা ইচ্ছাকৃতভাবে প্রিপ্রসেসর প্রত্যাখ্যান করেছে, এটিকে ভঙ্গুর কোডের উৎস হিসেবে বিবেচনা করে। পরিবর্তে, তারা expect/actual (কম্পাইল-টাইম নিরাপত্তা) এবং Gradle sourceSets (ফাইল স্তরে বিচ্ছিন্নতা) অফার করে। উভয় পদ্ধতিই টেক্সট প্রতিস্থাপনের চেয়ে বেশি নির্ভরযোগ্য।
CI-তে বিভিন্ন ফ্ল্যাগ সংমিশ্রণ সহ অ্যাপ্লিকেশন বিল্ড করুন। Swift-এর জন্য: বিভিন্ন Active Compilation Conditions সহ আলাদা Xcode স্কিম কনফিগার করুন। Android-এর জন্য: আলাদা Build Variants কনফিগার করুন এবং প্রতিটির জন্য পরীক্ষা চালান। অটোমেশন বাধ্যতামূলক।
Swift-এ, #if শর্ত একটি কম্পাইলার নির্দেশিকা। যদি শর্তটি নিজেই বাক্যগতভাবে ভুল হয় (যেমন, os() নামে টাইপো), কম্পাইলার একটি কম্পাইলেশন ত্রুটি দেবে। C/C++-এ, প্রিপ্রসেসর কেবল ম্যাক্রো খুঁজে পাবে না এবং শর্তটি মিথ্যা হয়ে যাবে।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন