قائمة طعام
مجاني
التسجيل
الصفحة الرئيسية  /  إنترنت/ برنامج تعليمي مصور على Macromedia Flash MX. مكتبة فلاش سونام المشتركة

برنامج تعليمي مصور على Macromedia Flash MX. مكتبة فلاش سونام المشتركة

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

يفترض استخدام المكتبات المشتركة و / أو مكتبات الارتباط الديناميكي (DLL) (في هذه الحالة ، الاختلاف بينهما ليس أساسيًا) شكلاً من أشكال التجميع في وقت التحميل: تحتوي الوحدة القابلة للتنفيذ على مراجع عناوين لم يتم حلها وأسماء المكتبات التي تحتاجها. عند التحميل ، يتم تحميل هذه المكتبات وحل الروابط. تكمن المشكلة هنا في أنه عند تحميل مكتبة ، يجب نقلها عن طريق إعادة تكوين مراجع العنوان المطلقة في كودها وبياناتها (انظر الفصل 3). إذا تم تكوين المكتبة في عمليات مختلفة لعناوين مختلفة ، فلن يتم مشاركتها (الشكل 5.14)! إذا كان من الممكن أن تحتوي المكتبات المشتركة على ارتباطات لم يتم حلها إلى مكتبات أخرى ، فإن المشكلة تتفاقم فقط عن طريق إضافة روابط خارجية إلى الارتباطات القابلة للنقل.

أرز. 5.14... عناوين تعيين DLL المتعارضة

على أنظمة Unix الأقدم التي تستخدم وحدات قابلة للتحميل المطلقة من التنسيق أ. خارجتم أيضًا شحن المكتبات المشتركة في تنسيق وحدة مطلق ، مضبوطة على عناوين ثابتة. تم تعيين كل مكتبة على عنوان ITS. كان على مورد المكتبات الجديدة الاتفاق على هذا العنوان مع مطوري النظام. كان هذا غير عملي للغاية ، لذلك كان هناك عدد قليل جدًا من المكتبات المشتركة (خاصةً باستثناء تلك التي تأتي مع نظام التشغيل).

يتم تطبيق حل أكثر قبولًا لهذه المشكلة في OS / 2 2.x و Win32 (كل من هاتين البنيتين هما تطوير أنظمة بمساحة عنوان واحدة). تكمن الفكرة في تخصيص منطقة عنوان لتحميل مكتبات DLL وتعيين هذه المنطقة إلى مساحات العنوان لجميع العمليات. وبالتالي ، فإن جميع مكتبات DLL التي تم تحميلها على النظام تكون مرئية للجميع (الشكل 5.15).

غالبًا ما تتطلب البرامج الكبيرة مكتبات جاهزة. المكتبة هي مجموعة من الوظائف المترجمة بالفعل (على سبيل المثال ، مكتبة الرياضيات). المكتبة مطلوبة عند الارتباط عند إنشاء exe-shnik. يتم ذلك باستخدام الخيار -l: cc -o badmath badmath.o -lm إذا كنت بحاجة إلى تحديد المسار إلى مكتبة غير قياسية: cc -o badmath badmath.o -lm -L / usr / junk / lib -lcrudإذا انتهى اسم المكتبة بـ .a ، فهي مكتبة ثابتة. عندما يتم ربط مكتبة ثابتة ، يقوم الرابط ببساطة بنسخ أجزاء كاملة منها إلى ملف exe الذي تم إنشاؤه ، والذي ، نتيجة لذلك ، يمكن أن يعمل بشكل مستقل بدونها. إذا كان exe-shnik يستخدم مكتبة مشتركة ، فسيتم تحميل الكود فقط حسب الحاجة. توجد المكتبات عادةً في الدلائل / lib و / usr / lib. يجب ألا يكون هناك مكتبات ثابتة في الدليل / lib. يتضمن اسم المكتبة المشتركة البادئة .so. لتحديد المكتبات التي يستخدمها البرنامج ، تحتاج إلى تشغيل الأمر: ldd prog يقوم مُحمل ld.so بتحميل المكتبات المشتركة. يمكن أن يقع المسار إلى المكتبة داخل exe-shnik. إذا لم يكن موجودًا ، فسيقوم المُحمل بالبحث في الملف /etc/ld.so.cache ، الذي يسرد الدلائل. يوجد أيضًا ملف /etc/ld.so.conf. إذا أضفت المسار يدويًا إلى ملف /etc/ld.so.cache ، فأنت بحاجة إلى تشغيل الأمر: ldconfig -v يوجد أيضًا LD_LIBRARY_PATH متغير النظام. لا تعد إضافة مسارات إلى ملف /etc/ld.so.conf فكرة جيدة ، حيث تدخل المكتبات الكبيرة في ذاكرة التخزين المؤقت للنظام وقد تتورط في مشكلة. أفضل طريقة هي خياطة المسار إلى المكتبة في exe-shnik: cc -o myprog myprog.o -Wl، -rpath = / opt / obscure / lib -L / opt / obscure / lib -lweirdمع نمو المكتبات المشتركة ، من الممكن حدوث مشاكل معها بسبب التداخل ، وما إلى ذلك. يعد استخدام LD_LIBRARY_PATH مشكلة أيضًا. يمكن استخدام نص برمجي بدلاً من ذلك: LD_LIBRARY_PATH = / opt / crummy / lib export LD_LIBRARY_PATH exec / opt / crummy / bin / my_prog [بريد إلكتروني محمي] أداة الترجمة الرئيسية في يونكس هي make. ويرد الوصف الأكثر تفصيلا في بيئة برمجة UNIXأو في إدارة المشاريع مع الصنع... اجعل دائمًا هدفًا - هدفًا - يمكن أن يكون إما ملفًا أو تسمية. يمكن أن يكون الهدف أساسيًا وثانويًا. لبناء هدف ، ابحث عن القواعد. على سبيل المثال: OBJS = aux.o main.o # ملفات الكائن جميعها: myprog myprog: $ (OBJS) $ (CC) -o myprog $ (OBJS)الهدف الأول - الكل - هو الهدف الرئيسي بشكل افتراضي. القاعدة الخاصة به هي myprog ، والتي يمكن أن تكون قاعدة أخرى أو هدفًا آخر أو ملفًا. OBJS هو ماكرو لبناء هدف. سينتج ملف makefile هذا الإخراج التالي: cc -o aux.o aux.c cc -c -o main.o main.c cc -o myprog aux.o main.oيمكن تشغيل make بالاقتران مع خيارات الأوامر ، على سبيل المثال: make aux.o Make options: -n -f وحدات الماكرو المستخدمة بشكل متكرر: CFLAGS - خيارات المترجم LDFLAGS - تشتمل خيارات الرابط على عدة أهداف قياسية: اختبار تثبيت نظيف نظيف يعتمد على Makefile عادةً ما يبدأ مع أي منهما وتتضمن ، على سبيل المثال: X_INCLUDES = -I / usr / X11R6 / include X_LIB = -L / usr / X11R6 / lib -lX11 -Xt NG_INCLUDES = -I / usr / local / include PNG_LIB = -L / usr / local / lib -lpngفيما يلي خيارات المترجم والرابط CFLAGS = $ (CFLAGS) $ (X_INCLUDES) $ (PNG_INCLUDES) LDFLAGS = $ (LDFLAGS) $ (X_LIB) $ (PNG_LIB)ثم يمكن إدراج رمز المصدر: UTIL_OBJS = util.o BORING_OBJS = $ (UTIL_OBJS) boring.o TRITE_OBJS = $ (UTIL_OBJS) trite.o PROGS = مبتذلة مملةوالآن فقط توجد أهداف وقواعد: الكل: $ (PROGS) مملة: $ (BORING_OBJS) $ (CC) -o [بريد إلكتروني محمي]$ (BORING_OBJS) $ (LDFLAGS) مبتذلة: $ (TRITE_OBJS) $ (CC) -o [بريد إلكتروني محمي]$ (TRITE_OBJS) دولار (LDFLAGS)المكتبات المشتركة هي عنصر أساسي في نظام Unix. مكتبة C القياسية على سبيل المثال في Suse 9.1 حجمها 1.3 ميجابايت. ستتطلب نسخة من هذه المكتبة لجميع البرامج التي تستخدمها في / usr / bin أكثر من غيغابايت واحد. لا تتطلب هذه المكتبات مساحة على القرص فحسب ، بل تتطلب أيضًا ذاكرة. تم تصميم النواة للاحتفاظ بنسخة واحدة من المكتبة المشتركة في الذاكرة. يجب أن نتذكر أنه عند الربط الثابت ، تتم إضافة رمز المكتبة بشكل ثابت إلى كود الملف القابل للتنفيذ ، وعند تشغيله ، لا نحتاج إلى المكتبة - رمزها مرتبط بالفعل أثناء التجميع بجسم الملف القابل للتنفيذ. باستخدام الارتباط الديناميكي ، يتم ربط المكتبة المشتركة في وقت التشغيل.
الارتباط الديناميكي هو النوع السائد من مكتبات الارتباط. تتكون المكتبة القياسية وحدها من أكثر من ألف مكالمة نظام. بالنسبة لبرامج العمل حقًا ، فإن ما يسمى ب. جدول ربط الإجراءات (PLT) هو جدول يتكون من نداءات للوظائف التي يتم استدعاؤها من المكتبات المشتركة. المشكلة الأولى التي يمكن أن تنشأ مع هذا هي مشكلة التوافق. مع التجميع الثابت ، يتم حل هذه المشكلة في وقت الترجمة. مع الارتباط الديناميكي ، لا يوجد مثل هذا الضمان ، لأنه يمكننا تحديث المكتبة المشتركة بعد التجميع. في هذه الحالة ، يكون الشيك هو رقم الإصدار - عندما يحاول الرابط الديناميكي ربط المكتبة ، فإنه يتحقق من رقم الإصدار ، وإذا كان الرقم غير متطابق ، فإنه غير مرتبط. يتكون رقم الإصدار من جزأين - الرقم الرئيسي (الرئيسي) والثانوي (الثانوي). إذا كان الرقم الرئيسي هو نفسه ، إذن ، كقاعدة عامة ، يجب ألا تكون هناك مشاكل عند تحميل المكتبة. إذا كان لدينا مكتبة libexample.so ، فسيكون لها رابط للإصدار libexample.so.N حيث N هو رقم الإصدار الرئيسي ، والذي ، بدوره ، سيكون هناك رابط إلى libexample.so.NM حيث M هو رقم الإصدار الثانوي الرئيسي. في هذه الحالة ، سيبحث البرنامج عن الإصدار N الذي يحتاجه بالضبط.
في المكتبات الثابتة ، يكون الرمز موجودًا في الملفات ذات الامتداد .a. بالنسبة للمكتبات الديناميكية ، يكون للملفات الامتداد .so. يتم إنشاء تنسيق المكتبة الثابت باستخدام الأداة المساعدة ar ، والتنسيق مشابه لما تنشئه الأداة المساعدة tar. بالنسبة للمكتبات الديناميكية على أحدث إصدارات Linux ، يكون هذا التنسيق عادةً ثنائي ELF. يتكون من رأس وأجزاء مقسمة إلى أقسام. عند الربط ، تتم إضافة التعليمات البرمجية من المكتبات الثابتة مباشرة إلى الملف التنفيذي للبرنامج ، ويتم أخذ الروابط من المكتبات الديناميكية وإضافتها إلى PLT. عند التحميل ، يقوم البرنامج بتحميل رابط ديناميكي يقوم بتحميل المكتبات المطلوبة. عند ربط برنامج ديناميكيًا ، يمكنك إضافة مسارات للبحث عن مكتبات في وقت الترجمة. بالنسبة إلى دول مجلس التعاون الخليجي ، يبدو بناء الجملة هذا مثل -Wl، -R / path إذا كان البرنامج مرتبطًا بالفعل ، فيمكنك استخدام متغير LD_LIBRARY_PATH. يمكنك أيضًا تشغيل نص برمجي خاص قبل بدء البرنامج الذي يقوم بتكوين أدلة المكتبة على وجه التحديد ، كما هو الحال ، على سبيل المثال ، عند بدء تشغيل Mozilla. يصل الرابط الديناميكي إلى /etc/ld.so.conf config ، والذي يتضمن قائمة دليل. لكن أولاً ، يصل الرابط إلى LD_LIBRARY_PATH. ldd (سرد التبعيات الديناميكية)- فائدة لتصحيح المكتبات المشتركة. يسرد المكتبات المشتركة لوحدة نمطية معينة ، على سبيل المثال: ldd / bin / sh linux-gate.so.1 => (0xffffe000) libreadline.so.4 => /lib/libreadline.so.4 (0x40036000) libhistory.so.4 => /lib/libhistory.so.4 (0x40062000) libncurses.so.5 => /lib/libncurses.so.5 (0x40069000) libdl.so.2 => /lib/libdl.so.2 (0x400af000) libc.so.6 => / lib / tls /libc.so.6 (0x400b2000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
  • بالنسبة إلى Newbies: مقال في مجلة Linux "Linkers and Loaders" بقلم Sandeep Grover
  • مخطوطة كتاب "الروابط واللوادر" على الإنترنت.
  • أوصى أيضا عام 2002 من قبل Ulrich Drepper بعنوان "كيفية كتابة المكتبات المشتركة" (pdf). شرائح (pdf) ، ونص مذكور في الشرائح

بناء مكتبة مشتركة

دعنا نكتب مكتبة صغيرة لا تفعل شيئًا ، تقريبًا لا شيء ، إلى جانب "أهلًا بالعالم". الكائن الأول:

/ * print1.c * / #include باطل print1 (باطل) (printf ("1 \ n") ؛)

وبالمثل ، فإن الكائن الثاني:

/ * print2.c * / #include باطل print2 (باطل) (printf ("2 \ n") ؛)

لنجمع:

gcc -Wall -g -c -fpic print1.c gcc -Wall -g -c -fpic print2.c

إنشاء مكتبة مشتركة:

gcc -shared -Wlsoname = libprint.so.1 -g \ -o libprint.so.1.0.1 print1.o print2.o

نقوم بعمل رابط للمكتبة:

ln -sf libprint.so 1.0.1 libprint.so

لكي يتمكن الآخرون من استخدام هذه المكتبة ، عليك كتابة رأس الصفحة:

/ * print.h * / #ifndef PRINT_H #define PRINT_H void print1 (void) ؛ print2 باطلة (باطلة) ؛ #إنهاء إذا

لنكتب برنامج اختبار:

/ * print.c * / #include "print.h" int main () (print1 ()؛ print2 ()؛ return 0؛)

دعونا نجمعها:

دول مجلس التعاون الخليجي -Wall -g -L. -طباعة -o print.c

لتشغيل البرنامج ، يحتاج الرابط إلى معرفة مكان المكتبة:

وظائف التحميل الزائد

قبل تحميل مكتبة ، يمكننا دائمًا إخبار المحمل بمكان بدء البحث وتحميله.

دعنا نضيف وظيفة جديدة إلى المكتبة التي كتبناها للتو. هذه الوظيفة تسمى fopen.

/ * fopen.c * / #include FILE * fopen (const char * fn، const char * mode) (printf ("fopen called \ n")؛ return NULL؛)

دعونا نجمع هذه الوظيفة ونضعها في المكتبة:

gcc -Wall -g -c -fpic fopen.c gcc -shared -Wlsoname = libprint.so.1 -g \ -o libprint.so.1.0.2 print1.o print2.o fopen.o ln -sf libprint.so .1.0.2 libprint.so

لنكتب برنامجًا للاختبار:

/ * print-2.c * / #include int main () (FILE * f؛ f = fopen ("abc"، "r")؛ if (f == NULL) (printf ("1")؛) else (printf ("2") ؛ fclose (f) ؛) إرجاع 0 ؛)

لنجمع هذا البرنامج:

دول مجلس التعاون الخليجي - جدار - ز - طباعة طباعة

يجب أن نطلقه بالبادئة التالية:

LD_PRELOAD =. / Libprint.so ./print

إذا حدث خطأ ما ، فسيتم عرض الخط: يسمى fopen

عملية إنشاء البرنامج.

الترجمة إلى الروسية: فلاديمير بوبوف

اليوم ، في بيئة دائمة التطور ، تعد عملية تطوير البرامج نتاجًا لتطور المهارات والخبرات التي طورها المبرمجون والمطورون.

تتكون هذه العملية من الخطوات التالية:

    إنشاء شفرة مصدر لغة عالية المستوى في محرر نصي. إذا حاولنا تضمين برنامج كبير جدًا في ملف واحد ، يصبح من الصعب إدارته. لهذا السبب ، يتم تقسيم التعليمات البرمجية المصدر إلى وحدات وظيفية يتم إنشاؤها من ملف أو أكثر من ملفات التعليمات البرمجية المصدر. قد لا تتم كتابة التعليمات البرمجية المصدر في هذه الوحدات بالضرورة بنفس اللغة ، حيث أن بعض اللغات أكثر ملاءمة لحل مشكلة معينة من غيرها.

    بعد إنشاء الملفات ذات الكود المصدري للبرنامج ، يجب ترجمتها إلى كتل من التعليمات البرمجية التي يمكن للجهاز تنفيذها. يشار إلى هذا الرمز عادةً باسم رمز التعليمة... يقوم هذا الرمز بتنفيذ نفس الإجراءات مثل الكود الأصلي ، باستثناء أنه مكتوب بلغة خاصة يمكن للجهاز تنفيذها مباشرة. تُعرف عملية ترجمة التعليمات البرمجية المصدر إلى التعليمات البرمجية الهدف باسم التحويل البرمجي... يتم التجميع في أجزاء ويجمع (اعتمادًا على المترجم) جزء من البرنامج وعادة ما يكون ملفًا واحدًا أو أكثر دفعة واحدة. يحتوي رمز الكائن المترجم على برنامج ، وروتين فرعي ، ومتغيرات ، وما إلى ذلك. - أجزاء البرامج التي تمت ترجمتها وجاهزة للخطوة التالية.

    بعد إنشاء جميع ملفات البرنامج التي تحتوي على رمز الجهاز ، يجب توصيلها أو ربطها باستخدام عملية يتم تنفيذها بواسطة أداة مساعدة خاصة تسمى رابط... في هذه المرحلة ، يتم "حل" جميع المراجع التي يقوم بها رمز الوحدة النمطية للتعليمات البرمجية التي تنتمي إلى وحدة نمطية أخرى (مثل استدعاء إجراء فرعي أو مراجع للمتغيرات المملوكة أو المحددة في وحدة نمطية أخرى). المنتج الناتج هو برنامج يمكن تحميله وتنفيذه مباشرة.

    يتم تنفيذ البرنامج بواسطة نوع خاص من البرامج ، والذي يعد جزءًا أساسيًا من نظام التشغيل ، وفي حالة Linux ، يتم استدعاء نظام exec (). تقوم هذه الوظيفة بالعثور على الملف ، وتخصيص الذاكرة للعملية ، وتحميل أجزاء معينة من محتوى الملف (تحتوي على رمز وقيم متغيرة أولية) ، وتنقل التحكم إلى المعالج عند نقطة "النص" في البرنامج ، والتي تشير عادةً إلى الملف القابل للتنفيذ بحد ذاتها.

2.- تاريخ موجز لعملية إنشاء البرنامج.

تتطور عملية إنشاء البرنامج باستمرار ، فمن الضروري تحقيق التنفيذ الأكثر كفاءة للبرامج أو الاستخدام الأفضل لموارد النظام.

في البداية ، تمت كتابة البرامج مباشرة في كود الآلة. أصبح من الواضح لاحقًا أنه من الممكن كتابة البرامج بلغة عالية المستوى ، حيث يمكن أتمتة الترجمة اللاحقة إلى رمز الآلة بسبب الطبيعة المنهجية للترجمة. أدى هذا إلى زيادة أداء البرامج.

بعد تعلم كيفية تجميع البرامج (لقد قمت بتبسيط تطور التجميع ، في الواقع كانت خطوة صعبة للغاية ، لأنها عملية معقدة للغاية) ، بدأت عملية إنشاء البرامج تتكون من إنشاء ملف مع الكود المصدري لـ البرنامج وتجميعه وتنفيذه في النهاية.

سرعان ما لوحظ أن عملية التجميع شاقة للغاية وتستهلك الكثير من الموارد ، بما في ذلك وقت الآلة ، وأن العديد من الوظائف المدرجة في هذه البرامج قد تم استخدامها مرارًا وتكرارًا في برامج مختلفة. علاوة على ذلك ، عندما قام شخص ما بتغيير جزء من البرنامج ، فإن تجميع الكود المُدرج يعني إعادة تجميع كود المصدر بالكامل مرة أخرى ، بما في ذلك ترجمة جديدة لكل الكود الذي لم يتغير.

لهذا السبب ، بدأ استخدام التجميع المعياري. كان معناه تقسيم البرنامج ، من ناحية ، إلى البرنامج الرئيسي ، ومن ناحية أخرى ، تلك الوظائف التي تم استخدامها مرارًا وتكرارًا والتي تم تجميعها وتخزينها بالفعل في مكان خاص (سنسميها هذا سلف المكتبة).

ثم أصبح من الممكن تطوير البرامج التي تدعم هذه الوظائف دون بذل جهد إضافي لترميزها مرارًا وتكرارًا. حتى ذلك الحين ، كانت العملية معقدة نظرًا لحقيقة أنه عند ربط البرامج ، كان من الضروري دمج جميع الأجزاء ويجب أن يعرفها المبرمج (وقد أدى ذلك إلى تكاليف إضافية للتحقق من إمكانية استخدام وظيفة معروفة تستخدم / يتطلب وظائف أخرى غير معروفة).

3.- ما هي المكتبة؟

أدت المشكلة الموصوفة أعلاه إلى إنشاء مكتبات. هذا ليس أكثر من نوع خاص من الملفات (على وجه الدقة ، أرشيف ، tar (1) أو cpio (1)) مع معلمات خاصة ، التنسيق الذي يفهمه الرابط ، وعندما نشير إلى أرشيف مكتبة ، لا يختار برنامج LINKER سوى تلك الوحدات التي تحتاج إلى برنامج ويستبعد كل شيء آخر. ظهرت ميزة جديدة. أصبح من الممكن الآن تطوير البرامج التي تستخدم مكتبات كبيرة للوظائف ، ولم يكن المبرمج بحاجة إلى معرفة كل تبعيات الوظائف في تلك المكتبة.

المكتبات التي ناقشناها حتى الآن لم تذهب أبعد من ذلك في التطوير. لقد أضافوا للتو ملفًا ، غالبًا ما يوجد في بداية الأرشيف ، يحتوي على أوصاف الوحدة والمعرفات التي يجب على الرابط حلها دون قراءة المكتبة بأكملها (وبالتالي يلغي الحاجة إلى قراءة المكتبة عدة مرات). يتم تنفيذ هذه العملية (إضافة جدول الرموز إلى أرشيف المكتبة) في Linux بواسطة الأمر ranlib (1). تُعرف المكتبات الموصوفة حتى الآن باسم مكتبات ثابتة.

حدث التقدم بعد ظهور أول نظام متعدد المهام: كود تقسيم... إذا تم تشغيل نسختين من نفس الكود على نفس النظام ، فسيكون من المرغوب فيه لكلتا العمليتين أن تكونا قادرتين على مشاركة نفس الكود ، لأن البرنامج لا يقوم عادة بتعديل الكود الخاص به. هذه الفكرة تلغي الحاجة إلى تخصيص نسخ متعددة في الذاكرة ، مما يحرر الكثير من الذاكرة على أنظمة ضخمة متعددة المستخدمين.

أخذ هذا الابتكار الأخير خطوة إلى الأمام ، شخص ما (لا أعرف من هو ، لكن الفكرة كانت رائعة ؛-) يعتقد أنه في كثير من الأحيان تستخدم العديد من البرامج نفس المكتبة ، ولكن نظرًا لكونها برامج مختلفة ، فأجزاء من المكتبات المستخدمة لم تكن بالضرورة نفس الأجزاء التي يستخدمها برنامج آخر. علاوة على ذلك ، كان الكود الرئيسي مختلفًا (هما برنامجان مختلفان) ، لذلك لم تتم مشاركة نصوصهما. حسنًا ، اعتقد بطلنا أنه إذا كان بإمكان البرامج المختلفة التي تستخدم نفس المكتبة مشاركة هذه المكتبة فيما بينها ، فيمكننا اكتساب بعض الذاكرة. الآن برامج مختلفة ، لها نصوص مختلفة ، تعمل بنفس كود المكتبة.

ومع ذلك ، أصبحت العملية الآن أكثر تعقيدًا. البرنامج القابل للتنفيذ غير مرتبط بشكل كامل ، ولكن يتم تأجيل حل مراجع معرفات المكتبة حتى يتم تحميل البرنامج. يتعرف الرابط (ld (1) في حالة Linux) على مكالمات المكتبة المشتركة ولا يتضمن كودها في البرنامج. يتعرف النظام نفسه ، النواة ، عند تنفيذ exec () على بدء تشغيل برنامج باستخدام مكتبات مشتركة وينفذ رمزًا خاصًا يقوم بتحميل مكتبات مشتركة (تخصيص ذاكرة مشتركة لنصها ، وتخصيص ذاكرة خاصة لقيم المكتبة ، وما إلى ذلك). الآن يتم تنفيذ هذه العملية عند تحميل الملف القابل للتنفيذ وأصبح الإجراء بأكمله أكثر تعقيدًا.

بالطبع ، عندما يصادف الرابط مكتبة عادية ، فإنه يستمر في التصرف كما كان من قبل.

المكتبة المشتركة ليست أرشيفًا يحتوي على رمز الكائن ، بل هي ملف يحتوي على رمز الكائن نفسه. عند ربط برنامج بمكتبة مشتركة ، لا يقوم الرابط بفحص المكتبة ، والوحدات التي يجب إضافتها إلى البرنامج وأيها لا ينبغي. يتأكد فقط من حل الارتباطات التي لم يتم حلها ، ويحدد ما يجب إضافته إلى القائمة عند تضمين المكتبة. من الممكن إنشاء مكتبة أرشيف ar (1) لجميع المكتبات المشتركة ، ولكن هذا لا يتم غالبًا ، نظرًا لأن المكتبات المشتركة غالبًا ما تكون نتيجة لربط وحدات مختلفة ، لذلك ستكون المكتبة مطلوبة لاحقًا ، في وقت التشغيل. ربما لا تكون مكتبة الأسماء المشتركة هي الأكثر ملاءمة وسيكون من الأكثر دقة تسميتها كائنًا مشتركًا (ومع ذلك ، نظرًا لأننا قد لا نفهم ، فنحن لا نستخدم هذا المصطلح).

4.- أنواع المكتبات.

كما قلنا ، هناك نوعان من المكتبات في Linux: المكتبات الثابتة والمشتركة. المكتبات الثابتة هي مجموعة من الوحدات النمطية التي يتم دمجها في أرشيف باستخدام الأداة المساعدة ar (1) ويتم فهرستها باستخدام الأداة المساعدة ranlib (1). غالبًا ما يتم تخزين هذه الوحدات في ملف ينتهي بـ .a (لا أستخدم مصطلح الامتداد لأن Linux لا يستخدم مفهوم امتداد الملف). يتعرف الرابط على نهاية ملف .a ويبدأ في البحث عن الوحدات النمطية كما لو كانت مكتبة ثابتة ، ويختار ويضيف إلى البرنامج تلك الوحدات النمطية التي تحل المراجع التي لم يتم حلها.

على عكس المكتبات الثابتة ، فإن المكتبات المشتركة ليست أرشيفات ، ولكنها كائنات قابلة للنقل ، تم تحديدها بواسطة كود خاص (الذي يعينها كمكتبات مشتركة). الرابط ld (1) ، كما ذكرنا سابقًا ، لا يضيف وحدات إلى كود البرنامج ، ولكنه يختار المعرفات التي توفرها المكتبة على النحو المسموح به ، ويضيف تلك التي تطلبها المكتبة نفسها ، ويستمر في العمل دون إضافة أي كود ، بافتراض أن الكود المطلوب قد تمت إضافته بالفعل إلى الكود الرئيسي. يتعرف الرابط ld (1) على المكتبات المشتركة من خلال الانتهاء بـ.

5. - عملية الربط في لينكس.

يتكون كل برنامج من وحدات كائن مرتبطة بملف قابل للتنفيذ. يتم ذلك عن طريق الرابط ld (1) المستخدم في Linux.

يدعم ld (1) العديد من الخيارات التي تغير سلوكه ، لكننا سنقتصر هنا فقط على تلك المتعلقة باستخدام المكتبات بشكل عام. لا يتم استدعاء ld (1) مباشرة من قبل المستخدم ، ولكن من قبل المترجم gcc (1) نفسه في مرحلته النهائية. القليل من المعرفة عنه طريقة العملساعدنا في فهم طريقة استخدام المكتبات في Linux.

لكي يعمل ld (1) بشكل صحيح ، فإنه يحتاج إلى قائمة بالكائنات لربطها بالبرنامج. يمكن تحديد هذه الكائنات بأي ترتيب (*) طالما أننا نتبع الاصطلاح أعلاه ، كما ذكرنا سابقًا ، يتم التعرف على المكتبة المشتركة بالنهاية. لذا (ليس .so.xx.yy) والمكتبة الثابتة بواسطة .a (وبالطبع فإن ملفات الكائنات البسيطة هي تلك التي ينتهي اسمها بـ .o).

(*) هذا ليس صحيحا تماما. يتضمن ld (1) فقط تلك الوحدات النمطية التي تحل الروابط في وقت إدراج المكتبة ، لذلك ، في وحدة مدرجة لاحقًا ، قد لا يزال هناك رابط ذلك لاحقًا ، لأنه لا يظهر في وقت إدراج هذه المكتبة ، يمكن أن يتسبب في أمر يتضمن المكتبات الضرورية ...

من ناحية أخرى ، يسمح ld (1) بإدراج المكتبات القياسية بفضل الخيارين -l و -L.

لكن .. ماذا نعني بالمكتبة القياسية ، ما الفرق؟ لا. فقط هذا ld (1) يبحث عن مكتبات قياسية في أماكن معينة ، بينما تلك الموصوفة في قائمة المعلمات ككائنات يتم البحث عنها بأسماء ملفاتها.

افتراضيًا ، يتم البحث عن المكتبات في الدلائل / lib و / usr / lib (على الرغم من أنني سمعت أنه بناءً على إصدار / تنفيذ ld (1) ، قد تكون هناك أدلة إضافية). -L يسمح لنا بإضافة أدلة إلى تلك التي تم البحث عنها بواسطة بحث عادي في المكتبة. يتم استخدامه من خلال تحديد الدليل -L لكل دليل نريد إضافته. يتم تحديد المكتبات القياسية باستخدام الخيار -l Name (حيث يحدد الاسم المكتبة المراد تحميلها) وسيقوم ld (1) بالبحث ، بالترتيب المناسب ، في الدلائل المناسبة عن ملف يسمى libName.so. إذا لم يتم العثور عليه ، فسيتم إجراء محاولة للعثور على libName.a ، نسخته الثابتة.

إذا عثر ld (1) على libName.so ، فسيتم ربطه كمكتبة مشتركة ، بينما إذا عثر على libName.a ، فإنه سيربط الوحدات النمطية المشتقة منه إذا قاموا بحل أي مراجع لم يتم حلها.

يتم تنفيذ الارتباط الديناميكي عندما يتم تحميل الملف التنفيذي بواسطة وحدة خاصة (في الواقع ، هذه الوحدة الخاصة هي المكتبة المشتركة نفسها) تسمى /lib/ld-linux.so.

توجد في الواقع وحدتان لربط المكتبات الديناميكية: /lib/ld.so (للمكتبات التي تستخدم تنسيق a.out القديم) و /lib/ld-linux.so (للمكتبات التي تستخدم تنسيق ELF الجديد).

تكمن خصوصية هذه الوحدات في أنه يجب تحميلها في كل مرة يتم فيها ربط البرنامج ديناميكيًا. أسمائهم قياسية (السبب هو أنه لا يمكن نقلهم من الدليل / lib ، كما لا يمكن تغيير أسمائهم). إذا قمنا بتغيير الاسم /etc/ld-linux.so ، فإننا نتوقف تلقائيًا عن استخدام أي برنامج يستخدم المكتبات المشتركة ، لأن هذه الوحدة مسؤولة عن حل جميع الروابط التي لم يتم حلها في وقت التشغيل.

يتم مساعدة الوحدة الأخيرة من خلال وجود ملف /etc/ld.so.cache ، والذي يحدد لكل مكتبة أنسب ملف تنفيذي يحتوي على تلك المكتبة. سنعود إلى هذا الموضوع لاحقًا.

7.- سونام. إصدارات المكتبة القابلة للتنفيذ. التوافق.

يقودنا هذا إلى الموضوع الأكثر إرباكًا للمكتبات المشتركة: إصداراتها.

غالبًا ما نرى الرسالة "لم يتم العثور على مكتبة libX11.so.3" ، مما يتركنا في حيرة من أمرنا: بوجود مكتبة libX11.so.6 ، لا يمكننا فعل أي شيء. كيف يمكن أن يتعرف ld.so (8) على libpepe.so.45.0.1 و libpepe.so.45.22.3 ولا يتعرف على libpepe.so.46.22.3 بالتبادل؟

في Linux (وعلى جميع أنظمة التشغيل التي تستخدم تنسيق ELF) ، يتم تحديد المكتبات من خلال تسلسل الأحرف المميز: soname.

يتم تضمين soname في المكتبة نفسها ، ويتم تحديد هذا التسلسل عند ربط الأشياء التي تتكون منها المكتبة. عند إنشاء مكتبة مشتركة ، لإعطاء قيمة لسلسلة الأحرف هذه ، يجب عليك تمرير الخيار ld (1) (-Soname<имя_библиотеки>).

يتم استخدام تسلسل الأحرف هذا بواسطة المُحمل الديناميكي لتحديد المكتبة المشتركة المراد تحميلها وتحديد الملف القابل للتنفيذ. يبدو شيئًا كالتالي:
يكتشف Ld-linux.so أن البرنامج يتطلب مكتبة ويحدد اسمها. ثم يتم البحث عن الاسم في /etc/ld.so.cache ويتم تحديد اسم الملف الذي يحتوي على هذه المكتبة. بعد ذلك ، تتم مقارنة اسم السونام المطلوب مع اسم المكتبة الحالية ، وإذا كانا متطابقين ، فنحن بحاجة إليه! إذا لم يتم العثور عليه ، فسيستمر البحث حتى يتم العثور عليه ، أو إذا لم يتم العثور عليه ، فسيتم عرض رسالة خطأ.

يمكن استخدام soname لتحديد ما إذا كانت المكتبة مناسبة للتحميل ، لأن ld-linux.so يتحقق مما إذا كان السونام المطلوب هو نفس الملف المطلوب. في حالة الاختلاف ، يمكننا الحصول على "libXXX.so.Y غير موجود" الشهير. إنه الابن الذي يتم البحث عنه ويتم تحديد الخطأ الذي تم إرجاعه بواسطة Soname.

إذا قمنا بتغيير اسم المكتبة ، فقد يكون هناك الكثير من الالتباس وستظل المشكلة نفسها قائمة. لكن تغيير Soname ليس فكرة جيدة أيضًا ، لأن هناك اتفاقية في مجتمع Linux لتعيين soname:

يجب أن يحدد اسم مكتبة ما ، بشكل افتراضي ، المكتبة المقابلة والواجهة الخاصة بتلك المكتبة. إذا قمنا بإجراء تغييرات على المكتبة التي تؤثر فقط على الوظائف الداخلية ، ولكن الواجهة بقيت دون تغيير (عدد الوظائف ، المتغيرات ، معلمات الوظيفة) ، عندها ستكون المكتبتان قابلتان للتبادل وسنقول بشكل عام أن التغييرات كانت طفيفة (كلاهما المكتبات متوافقة ويمكننا استبدال واحدة فوق الأخرى). إذا حدث هذا ، فإن الرقم الصغير (الذي ليس جزءًا من السونام) يتغير كثيرًا ويمكن استبدال المكتبة دون مشاكل كبيرة.

ومع ذلك ، عندما نضيف وظائف ، ونزيل الوظائف ، وبشكل عام ، قم بتغيير واجهة المكتبة ، لم يعد من الممكن القول إن هذه المكتبة قابلة للتبديل مع المكتبة السابقة (على سبيل المثال ، استبدال libX11.so.3 بـ libX11. يمثل ذلك 6 جزءًا من الانتقال من X11R5 إلى X11R6 ، عندما يقدم هذا وظائف جديدة وبالتالي يغير الواجهة). من المحتمل ألا يؤدي الانتقال من X11R6-v3.1.2 إلى X11R6-v3.1.3 إلى تغيير الواجهة وسيكون للمكتبة نفس اسم الصوت - على الرغم من الاحتفاظ بالإصدار القديم ، نحتاج إلى إعطائها اسمًا مختلفًا (لهذا السبب ، رقم الإصدار ينهي اسم المكتبة ، بينما يتم تحديد الأرقام الرئيسية فقط في سونام).

8.- ldconfig (8)

كما قلنا سابقًا ، يسمح /etc/ld.so.cache لـ ld-linux.so بتحويل Soname للملف الموجود في المكتبة. هذا ملف ثنائي (للكفاءة) تم إنشاؤه بواسطة الأداة المساعدة ldconfig (8).
ينشئ ldconfig (8) ارتباطًا رمزيًا مع اسم المكتبة soname لكل DLL موجود في الدلائل المحددة في /etc/ld.so.conf. في هذه الحالة ، عندما يريد ld.so الحصول على اسم ملف ، فإن ما يفعله هو تحديد الملف بالاسم المطلوب من قائمة الدليل. وبالتالي لا داعي لتشغيل ldconfig (8) في كل مرة تقوم فيها بإضافة مكتبة. نقوم بتشغيل ldconfig فقط عندما نضيف دليلًا إلى القائمة.

9.- أريد إنشاء مكتبة ديناميكية.

قبل أن نبدأ في إنشاء مكتبة ديناميكية ، يجب أن نفكر فيما إذا كانت ضرورية حقًا. تتسبب المكتبات الديناميكية في تحميل النظام الزائد لعدة أسباب:
    يتم تحميل البرنامج على عدة مراحل ؛ واحد لتحميل البرنامج الرئيسي ، والباقي لكل مكتبة ارتباط ديناميكي يستخدمها هذا البرنامج (سننظر في ذلك لمكتبة الارتباط الديناميكي المقابلة ، لأن هذه النقطة الأخيرة لم تعد نادرة وأصبحت ميزة).

    يجب أن تحتوي مكتبات DLL على تعليمات برمجية قابلة لتغيير موضعها لأن العنوان المخصص لعملية ما في مساحة العنوان الظاهرية غير معروف حتى يتم تحميله. في هذه الحالة ، يضطر المترجم إلى حجز سجل لتخزين موضع تحميل المكتبة ، ونتيجة لذلك ، لدينا سجل واحد أقل لتحسين الكود. هذه ليست مشكلة ، لأن الحمل الزائد الناتج في معظم الحالات لا يزيد عن 5 ٪ من الحمل الزائد.

بالنسبة للمكتبة الديناميكية ، فإن الحالة الأكثر قبولًا هي عندما يتم استخدامها باستمرار من قبل بعض البرامج (وهذا يساعد على تجنب تفريغ نص المكتبة بعد إنهاء العملية التي تم تحميلها. بينما تستخدم العمليات الأخرى وحدات المكتبة ، فإنها تظل في الذاكرة) .

يتم تحميل المكتبة المشتركة بالكامل في الذاكرة (وليس فقط الوحدات التي تحتاجها) ، لذلك يجب استخدامها بالكامل لتكون مفيدة. أسوأ مثال على استخدام مكتبة الارتباط الديناميكي هو استخدام وظيفة واحدة فقط ، و 90٪ من المكتبة نادرًا ما يتم استخدامها.

تعد مكتبة C القياسية مثالًا جيدًا لمكتبة الارتباط الديناميكي (يتم استخدامها بواسطة جميع البرامج المكتوبة بلغة C). يتم استخدام جميع الوظائف في المتوسط.

لا تحتاج المكتبة الثابتة إلى تضمين وظائف نادرة الاستخدام ؛ طالما أنها مضمنة في الوحدة النمطية الخاصة بها ، فلن يتم ربطها بأي برنامج لا يتطلبها.

9.1.- تجميع أكواد المصدر
إن تجميع الكود المصدري هو بالضبط نفس الشيء بالنسبة لشفرة المصدر العادية ، فيما عدا أننا سنستخدم "-f PIC" (كود مستقل للموضع).

هذه الخطوة أساسية لأنه في مكتبة ثابتة يتم حل موضع كائنات المكتبة أثناء الارتباط ، لذلك يستغرق وقتًا ثابتًا. لم تكن هذه الخطوة ممكنة في الثنائيات القديمة a.out ، مما أدى إلى وضع كل مكتبة مشتركة في موضع ثابت في مساحة العنوان الافتراضية. نتيجة لذلك ، يمكن أن تنشأ التعارضات في أي وقت إذا أراد البرنامج استخدام مكتبتين وتحميلهما في مناطق متداخلة من الذاكرة الافتراضية. هذا يعني أنك أُجبرت على الاحتفاظ بقائمة حيث يتعين على كل شخص يريد أن يجعل المكتبة ديناميكية أن يعلن عن مجموعة من العناوين لاستخدامها حتى لا يتمكن أي شخص آخر من استخدامها.

كما لاحظنا بالفعل ، فإن تسجيل مكتبة ديناميكية في القائمة الرسمية ليس ضروريًا ، لأنه عندما يتم تحميل المكتبة ، يتم وضعها في الموضع المحدد في الوقت الحالي ، على الرغم من ضرورة نقل الكود.

9.2.- ربط الأشياء بالمكتبة
بعد تجميع كل الكائنات ، يجب ربطها بتحديد خيار يقوم بإنشاء كائن قابل للتحميل ديناميكيًا. مكتبة مشتركة gcc -shared -o libName.so.xxx.yyy.zzz -Wl، -soname، libName.so.xxx. دعونا نتعامل مع كل واحد على حدة:
    -مشاركة.
    هذا يخبر الرابط أنه في النهاية يجب أن ينشئ المكتبة المشتركة وبالتالي يجب أن يحتوي على كود قابل للتنفيذ في ملف الإخراج المقابل للمكتبة.

    O lib Name.so.xxx.yyy.zzz.
    هذا هو اسم ملف الإخراج. ليس من الضروري على الإطلاق اتباع اصطلاح التسمية ، ولكن إذا أردنا أن تصبح هذه المكتبة معيارًا للتطوير المستقبلي ، فمن الأفضل اتباعها.

    Wl، -soname، lib Name.so.xxx.
    يقوم الخيار -Wl بإخبار مجلس التعاون الخليجي (1) باتباع الخيارات (مفصولة بفواصل) المخصصة للرابط. تستخدم هذه الآلية من قبل دول مجلس التعاون (1) لتمرير الخيارات إلى ld (1). في المثال ، نقوم بتمرير الخيارات التالية إلى الرابط:

-Soname libName.so.xxx يغير هذا الخيار اسم Soname للمكتبة ، لذلك سيتم تحميل هذه المكتبة عندما تطلبها البرامج التي تتطلب اسم Soname المحدد.
9.3.- تركيب المكتبة
حسنًا ، لدينا بالفعل الملف القابل للتنفيذ المقابل. الآن ، لتتمكن من استخدامه ، يجب تثبيته في المكان المناسب.

لتجميع برنامج يتطلب مكتبتنا الجديدة ، نحتاج إلى استخدام الأمر التالي:

Gcc -o program lib Name.so.xxx.yyy.zzz أو ، إذا كانت المكتبة مثبتة في الدليل (/ usr / lib) ، فستكفي: gcc -o program -l Name (إذا كانت المكتبة في / usr / local / lib ، ثم فقط أضف الخيار "-L / usr / local / lib"). لتثبيت المكتبة ، قم بما يلي:

    انسخ المكتبة إلى الدليل / lib أو / usr / lib. إذا اخترت نسخه إلى موقع مختلف (على سبيل المثال ، / usr / local / lib) ، فلا يمكنك التأكد من أن الرابط ld (1) سيجده تلقائيًا عند ربط برامجك.

    قم بتشغيل ldconfig (1) لإنشاء ارتباط رمزي libName.so.xxx.yyy.zzz إلى libName.so.xxx. في هذه الخطوة ، سنعرف ما إذا كنا قد اتبعنا جميع الخطوات السابقة بشكل صحيح وما إذا كان يتم التعرف على المكتبة على أنها ديناميكية. تؤثر هذه الخطوة فقط على تحميل المكتبة في وقت التشغيل ، وليس ربط البرامج.

    لكي يتمكن الرابط من العثور على المكتبة ذات الخيار -l ، قم بإنشاء ارتباط رمزي من libName.so.xxx.yyy.zzz (أو libName.so.xxx ، soname) إلى libName.so. لكي تعمل هذه الآلية ، يجب أن يتطابق اسم المكتبة مع النمط lib Name.so

10.- إنشاء مكتبة ثابتة

من ناحية أخرى ، إذا كنت بحاجة إلى إنشاء مكتبة ثابتة (أو كنت بحاجة إلى نسختين لتتمكن من إنشاء نسخ مرتبطة بشكل ثابت) ، فأنت بحاجة إلى القيام بما يلي:

ملاحظة: عند البحث عن مكتبات ، يبحث الرابط أولاً عن ملف باسم libName.so ، وبعد ذلك فقط يبحث libName.a. إذا أطلقنا على كل من هاتين المكتبتين (الإصدارات الثابتة والديناميكية) نفس الاسم ، فسيكون من المستحيل بشكل عام تحديد أي منهما سيتم ربطه في كل حالة (تكون المكتبة الديناميكية مرتبطة دائمًا أولاً ، لأن الرابط يكتشفها أولاً ).

لهذا السبب ، إذا كان من الضروري وجود نسختين من نفس المكتبة ، فمن المستحسن دائمًا تسمية الإصدار الثابت بالصيغة libName_s.a ، و libName.so الديناميكي. بعد ذلك ، عند الارتباط ، ستحتاج إلى تحديد:

برنامج Gcc -o -l Name_s للربط بإصدار ثابت ، بينما للإصدار الديناميكي: gcc -o program -l

10.1.- تجميع كود المصدر
لا يتعين عليك اتخاذ أي خطوات خاصة لتجميع شفرة المصدر. وبالمثل ، يتم تحديد موضع الكائنات في مرحلة الارتباط ، وليس من الضروري إجراء التحويل البرمجي باستخدام الخيار -f PIC (على الرغم من إمكانية الاستمرار في استخدامه).
10.2.- ربط الأشياء بالمكتبة
لم يتم ربط المكتبات الثابتة. يتم أرشفة جميع الكائنات في ملف مكتبة باستخدام الأمر ar (1). علاوة على ذلك ، من أجل حل الرموز بسرعة ، يُنصح بتنفيذ الأمر ranlib (1) في المكتبة. على الرغم من أنه ليس مطلوبًا ، يمكن أن يؤدي الفشل في تنفيذ هذا الأمر إلى إلغاء ارتباط الوحدات النمطية في الملف التنفيذي لأنه عندما يعالج الرابط الوحدة النمطية أثناء إنشاء المكتبة ، لا يتم حل جميع التبعيات غير المباشرة بين الوحدات النمطية على الفور: على سبيل المثال ، تحتاج الوحدة النمطية في نهاية الأرشيف إلى وحدة نمطية أخرى في بداية الأرشيف ، وهذا يعني أن الأمر يستغرق عدة تمريرات عبر نفس المكتبة لحل جميع الروابط.
10.3.- تثبيت المكتبة
يُنصح بتسمية المكتبات الثابتة بتنسيق libName.a فقط إذا كنت تريد أن يكون لديك مكتبات ثابتة فقط. في حالة وجود نوعين من المكتبات ، أوصي بالاتصال بهما libName_s.a بحيث يسهل التمييز بين وقت تحميل مكتبة ثابتة ومتى يتم تحميل مكتبة ديناميكية.

تسمح لك عملية الإنشاء بالدخول إلى الخيار الثابت. يتحكم هذا الخيار في تحميل الوحدة النمطية /lib/ld-linux.so ، ولا يؤثر على ترتيب البحث في المكتبة ، لذلك إذا حدد شخص ما -static ووجد ld (1) مكتبة ديناميكية ، فستعمل معها (وليس استمر في البحث عن مكتبة ثابتة). سيؤدي ذلك إلى حدوث أخطاء في وقت التشغيل بسبب استدعاءات الإجراءات في مكتبة ليست جزءًا من الملف القابل للتنفيذ - الوحدة النمطية للتحميل الديناميكي التلقائي غير مرتبطة وبالتالي لا يمكن تنفيذ العملية.

11.- مقارنة التخطيط الثابت والديناميكي

لنفترض أننا نريد إنشاء توزيع لبرنامج يستخدم مكتبة يمكننا توزيعه بشكل ثابت فقط مدرج في البرنامج ، وليس بأي شكل آخر (مثال على هذه الحالة هو التطبيقات التي تم إنشاؤها باستخدام Motif).

هناك طريقتان لإنشاء مثل هذا البرنامج. الأول هو إنشاء ملف تنفيذي مرتبط بشكل ثابت (باستخدام مكتبات .a فقط وليس باستخدام أداة تحميل ديناميكية). يتم تحميل هذا النوع من البرامج مرة واحدة ولا يتطلب أي مكتبات من النظام (ولا حتى /lib/ld-linux.so). ومع ذلك ، فإن لديهم عيبًا يتمثل في أن كل ما تحتاجه يجب أن يتم حفظه في ملف ثنائي واحد ، وبالتالي فهي عادةً ملفات كبيرة جدًا. الخيار الثاني هو إنشاء برنامج مرتبط ديناميكيًا ، أي أن البيئة التي سيعمل فيها تطبيقنا يجب أن تحتوي على جميع المكتبات الديناميكية المقابلة. يمكن أن يكون الملف القابل للتنفيذ صغيرًا جدًا ، على الرغم من أنه في بعض الأحيان يكون من المستحيل وجود جميع المكتبات على الإطلاق (على سبيل المثال ، هناك أشخاص ليس لديهم Motif).

يوجد خيار ثالث ، مختلط ، يتم فيه ربط بعض المكتبات ديناميكيًا والبعض الآخر بشكل ثابت. في هذه الحالة ، سيكون من المنطقي تحديد المكتبة المتضاربة في شكلها الثابت وجميع المكتبة الأخرى في شكلها الديناميكي. هذا البديل هو شكل شائع جدًا لتوزيع البرامج.

على سبيل المثال ، يمكنك تجميع ثلاثة إصدارات مختلفة من البرنامج على النحو التالي:

Gcc -static -o program.static program.o -lm_s -lXm_s -lXt_s -lX11_s \ -lXmu_s -lXpm_s gcc -o program.dynamic program.o -lm -lXm -lXt -lX11 -lXmu -lXpm gcc -o program. مختلط program.o -lm -lXm_s -lXt -lX11 -lXmu -lXpm في الحالة الثالثة ، يتم ربط مكتبة Motif فقط (-lXm_s) بشكل ثابت ، ويتم ربط جميع المكتبة الأخرى ديناميكيًا. يجب أن تحتوي البيئة التي سيتم تشغيل البرنامج فيها على الإصدارات المناسبة من المكتبات libm.so.xx libXt.so.xx libX11.so.xx libXmu.so.xx و libXpm.so.xx

مكتبة مشتركةأو مكتبة مشتركةهو ملف مخصص للمشاركة بين البرامج. يتم تحميل الوحدات النمطية التي يستخدمها البرنامج من كائنات منفصلة مشتركة في الذاكرة ، بدلاً من نسخها بواسطة الرابط عندما يقوم بنسخ ملف واحد قابل للتنفيذ للبرنامج.

يمكن ربط المكتبات المشتركة بشكل ثابت ، مما يعني أنه يتم حل المراجع إلى وحدات المكتبة النمطية وتخصيص ذاكرة للوحدات النمطية عند إنشاء الملف القابل للتنفيذ. ولكن غالبًا ما يتأخر ربط المكتبات المشتركة حتى يتم تحميلها.

بعض الأنظمة القديمة مثل بوروز إم سي بيتحتوي Multics أيضًا على تنسيق واحد فقط للملفات القابلة للتنفيذ ، سواء كانت عامة أم لا. لقد قاموا بمشاركة ملفات المكتبة بنفس تنسيق الملفات التنفيذية. هذا له ميزتان رئيسيتان: أولاً ، يتطلب كل منهما أداة تحميل واحدة فقط ، وليس اثنين (يؤدي وجود أداة تحميل إقلاع منفصلة إلى تعقيد إضافي). ثانيًا ، يسمح أيضًا باستخدام الملفات التنفيذية كمكتبات مشتركة إذا كان لديهم جدول رموز. التنسيقات النموذجية للمكتبات المشتركة القابلة للتنفيذ والمشتركة هي ELF و Mach-O (كلاهما على Unix) و (Windows).

في بعض البيئات القديمة مثل 16 بت Windows أو MPEل HP 3000، في رمز مع مكتبة مشتركة ، تم السماح فقط بالبيانات المستندة إلى المكدس (المحلية) ، أو تم فرض قيود مهمة أخرى على رمز المكتبة المشتركة.

ذكريات مشتركه

يمكن مشاركة رمز المكتبة في الذاكرة مع العمليات ، وكذلك على القرص. إذا تم استخدام الذاكرة الظاهرية ، فسيتم تنفيذ العمليات في صفحة فعلية من ذاكرة الوصول العشوائي (RAM) ، والتي تحدد مساحات عناوين العملية المختلفة. هذا له مزاياه. على سبيل المثال ، في نظام OpenStep ، غالبًا ما تكون التطبيقات قليلة الحجم ويتم تحميلها بسرعة ؛ كان معظم شفراتهم في مكتبات تم تحميلها بالفعل بواسطة نظام التشغيل لأغراض أخرى.

يمكن للبرامج مشاركة ذاكرة الوصول العشوائي باستخدام كود مستقل ، كما هو الحال في Unix ، مما ينتج عنه بنية معقدة ومرنة. هذا يضمن وجود احتمالية أكبر للمشاركة من خلال تقنيات مختلفة مثل التعيين المسبق لمساحة العنوان وحجز الصفحات لكل مكتبة مشتركة. الخيار الثالث هو تخزين أحادي الطبقةاستعمل من قبل نظام IBM / 38وخلفاؤه.

في بعض الحالات ، يمكن أن تتسبب الإصدارات المختلفة من المكتبات المشتركة في حدوث مشكلات ، خاصةً عندما يكون للمكتبات ذات الإصدارات المختلفة نفس أسماء الملفات وتستخدم لتطبيقات مختلفة مثبتة على النظام ، فكل منها يتطلب إصدارًا محددًا. يُعرف مثل هذا السيناريو بـ

تتيح لك المكتبة المشتركة استخدام الرموز التي تحتوي عليها في أفلام متعددة دون نسخ هذه الرموز إلى مكتبات الأفلام. وبسبب هذا ، يتم تسمية كائنات المكتبة المشتركة مصادر(الأصول). في هذه الحالة ، يتم استخدام المكتبة المشتركة كملف خارجي ولا تتم إضافتها إلى الفيلم الذي تم إنشاؤه (أو تحريره).

يُنصح باستخدام المكتبات المشتركة ، على سبيل المثال ، في الحالات التالية:

  • عند استخدام نفس المقطع الصوتي في عدة صفحات من الموقع ؛
  • عند استخدام أحرف نصية للخط في عدة صفحات من الموقع ؛
  • عندما تريد توفير مصدر واحد لعناصر الرسوم المتحركة المستخدمة في مشاهد متعددة في فيلم أو في أفلام متعددة ؛
  • عندما تحتاج إلى مكتبة مركزية من الموارد لتسهيل التحكم في التغييرات التي تجريها.

يدعم Flash MX نوعين من المكتبات المشتركة:

  • مدة العرض- مكتبة وقت التشغيل المشتركة ؛ الرموز المدرجة في مثل هذه المكتبة متاحة للمشاركة في العديد من الأفلام ، ومع ذلك ، لا يمكن تحرير هذه الرموز إلا مباشرة في الفيلم المصدر ؛
  • وقت المؤلف- مكتبة مشتركة في وقت التطوير ؛ الرموز الموجودة في هذه المكتبة متاحة للمشاركة في عدة أفلام ، ويسمح بتعديل محتويات المكتبة في أي فيلم شريك.

لكي تتوفر موارد المكتبة المشتركة في الأفلام المستضافة على موقع بعيد ، يجب تصدير ملف Flash بالمكتبة إلى تنسيق SWF وتحميله إلى موقع الويب.

تعليق
يدعم الإصدار السابق من Flash مكتبة وقت التشغيل المشتركة فقط
.

لإنشاء مكتبة مشتركة مثل مدة العرض، من الضروري:

  1. تحديد مصادره (الرموز المدرجة فيه) في فيلم منفصل.
  2. السماح بتصدير الشخصيات المشتركة.
  3. حدد عنوان URL الخاص بالموقع الذي ستتم فيه استضافة المكتبة.
  4. قم بتصدير ملف الفلاش بهذه المكتبة إلى تنسيق SWF وتحميله إلى موقع الويب.

لتتمكن من استخدام رموز المكتبة المشتركة مدة العرضفي الأفلام الأخرى ("المالكين المشتركين") ، من الضروري في كل منها إنشاء رابط إلى الشخصيات المشتركة.

الآن دعونا نلقي نظرة على الخطوات المذكورة أعلاه بمزيد من التفصيل.

بعد إنشاء مكتبة مشتركة ، تحتاج إلى تحديد الرموز المضمنة التي يمكن تصديرها إلى أفلام أخرى. هذا يتطلب الخطوات التالية:

  1. حدد الرمز من القائمة التي تريد جعلها "مشتركة".
  2. في قائمة سياق الرمز ، حدد الأمر ربط(ربط).
  3. في مربع الحوار المفتوح خصائص ارتباط الرمز(معلمات ربط الرمز) ، الشكل. 10.12 ، حدد المربع تصدير لمشاركة وقت التشغيل(السماح بالتصدير في وقت التشغيل).
  4. في مربع نص المعرفأدخل اسم (معرف) الرمز الذي سيتم تصديره تحته إلى فيلم المالك المشترك ؛ على الرغم من أن الاسم الافتراضي هو اسم رمز المكتبة ، إذا كان يحتوي على مسافات ، فقم بإزالتها.
  5. في مربع نص عنوان Urlأدخل عنوان الإنترنت للفيلم المصدر (أي ملف SWF للمكتبة المشتركة).
  6. إذا كان الرمز الذي تم تصديره سيستخدم مباشرة من الإطار الأول لفيلم الشريك في المالك ، فحدد تصدير في الإطار الأول.
  7. إذا كنت تريد إتاحة الرمز الذي تم تصديره في ActionScript ، فحدد ملف تصدير لـ ActionScript.

أرز. 10.12... مربع الحوار إعدادات رمز المكتبة المشتركة

لاستخدام موارد المكتبة المشتركة مدة العرضفي فيلم المالك المشترك ، الخطوات التالية مطلوبة:

  1. افتح مكتبة هذا الفيلم عن طريق الاختيار من القائمة نافذة او شباكأمر مكتبة.
  2. من القائمة المنسدلة للمكتبة ، اختر الأمر رمز جديدنتيجة لذلك ، سيظهر مربع حوار على الشاشة إنشاء رمز جديد(أنشئ رمزًا جديدًا) ، يشبه الجزء المركزي منه تنسيقه مع مربع الحوار خصائص ارتباط الرمز(شكل 10.13).
  3. في مربع نص المعرفأدخل اسم الرمز المراد استيراده إلى فيلم الشريك المالك.
  4. في مربع نص عنوان Urlأدخل عنوان الإنترنت الخاص بالفيلم المصدر.


أرز. 10.13... مربع حوار لتعيين معلمات الحرف المقسم

مكتبات ثابتة وديناميكية.

تسمى المكتبات "مجموعات" من الإجراءات الفرعية أو الكائنات ، كقاعدة عامة ، تركز على حل مجموعة من المشكلات ذات الصلة. المكتبات ثابتة وديناميكية من وجهة نظر تنظيمها واستخدامها.

يمكن أن تكون المكتبات الثابتة (المكتبات الثابتة) عبارة عن مجموعة من الأكواد المصدرية ، يتم تضمينها بواسطة المبرمج في برنامجه ، أو في شكل ملفات كائنات مُترجمة مسبقًا ، مرتبطة ببعضها البعض في مرحلة التجميع. في نظام التشغيل Windows ، عادةً ما يكون لهذه الملفات الامتداد<.lib>... نتيجة الارتباط بمكتبة ثابتة ، يشتمل البرنامج على جميع الوظائف التي يستخدمها ، مما يزيد من حجمها ، ولكنه يجعلها أكثر احتواءً ذاتيًا.

يتم تحميل المكتبات الديناميكية (المكتبة المشتركة ، مكتبة الارتباط الديناميكي) بواسطة نظام التشغيل عند "طلب" برنامج قيد التشغيل بالفعل أثناء تنفيذه. إذا تم بالفعل تحميل المكتبة المطلوبة في الذاكرة ، فلن يتم تنفيذ إعادة التحميل. في هذه الحالة ، يمكن استخدام نفس مجموعة الوظائف أو كائنات المكتبة في وقت واحد بواسطة عدة برامج قيد التشغيل ، مما يجعل من الممكن استخدام موارد ذاكرة الوصول العشوائي بكفاءة. عادةً ما تحتوي المكتبات المشتركة على Windows على الامتداد<.dll>.

لاستخدام المكتبة ، تحتاج إلى إخبار المترجم أنك بحاجة إلى توصيله واستدعاء الوظيفة من المكتبة (باستخدام ملف الرأس المناسب) ، بينما لا يلزم النص المصدر للوظيفة.

إنشاء مكتبة ديناميكية.

في Microsoft Visual Studio ، يشبه إنشاء مشروع لبناء مكتبة ارتباط ديناميكي الإجراء المعتاد لإنشاء مشروع لتطبيق أخرق. نوع المشروع هو Win32 Console Application ، فقط الآن تحتاج إلى تحديد عنصر "DLL" في معالج المشروع الجديد:

إذا لم يكن هناك عنصر من هذا القبيل في المعالج ، فيمكنك إنشاء مشروع تطبيق وحدة تحكم عادي ، ثم تعيين نوعه في خصائص المشروع:

خصائص التكوين => عام => نوع التكوين: مكتبة ديناميكية (.dll)

عرض باطل Declspec (dllexport) (حرف const char * str) ؛

# تضمين "dlltest.h"

عرض باطل (حرف * str)

يسمح معدّل __declspec (dllexport) للمكتبة بتصدير الوظيفة المحددة لتستخدمها التطبيقات الأخرى.

نتيجة بناء المشروع ملف مكتبة ديناميكي بالملحق<.dll>وأيضًا ملف مكتبة استيراد بالملحق<.lib>... تهدف مكتبة الاستيراد إلى تسهيل الاستخدام اللاحق للمكتبة الديناميكية. على الرغم من أن امتداد الملف الخاص بمكتبة الاستيراد هو نفس الامتداد القياسي للمكتبات الثابتة ، فلا يجب الخلط بينها.

باستخدام مكتبة ديناميكية.

هناك طريقتان لاستخدام مكتبة ديناميكية في البرنامج. يتضمن الارتباط الضمني استخدام مكتبة استيراد لتحديد عناوين الوظائف التي توفرها المكتبة. يقوم نظام التشغيل بتحميل DLL بعد تحميل ملف البرنامج القابل للتنفيذ. يستدعي الملف القابل للتنفيذ وظائف DLL المُصدَّرة كما لو كانت الوظائف موجودة في الملف القابل للتنفيذ نفسه.

عند الارتباط بشكل صريح ، يجب أن يقوم الملف التنفيذي الذي يستخدم DLL بإجراء استدعاءات وظيفية لتحميل DLL وإلغاء تحميله بشكل صريح والوصول إلى وظائف DLL المُصدَّرة. يستدعي العميل القابل للتنفيذ الوظائف التي تم تصديرها باستخدام مؤشر دالة.

بغض النظر عن الطريقة المختارة ، يمكن للملف القابل للتنفيذ استخدام نفس DLL. علاوة على ذلك ، فإن هذه الآليات ليست حصرية لبعضها البعض ، لأنه في حين أن أحد الملفات التنفيذية يرتبط ضمنيًا بـ DLL ، يمكن للآخر أن يرتبط بشكل صريح.

كمثال ، سوف نستخدم آلية الربط الضمنية (كأبسطها) لربط المكتبة البسيطة المُنشأة.

دعنا ننشئ مشروعًا منفصلاً لتطبيق وحدة تحكم عادي (من الممكن في إطار نفس الحل مثل مشروع المكتبة نفسها). لاستخدام وظيفة العرض المطبقة في المكتبة ، يجب عليك:

    قم بتوصيل ملف الرأس المقابل "dlltest.h". للقيام بذلك ، إما أن تستخدم المسار إلى الملف مباشرة في التوجيه #include (إذا كانت المشاريع في نفس مجلد الحل ، فمن الأفضل استخدام مسار نسبي) ، أو في خصائص المشروع أضف المسار إلى ملف الرأس هذا في القسم

معلمات التكوين => C / C ++ => عام => أدلة التضمين الإضافية

    استخدم ملف مكتبة الاستيراد المناسب. للقيام بذلك ، يمكنك استخدام توجيه من النموذج (هنا يتم استخدام المسار النسبي لملف lib المدمج).

بدلاً من ذلك ، يمكنك إضافة المسار إلى ملف مكتبة الاستيراد في خصائص المشروع ضمن

معلمات التكوين => الرابط => الإدخال => التبعيات الإضافية

لنقم الآن بإنشاء ملف البرنامج الرئيسي بالمحتوى التالي:

تعليق #pragma (lib، "../Debug/dlltest.lib")

# تضمين "dlltest.h"

عرض ("مرحبًا") ؛

نظام ("وقفة") ؛

لبدء تشغيل البرنامج بنجاح ، كل ما تبقى هو التأكد من توفر DLL المقابل. عند بدء تشغيل البرنامج ، سيبحث نظام التشغيل عن جميع ملفات المكتبة المطلوبة في المجلد الذي تم إطلاق البرنامج منه ، وكذلك في مسارات النظام المحددة بواسطة متغير البيئة PATH. وفقًا لذلك ، يجب أن يكون ملف DLL للمكتبة المبنية إما في نفس المجلد مع الملف القابل للتنفيذ لبرنامج الاستدعاء ، أو في أحد المجلدات المحددة في PATH.