• 0
مصطفى 36a2

تعرف على المكتبات الساكنة static library

سؤال

السلام عليكم ورحمة الله وبركاته

 

مدخل :

إذا بدأنا الحديث عن "إعادة استخدام الكود" فسنبدأ بذكر التوابع , فعندما تكتب جسم التابع ثم تستدعيه مرات ومرات داخل الكود , فأنت توفر إعادة كتابة هذا التابع في كل مرة استدعيته فيها ( باستثناء التوابع العودية التي تقوم بأكثر من ذلك)

ثم أخذت الأمور تكبر , وصار لدينا العديد من التوابع وصرنا نحتاج نسخ ولصق أجسام التوابع الخاصة بنا أينما ذهبنا .. لذلك قررنا وضع كل تلك التوابع في ملف واحد , وأسميناه header file وعوضاً عن نسخ محتوى الملف يدوياً

جاءت include# لتقوم بعملية النسخ واللصق فقط , ونحن نخبرها بموضع واسم الملف الذي نريد لصق محتواه .

ولكن ماذا عن أجسام التوابع ! آلاف التوابع وآلاف الأجسام , وكلها تحتاج للترجمة من قبل الـ compiler كل مرة !

عندها جاءت مكتبات الربط لحل المشكلة .. وأصبحنا ننسخ فقط الـ function prototype فقط ليعرف المترجم أن هناك تابعاً بهذا الاسم وهذه الوسطاء parameters وله القيمة المعادة من النوع الفلاني returned type .

ولكن أين أجسام التوابع ؟

كثيراً ما حاولنا رؤية محتوى أحد التوابع المثيرة للاهتمام , ماذا بداخل التابع sin وماذا بداخل التابع rand !

أحياناً يكون متاحاً لنا الوصول إلى أجسام التوابع , وأحياناً أخرى تكون الأجسام مخفية داخل المكتبات الساكنة التي سنتحدث عنها اليوم .

 

هذا المقال موجّه لمن تجاوز مرحلة انشاء التوابع ويرغب بالتعرف على كيفية حزم التوابع ضمن مكتبات مشابهة لمكتبات اللغة بحيث تظهر الـ prototypes فقط للتوابع ولا تظهر أجسامها.

 

الفهرس :

 

0- مقدمة

1- ما هي المكتبات الساكنة static library ؟

2- لماذا نحتاج إلى مكتبة ساكنة ؟

3- إنشاء مكتبة ربط ساكنة باستخدام بيئة code::blocks

  • ربط المكتبة مع مشروع بلغة C
  • ربط المكتبة مع مشروع بلغة ++C

 

0-المفدمة :

لدينا الكود البسيط التالي :

int Add(int i1, int i2){    return i1 + i2;}long long Mul(int i1, int i2){    return i1 * i2;}int Sub(int i1, int i2){    return i1 - i2;}int Div(int i1, int i2){    if(i2)        return i1 / i2;    return -1;}

أين ستضع الكود السابق في حال أردت استخدام التوابع السابقة بشكل متكرر ؟ قد تقوم بنسخها معك أينما ذهبت , وقد تقوم بوضعها في ملف header خاص بك وقوم بعمل include له , ولكن ماذا لو كان لديك المئات من التوابع , هل تدري أنك في كل مرة تقوم بعمل compile يتم إعادة ترجمة الكود كاملاً , وربط كل تلك التوابع مع استدعاءاتها في عمليات طويلة , يمكنك أن تتخيل ان عملية ترجمة ملفات بهذا الحجم ستسغرق الكثير من الوقت , فما بالك عندما تصل إلى آلاف التوابع , ستكون عملية الترجمة لكودك البسيط الذي لم يتجاوز الأسطر .. كابوساً من الانتظار .

 

1- ما هي المكتبات الساكنة static library ؟

هي ملفات تحوي أجسام توابع تمت ترجمتها مسبقاً ومتغيرات تم حجزها مسبقاً, يتم نسخ محتويات المكتبة إلى الملف التنفيذي مباشرة عند بناء مشروع مرتبط linked بها بعد عمل الـ linking اللازمة لربط استدعاءات التوابع بأجسامها كما يمكن أن تنسخ إلى مساحة ذاكرة ساكنة خاصة بها محددة في وقت الترجمة .

 

2- لماذا نحتاج إلى مكتبة ساكنة ؟

كما ذكرنا في المقدمة , فإن انشاء مكتبة ساكنة يخفف الحمل عن المترجم compiler في وقت الترجمة , فالمكتبة مترجمة مسبقاً وتنتظر الربط linking كما أنها تقيد في تجزئة ملفات الكود وتنظيم بنية المشروع , ويمكننا أن نضيف إلى فوائدها : إغلاق مصدر البرنامج , أي جعله closed source وذلك لأن عدم وجود أجسام للتوابع ضمن ملفات المشروع يجعل هذا الجزء مغلق المصدر , مما يتيح بعض الخصوصية وحقوق النشر للمبرمج والشركة.

 

3- إنشاء مكتبة ربط ساكنة باستخدام بيئة code::blocks

يمكن إنشاء مكتبات الربط بأي مترجم , وتتيح أي بيئة القيام بذلك بسهولة , باستخدام code::blocks سنقوم بإنشاء مكتبة ربط ساكنة ثم نربطها بمشروع يستخدمها ,

من القائمة file اختر new ثم project واختر نوع المشروع Static Library

لدينا أجسام التوابع التالية :

