مفهوم API رو می دونم ولی ABI چیه؟

همان طور که می دانید، به لحاظ تاریخی ابتدا زبان ماشین و اسمبلی بوجود آمد. برنامه نویسان از همان ابتدا متوجه این نکته شدند که functionalityهای مشخصی وجود دارند که کافی است یک بار طراحی و پیاده سازی شده و سپس به فراخور نیاز از آن ها استفاده شود. بنابراین مفهوم function یا routine از همان ابتدا بوجود آمد. لذا استفاده مجدد از کد بحثی بود که خیلی سریع وارد دنیای برنامه نویسی شد. اما زبان اسمبلی سخت بود. بنابراین تلاشی برای ایجاد زبان های سطح بالاتر (زبان هایی که به زبان انسان نزدیک باشند) آغاز شد و در نهایت به معرفی غولی مثل C انجامید. C این قابلیت را به شما می دهد که کتابخانه های مختلفی را بنویسید و از آنها یا کتابخانه های آماده ی دیگر استفاده کنید. شما همچنین این امکان را دارید که بدون داشتن اصل کد C کتابخانه و با در دست داشتن کد کامپایل شده ی آن، از توابع کتابخانه استفاده کنید! به عبارت دیگر کافی است فردی که کتابخانه را نوشته است، کد کامپایل شده ی کتابخانه اش را در قالب یک سری فایل اجرایی (مثل فایل های exe، lib و dll) به شما بدهد و شما از توابع آن سرویس بگیرید.

طبیعی است که هر کتابخانه ای ساختارهای داده ای و عملکردی خود را داشته باشد. اصطلاحا هر کتابخانه ای data interface و functionality interface خاص خود را دارد. به بیان مفاهیم C این مطلب به این معناست که هر کتابخانه ای struct ها و توابع خاص خود را دارد. از این رو استفاده کننده باید از این interface ها آگاهی داشته باشد. لذا مفهومی به اسم Application Programming Interface یا API بوجود آمد که در واقع چیزی جز همین واسط ها نیست که در قالب یک سری فایل .h به همراه با کدهای اجرایی کتابخانه منتشر می شود. پس برای استفاده از کتابخانه شما نیاز به یک سری فایل اجرایی که معمولا dll هستند و یک سری فایل .h که حاوی prototype توابع و نیز تعریف ساختارهای داده ای است دارید، و به سادگی با include کردن این فایل های .h در کد C برنامه تان می توانید از آن کتابخانه ها استفاده کنید. حال این کتابخانه جز کرنل ویندوز باشند (مثل کتابخانه های کار با مانیتور، فایل، چند نخی و ... که در باینری فایل هایی مثل kernel32.dll, user32.dll و ... پیاده سازی شده اند) و خواه یک کتابخانه ریاضی باشند، یا کتابخانه ای برای کار با پایگاه داده و ...

همه چیز در مورد C عالی بود به جز عدم پشتیبانی از شی گرایی. استراستروپ نگاه زیبایی به جهان کدها داشت و آن را هم ارز با دنیای واقعی می دید. اون هر برنامه را یک جهان مجازی حاوی اشیایی می دید که با هم در کنش و واکنش هست و این کنش و واکنش ها رفتار کلی جهان را شکل می داد. در واقع هر شی از این جهان دارای دو دسته مشخصه بود. هر شی یک سری ویژگی داشت و یک سری رفتار. وی ویژگی ها را با متغیرهای عضو کلاس مدل کرد و رفتارها را با توابع عضو کلاس. کلاس نیز در واقع نقشه ی تولید اشیا بود و صرفا یک چیز توصیفی بود که ماهیت اشیا را توصیف می کرد.

با ورود C++ استفاده ی مجدد از کد بسیار آسان و انسان فهم تر شد و کتابخانه های بسیاری نیز برای آن بوجود آمد. اما یک مشکل عمده هنوز وجود داشت. اگر شما کدی را به زبان دیگری نوشته بودید و می خواستید آن را در کد c++ تان استفاده کنید (و یا برعکس) امکان پذیر نبود. دلیل این امر هم ناسازگاری ABI های زبان ها یا Application Binary Interface ها بود.

مفهوم ABI چیزی شبیه به API است با این تفاوت که در لایه بسیار پایین تری و در نزدیکی بیشتری به سخت افزار حضور دارد، به طوری که می توان آن را ورژن کامپایل شده ی API دانست. در واقع ABI نحوه ی پاس دادن پارامترها بین فراخوانی توابع، محل ذخیره ی خروجی توابع در رجیسترهای سی پی یو، آرایش عناصر داخل struct ها و ... را در سطح زبان ماشین معین می کند. لذا کدی که با یک ABI مشخص کامپایل شده است، لزوما قابل استفاده در کدی که با ABI دیگری کامپایل خواهد شد نیست (مگر اینکه ABI ها سازگار باشند). تصورش را بکنید که شما کلی کد می نویسید و ویژوال استودیو یا سایر IDE ها آن را برایتان کامپایل می کنند و شما اصلا نگران هیچ کدام از این مفاهیم نیستید! (چقدر این لامصب ها هوشمندن) اصلا باید خدمتتان عرض کنم که برای کامپایل کردن یک hello world ساده مجموعه ای از نرم افزار ها دخیل هستند (مثل کامپایلر، لینکر، کتابخانه ها، دیباگرها و ...) که به مجموعه ی آن ها اصطلاحا یک tool chain گفته می شود. دقت کنید که زبان های مختلف، ABI های متفاوتی دارند و به علاوه برای یک زبان نیز می توان از ABI های مختلفی استفاده کرد.

از بحث اصلی دور شدیم! همان طور که قبلا گفتم وقتی کدهای مختلفی تحت ABI های مختلفی کامپایل می شوند، ناسازگار بوده و نمی توان یکی از آن ها را توسط دیگری اجرا کرد. اما به مرور این نیاز احساس شده بود که کدهایی که با زبان های مختلف نوشته شده اند، توسط کدهای دیگر قابل فراخوانی باشند. به عبارت دیگر یک مجموعه ی کد باینری که مجموعه ای از دستورات قابل فهم برای CPU است، حتما باید توسط یک مجموعه ی باینری دیگر که CPU آن ها را نیز می فهمد قابل ارجاع باشد. در واقع جهان وارد گذر از فاز استفاده ی مجدد کد به فاز استفاده مجدد باینری شده بود. اینجا جایی بود که شرکت های مختلف نرم افزاری مدل های مختلف و تکنیک های متفاوتی را ابداع کردند و ماکروسافت نیز Component Object Model یا COM را مطرح کرد.