اختاپوس خسته

یادداشت‌هایی پیرامون کد، زندگی و دوستان

توسعهٔ چندسکویی

دوست دارم برنامه‌ها و کتابخونه‌هام روی پلتفرم‌های مختلف اجرا بشن. هرچه بیشتر بهتر! البته همیشه هدف اصلی همیشه لینوکس و سیستم‌های شبه‌یونیکس هستند. با این حال بدم نمیاد که عملکرد مشابهی رو برای ویندوز و اندرویید، شاید هم مک‌اواس فراهم کنم. در واقع پلتفرم نباید یک محدودیت برای استفاده از نرم‌افزار باشه. مجموع این‌ها ما رو به ایدهٔ توسعهٔ چندسکویی می‌رسونه. متأسفانه این کار چندان ساده هم نیست. استاندارد پذیرفته‌شده‌ای برای APIهای سیستم‌عامل‌ها وجود نداره. همچنین هیچ الگوی کلی‌ای برای عملیات سیستم‌عامل موجود نیست. توسعه‌دهنده‌ها باید با درنظر داشتن تمام نیازمندی‌های چندسکویی کد بنویسند.

توی این پست، تجربهٔ شخصی خودم رو در مورد توسعهٔ چندسکویی پروژهٔ AIT می‌نویسم. توی اون پروژه به مشکلات زیادی برخوردم و تعدادی‌شون رو حل کردم. این نوشته یک چک‌لیست ساده برای کسایی که می‌خوان توسعهٔ چندسکویی انجام بدن فراهم می‌کنه که بتونن از مشکلات توسعهٔ چندسکویی با زبان‌های ‏‪C/C++‬ پیشگیری کنن. رفتیم که بریم :)

زبان

Ⅰ. با یک زبان ویژهٔ پلتفرم کد ننویسید.

این کار رو نکنید. با C#، C++ CLI یا ابزارهای دیگهٔ مایکروسافت کد ننویسید.

کد

Ⅱ. کد وابسته به یک پلتفرم خاص ننویسید. حتا اگر شده به قیمت اضافه کردن وابستگی‌های بیشتر.

قانون شمارهٔ دو میگه که نرم‌افزار شما نباید وابسته به ابزارهای ویژهٔ پلتفرم خاصی باشه. این به معنی هست که مثلاً از Berkeley socket API توی سیستم‌های یونیکس استفاده نکنید. همچنین از Winsock روی ویندوز. به‌جای استفاده از این APIها یک پیش‌نیاز جدید اضافه کنید که کاربرد موردنظر رو به شکل چندسکویی پیاده‌سازی کرده باشه. مثلاً Boost ASIO برای کارهای شبکه می‌تونه یه راهکار چندسکویی باشه. ASIO خودش چندسکویی‌یه بنابراین کدی که ازش استفاده می‌کنه نیازی به تغییر روی سکوها نداره.

درصورتی که بخواید یک API سطح سیستم‌عامل بنویسید، باید پیاده‌سازی مربوط به هر پلتفرم رو بنویسید و بعد با استفاده از تعریف‌های شرطی زمان کامپایل زمان کامپایل مشخص کنید که کدوم کامپایل بشه. مثل این:

1
2
3
4
5
6
7
8
void delay(int ms)
{
#ifdefined(OS_WIN32)
              Sleep(ms);
#elifdefined(OS_LINUX)
             usleep(ms*1000);
#endif
}

در صورتی که روش استاندارد مشترکی برای انجام کاری روی پلتفرمی وجود داشته باشه، توسعه‌دهنده باید به‌جای انجام فراخوانی سیستمی از اون روش استفاده کنه. کد بالا می‌تونه با این کد جایگزین بشه:

1
2
3
4
void delay(int ms) {
    // تضمین میشه که به‌خوبی روی هر سکویی که کامپایل میشه کار کنه!
    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}

البته تأخیر دومی نیازمند C++11 هست. شاید بعد از سال ۲۰۱۵ توسعه‌دهنده‌های مایکروسافت تصمیم بگیرن که سویت کامپایلرشون یه سویت به‌دردنخورِ مزخرفِ ازرده‌خارج نباشه و شاید موفق بشن استاندارد ۲۰۱۱ رو به‌طور کامل پیاده‌سازی کنن.

سیستم ساخت (Build System)

Ⅲ. نباید از یک بیلدسیستم مختص پلتفرمی خاص استفاده کنید. در صورت عدم وجود سیستم ساخت مستقل از پلتفرم، از چند سیستم ساخت استفاده کنید.

پلتفرم‌های مختلف از سیستم‌های ساخت متفاوت استفاده می‌کنند. سیستم‌های ساخت متداول عبارتند از GNU Make و Microsoft NMake. تعداد زیادی نرم‌افزار برای تولید سیستم‌ساخت وجود دارد از جمله GNU Autohell, CMake, QMake و Microsoft Visual Studio. ابزارهای گنو شاید روی ویندوز شهروند درجهٔ یک شمرده نشوند. برای همین ممکن است بخواهید از MSVC استفاده کنید. معمولاً سیستم‌های ساخت با همدیگر تداخل پیدا نمی‌کنند. شما می‌توانید فایل‌های Autohell را داخل دایرکتوری کد داشته باشید و در عین حال فایل‌های مربوط به Solution و QMake. با این همه بهتر است از یک سیستم چندسکویی مثل CMake استفاده کنید.

دیدگاه‌ها