int Add(int i1, int i2){    return i1 + i2;}long long Mul(int i1, int i2){    return (long long)i1 * i2;}int Sub(int i1, int i2){    return i1 - i2;}int Div(int i1, int i2){    if(i2)        return i1 / i2;    return -1;} 

انسخ الكود السابق واستبدل المحتوى السابق للمشروع (الذي تنشئه البيئة افتراضياً) به .

والآن قم بعمل Build ويفترض أن الكود خالٍ من الأخطاء ( لا تقم بعمل run لأن هذا ليس مشروعاً كاملاً ولا يحوي main )

  • ربط المكتبة مع مشروع بلغة C

والآن لنقم بإنشاء مشروع جديد عادي من نوع console project واختر لغة C لكتابة المشروع

للتبسيط , سنقوم بلصق تصاريخ التوابع قبل الـmain مباشرة :

سيكون لدينا الكود التالي في المشروع :

#include <stdio.h>#include <stdlib.h>int Add(int,int);long long Mul(int, int);int Sub(int, int);int Div(int, int);int main(){    printf("4 + 2 = %d\n",Add(4,2));    printf("5 - 4 = %d\n",Sub(5,4));    printf("5 * 5 = %d\n",Mul(5,5));    printf("5 / 5 = %d\n",Div(5,5));    return 0;}

والآن إلى عملية الـ linking , من Settings>> Compiler اختر Linker settings ثم قم بالضغط على Add واختر مسار المكتبة الذي أنشأناها قبل قليل ثم O.K -- O.K

والآن يمكنك عمل Build ثم run للمشروع وتكون قد أنشأت أول مكتبة ربط ساكنة لك

 

  • ربط المكتبة مع مشروع بلغة ++C

تختلف توابع الـ C عن توابع ++C بمسألة تسمى name mangling وهي عملية يقوم بها المترجم فيغيّر أسماء التوابع قبل مرحلة الـ linking ليتمكن من عمل  overloading للتوابع أو إذا كانت بداخل classes , المهمّ أن توابع ++C لا تبقى بنفس الاسم الذي نكتبه عند التعريف , وكل مترجم له mangling خاص به , ولكن في C لا يوجد overloading ولا تغليف للتوابع , فالتابع يبقى بنفس اسمه بالنسبة للمترجم أثناء الربط , لذلك عندما نقوم بعمل مكبتة ربط ساكنة ونريد ربطها مع كود بلغة ++C فعلينا اخبار المترجم أن هذه التوابع مكتوبة ومترجمة بلغة C وذلك عن طريق الكلمة المجوزة التي لا نستخدمها كل يوم , extern

ويصبح كود الـ ++C كما يلي :

#include <cstdio>#include <cstdlib>extern "C"{    int Add(int,int);    long long Mul(int, int);    int Sub(int, int);    int Div(int, int);}int main(){    printf("4 + 2 = %d\n",Add(4,2));    printf("5 - 4 = %d\n",Sub(5,4));    printf("5 * 5 = %d\n",Mul(5,5));    printf("5 / 5 = %d\n",Div(5,5));    return 0;} 

والآن يمكنك الانطلاق لعمل مكاتبك الساكنة الخاصة بك , وتنظيم مشاريعك بطريقة أكثر تقدماً .

 

والله ولي التوفيق

4

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

3 إجابة على هذا السؤال .

  • 0

فعلا دائما أرى prototypes فقط . أحسنت أخي ووفقت في الشرح

ولكن هل من طريقة للوصول إلى المكتبات الساكنة للغة ؟ فأحيانا الفضول يحتم عليك أن تعرف كيف تعمل دالة ما

أكرر أنك أحسنت أخي مصطفى ، دائما مبدع ما شاء الله

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

موضوع مفيد

من بين فوائد الربط الستاتيكي  في لينيكس . كلما كان التطبيق اقل اعتمادا على المكتبات الخارجية كلما كان اسهل في تشغيله من طرف المستخدم العادي

لانه لن تجبر كل مرة على تصدير (export) المسار الذي يحتوي على shared library

 

شكرا على الموضوع

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

شكراً لكما .. بصراحة عدت إلى عدة مواضيع لأستاذي Snacker لأنقل منه طريقة التنسيق في الموضوع .

بالنسبة لتعليق الأخ codz فهناك موضوع يجب أن يلحق بهذا المقال وهو أهمية المكتبات الساكنة ومقارنتها بالمكتبات الديناميكية , ما رأيك لو تكتب مقالاً عن الموضوع , فنحن في المنتدى بصدد الدعوة إلى الويكي منتدى , وستكون هذه بادرة جيدة إن شاء الله .

بالنسبة لسؤالك أخي++Hisawa فالمكتبات الساكنة محتواها هو مثل محتوى ملفات الـ .o أو الـ object file الذي يتحول إلى exe لاحقاً , وهي مكتوبة بلغة الآلة , الطريقة الوحيدة التي أعرفها لتتبع محتواها هو عن طريق الهندسة العكسية , أثناء تشغيل البرنامج , ولكن ستكون عندها بالأسمبلي وليست بالسي ..

 

من الأمور التي لم تذكر في المقالة , هي كيف نصنع مكتبة ++C حقيقية تحوي namespaces وما إلى ذلك , فالمذكور في المقالة هو مكتبة C تم ربطها ببرنامج ++C وهذا نقص أرجو منكم إتمامه , فلو كان لدى أحد فراغ وقت فحبذا لو يتابع الموضوع

والله ولي التوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .