



لغة C إنتاج واستخدام مكتبة الارتباط الثابت ومكتبة الارتباط الديناميكي
. مقدمة موجزة عن مكتبة الوظائف
ببساطة ، مكتبة الوظائف هي مجموعة من الوظائف المعيارية المكتوبة مسبقًا ، والتي يمكن استخدامها من قبل المبرمجين الآخرين. في البداية ، لم تكن هناك مكتبة وظائف ، وكان على كل مبرمج كتابة برنامج من الصفر ، وبمرور الوقت ، تراكمت بعض مكتبات الوظائف عالية الجودة بشكل تدريجي. في وقت لاحق ، جمعت المنظمات مكتبات وظيفية مختلفة معًا ، ومعايرتها وفرزها ، وشكلت مكتبة وظائف موحدة ، وهي مكتبة الوظائف القياسية الحالية ، مثلglibc
1.1 توفير شكل مكتبة الوظائف: مكتبة الارتباط الديناميكي ومكتبة الارتباط الثابتة
تم تنفيذ مشاركة الوظائف السابقة في شكل كود المصدر. ببطء ، شكل اتجاه مشاركة كود المصدر مجتمعنا الحالي مفتوح المصدر ، ولا يمكن إطلاق مكتبات الوظائف في شكل تجاري. تحتاج الشركات التجارية إلى السماح للآخرين بالدفع مقابل استخدام مكتبات الوظائف الخاصة بهم ، لكن لا يمكنهم تزويد العملاء برمز المصدر. في هذا الوقت ، تظهر مكتبات الارتباط الثابتة ومكتبات الارتباط الديناميكي.
1.1.1 مكتبة الارتباط الثابتة
gccيستخدم البرنامج المترجم والمرتبط مكتبات ديناميكية بشكل افتراضي. للربط الثابت ، تحتاج إلى استخدام صريح-staticلفرض ربط ثابت. يجب الانتباه إلى استخدام وظائف المكتبة:
إذا استخدمنا مكتبة وظائف الرياضياتsqrtوظيفة:
#include <stdio.h> #include <math.h> int main(void) { double x = 16.0; double y = sqrt(x); printf("y = %lf\n", y); return 0; }
سنجد أنه تم الإبلاغ عن خطأ عند الارتباط! التقرير صحيح'sqrt'مرجع غير محدد ، أي أن الدالة sqrt لها تصريح (بتنسيقmath.hفي) هناك مراجع (فيmath.c) ، ولكن لا يوجد تعريف ، فلا يمكن للرابط العثور على جسم الوظيفة. لماذا هو كذلك؟ نظرًا لوجود العديد من وظائف المكتبة ، يستغرق الرابط وقتًا طويلاً للبحث في دليل وظيفة المكتبة. من أجل تحسين السرعة ، يبحث الرابط فقط عن عدد قليل من المكتبات الأكثر استخدامًا بشكل افتراضي.إذا تم استدعاء الوظائف في بعض المكتبات غير الشائعة ، يحتاج المبرمج إلى إعطاء اسم المكتبة بشكل صريح ليتم توسيعه عند الارتباط.
عند الارتباط ، يمكنك استخدام -lxxx لتوجيه الرابط للعثور على وظائف في libxxx.a (ثابت) أو libxxx.so (متحرك)
يمكننا أن نرى أن ملف-lmبعد ذلك ، تم ربطه بنجاح. وفي نفس الوقت ، يمكننا أيضًا أن نرى أن حجم الملف القابل للتنفيذ الذي تم إنشاؤه بواسطة ارتباط ثابت لا يماثل حجم الارتباط الديناميكي! ! !
ثانيًا ، قم بإنشاء واستخدام مكتبة ارتباط ثابتة
2.1 الإنتاج
قم بإنشاء ملفملف المصدرمعملف رأس .hإلى جانبMakefile:
touch mylib1.c mylib1.h Makefile
بعد ذلك ، قم فقط بالتجميع بدون ارتباط وإنشاء.oملف ؛ ثم استخدمarيتم حزم الأدوات في.aأرشفة الملفات: عند الحزم ، انتبه إلى أن اسم المكتبة لا يكون عشوائيًا بشكل عامlib + اسم المكتبة، لاحقة.aيشير إلى أنه ملف مكتبة مرتبط بشكل ثابت. متجانسMakefileالمقطع هو كما يلي:
lib: gcc -c mylib1.c -o mylib1.o ar -rc libmylib1.a mylib1.o
2.2 الإصدار
الافراج عن ما يسمى.aالملفات و.hيتم وضع الملفات في مجلد منفصل لاستخدامها لاحقًا. كما تظهر الصورة
3.3 الاستخدام
نحن نبني منطقتنا في المجلد المنشور.cملف ، يمكنك استدعاء وظائف المكتبة مباشرة!
touch main.c Makefile
#include "mylib1.h" int main(void) { myprint(); return 0; }
all: gcc main.c -o main.elf -lmylib1
سنجد أنه لا يزال يتعذر ربط هذا بشكل صحيح ، وستظهر رسالة الخطأ التالية:/ usr / bin / ld: لا يمكن العثور على -lmylib1، نعلم من رسالة الخطأ أن الرابط يبحث فقط عن مكتبة الارتباط في الدليل المحدد بواسطة النظام افتراضيًا. لذلك تحتاج إلى استخدام -L لتحديد عنوان المكتبة ، نقوم بتعديل ملف Makefile على النحو التالي:
all: gcc main.c -o main.elf -lmylib1 -L.
ثالثًا ، قم بإنشاء واستخدام مكتبة الارتباط الديناميكي
3.1 الإنتاج والإصدار
يشبه إنتاج مكتبة الارتباط الديناميكي فكرة المكتبة الثابتة ، لكن اسم اللاحقة هو.so(windowsالتالي هوdll)،بواسطةgccلحزم بدلا من ذلكar،متجانسMakefileكما يلي:
lib: gcc -c mylib2.c -o mylib2.o -fPIC gcc mylib2.o -o libmylib2.so -shared
انشر عند النشرlibxxx.soمعxxx.hنعم ، لن أكررها هنا
3.2 الاستخدام
من خلال تجربة المكتبات الثابتة ، نعلم أن تعليمات التجميع والربط يجب أن تكون:
all: gcc main.c -o main.elf -lmylib2 -L.
ولكن حدث خطأ أثناء التشغيل وتم الإبلاغ عن رسالة خطأ:error while loading shared libraries: libmylib2.so: cannot open shared object file: No such file or directory
هذا بسببيجب تحميل مكتبة الارتباط الديناميكي عند تشغيلها(وجدت بيئة وقت التشغيل الارتباط الديناميكي عند تنفيذ البرنامجlibxxx. so، لذلك سوف تذهبالدليل الثابت/usr/libتحميل libxxx، إذا فشل التحميل ، ستتم طباعة رسالة الخطأ أعلاه. )
المحلول
export LD_LIBRARY_PATH=D_LIBRARY_PATH:\ /mnt/hgfs/VMShare/C/6.PreprocessFunction/funclib/dynamiclib/publib
يمكننا أن نجد أنه يمكن تشغيل البرنامج مباشرة بعد استيراد متغيرات البيئة
3.3 ldd الأمر
lddيمكن للأمر تحليل المكتبات المشتركة التي يستخدمها البرنامج قبل تنفيذ برنامج يستخدم المكتبات المشتركة ، والتحقق مما إذا كان يمكن العثور على هذه المكتبات المشتركة ، مثل المثال أعلاه بعد إضافة المكتبة المشتركة ، وكلها مستخدمة.soيمكن حلها إلى عنوان
إذا قمنا بتعيين متغير البيئة على فارغ:
export LD_LIBRARY_PATH=
يمكننا أن نرى main.elfمرتبطlibmylib2.soفيnot foundالحالة ، لا يمكن تنفيذها بشكل صحيح
. مقدمة موجزة عن مكتبة الوظائف
ببساطة ، مكتبة الوظائف هي مجموعة من الوظائف المعيارية المكتوبة مسبقًا ، والتي يمكن استخدامها من قبل المبرمجين الآخرين. في البداية ، لم تكن هناك مكتبة وظائف ، وكان على كل مبرمج كتابة برنامج من الصفر ، وبمرور الوقت ، تراكمت بعض مكتبات الوظائف عالية الجودة بشكل تدريجي. في وقت لاحق ، جمعت المنظمات مكتبات وظيفية مختلفة معًا ، ومعايرتها وفرزها ، وشكلت مكتبة وظائف موحدة ، وهي مكتبة الوظائف القياسية الحالية ، مثلglibc
1.1 توفير شكل مكتبة الوظائف: مكتبة الارتباط الديناميكي ومكتبة الارتباط الثابتة
تم تنفيذ مشاركة الوظائف السابقة في شكل كود المصدر. ببطء ، شكل اتجاه مشاركة كود المصدر مجتمعنا الحالي مفتوح المصدر ، ولا يمكن إطلاق مكتبات الوظائف في شكل تجاري. تحتاج الشركات التجارية إلى السماح للآخرين بالدفع مقابل استخدام مكتبات الوظائف الخاصة بهم ، لكن لا يمكنهم تزويد العملاء برمز المصدر. في هذا الوقت ، تظهر مكتبات الارتباط الثابتة ومكتبات الارتباط الديناميكي.
1.1.1 مكتبة الارتباط الثابتة
- تشكل الشركات التجارية الكود المصدري لمكتبة الوظائف بعد التجميع فقط وعدم الربط.oالملف الهدف ، ثم استخدمarأداة سوف.oملف في.aملف الأرشيف ، هذا.aيسمى ملف الأرشيف بملف مكتبة الارتباط الثابت. عن طريق النشر.aملفات المكتبة و.hملفات الرأس لتوفير مكتبات ثابتة للعملاء لاستخدامها ؛
- حصل العميل.aمع.hبعد الملف ، مرر.hيعرف ملف الرأس النموذج الأولي لوظيفة المكتبة في المكتبة ، ثم بمفردها.cيتم استدعاء ملفات المكتبة هذه مباشرة في الملف ، وسوف ينتقل الرابط إلى.aأخرج الوظيفة المترجمة للوظيفة المطلوبة في الملف.oترتبط مقاطع الكود الثنائي لتشكيل البرنامج القابل للتنفيذ النهائي.
- تظهر المكتبة الديناميكية بعد مكتبة الارتباط الثابتة وتكون أكثر كفاءة.في الوقت الحاضر ، يتم استخدام المكتبات الديناميكية بشكل عام. لقد قامت المكتبة الثابتة بالفعل بربط مقطع الكود الخاص بالوظيفة في المكتبة المسماة بالبرنامج التنفيذي النهائي عندما يقوم المستخدم بربط برنامجه القابل للتنفيذ. الميزة هي أنه يمكن تنفيذه في كل مكان ، ولكن العيب هو أنه يأخذ الكثير الفراغ. خاصة عندما تستخدم تطبيقات متعددة نفس وظيفة المكتبة ، سيكون لكل برنامج نهائي قابل للتنفيذ مقطع رمز لوظيفة المكتبة هذه. عندما يتم تشغيل هذه التطبيقات في الذاكرة في نفس الوقت ، هناك بالفعل أجزاء متعددة من التعليمات البرمجية لوظيفة المكتبة هذه في الذاكرة ، والتي تتكرر بالكامل.
- ومكتبة الارتباط الديناميكي نفسها لا تربط مقطع الكود الخاص بوظيفة المكتبة بالبرنامج القابل للتنفيذ ، تمامًا كعلامة. ثم عندما يتم تنفيذ التطبيق في الذاكرة ، عندما تجد بيئة وقت التشغيل أنها تستدعي وظيفة مكتبة في مكتبة ديناميكية ، فإنها ستحمّل المكتبة الديناميكية في الذاكرة ، ثم بغض النظر عن عدد التطبيقات الموجودة لاستدعاء المكتبة فيها المستقبل ستنتقل الوظيفة إلى المكان الذي تم تحميلها فيه لأول مرة للتنفيذ (لم يتم تحميلها بشكل متكرر).
gccيستخدم البرنامج المترجم والمرتبط مكتبات ديناميكية بشكل افتراضي. للربط الثابت ، تحتاج إلى استخدام صريح-staticلفرض ربط ثابت. يجب الانتباه إلى استخدام وظائف المكتبة:
- قم بتضمين ملف الرأس المقابل
- انتبه إلى النموذج الأولي للوظيفة عند استدعاء وظائف المكتبة
- تحتاج بعض وظائف المكتبة إلى استخدام إضافي عند الارتباط-lxxxلتحديد الارتباط
- إذا لم تكن مكتبة نظام ، فاحرص على استخدامها-Lحدد عنوان المكتبة
- يتم تحديد وظيفة العملية الحسابية الحقيقية في:/usr/include/x86_64-linux-gnu/bits/mathcalls.h
- عند استخدام وظائف مكتبة الرياضيات ، ما عليك سوى تضمينهاmath.hعلبة
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10

سنجد أنه تم الإبلاغ عن خطأ عند الارتباط! التقرير صحيح'sqrt'مرجع غير محدد ، أي أن الدالة sqrt لها تصريح (بتنسيقmath.hفي) هناك مراجع (فيmath.c) ، ولكن لا يوجد تعريف ، فلا يمكن للرابط العثور على جسم الوظيفة. لماذا هو كذلك؟ نظرًا لوجود العديد من وظائف المكتبة ، يستغرق الرابط وقتًا طويلاً للبحث في دليل وظيفة المكتبة. من أجل تحسين السرعة ، يبحث الرابط فقط عن عدد قليل من المكتبات الأكثر استخدامًا بشكل افتراضي.إذا تم استدعاء الوظائف في بعض المكتبات غير الشائعة ، يحتاج المبرمج إلى إعطاء اسم المكتبة بشكل صريح ليتم توسيعه عند الارتباط.
عند الارتباط ، يمكنك استخدام -lxxx لتوجيه الرابط للعثور على وظائف في libxxx.a (ثابت) أو libxxx.so (متحرك)

يمكننا أن نرى أن ملف-lmبعد ذلك ، تم ربطه بنجاح. وفي نفس الوقت ، يمكننا أيضًا أن نرى أن حجم الملف القابل للتنفيذ الذي تم إنشاؤه بواسطة ارتباط ثابت لا يماثل حجم الارتباط الديناميكي! ! !
ثانيًا ، قم بإنشاء واستخدام مكتبة ارتباط ثابتة
2.1 الإنتاج
قم بإنشاء ملفملف المصدرمعملف رأس .hإلى جانبMakefile:
touch mylib1.c mylib1.h Makefile
- 1

بعد ذلك ، قم فقط بالتجميع بدون ارتباط وإنشاء.oملف ؛ ثم استخدمarيتم حزم الأدوات في.aأرشفة الملفات: عند الحزم ، انتبه إلى أن اسم المكتبة لا يكون عشوائيًا بشكل عامlib + اسم المكتبة، لاحقة.aيشير إلى أنه ملف مكتبة مرتبط بشكل ثابت. متجانسMakefileالمقطع هو كما يلي:
lib: gcc -c mylib1.c -o mylib1.o ar -rc libmylib1.a mylib1.o
- 1
- 2
- 3

2.2 الإصدار
الافراج عن ما يسمى.aالملفات و.hيتم وضع الملفات في مجلد منفصل لاستخدامها لاحقًا. كما تظهر الصورة

3.3 الاستخدام
نحن نبني منطقتنا في المجلد المنشور.cملف ، يمكنك استدعاء وظائف المكتبة مباشرة!
touch main.c Makefile
- 1
#include "mylib1.h" int main(void) { myprint(); return 0; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
all: gcc main.c -o main.elf -lmylib1
- 1
- 2

سنجد أنه لا يزال يتعذر ربط هذا بشكل صحيح ، وستظهر رسالة الخطأ التالية:/ usr / bin / ld: لا يمكن العثور على -lmylib1، نعلم من رسالة الخطأ أن الرابط يبحث فقط عن مكتبة الارتباط في الدليل المحدد بواسطة النظام افتراضيًا. لذلك تحتاج إلى استخدام -L لتحديد عنوان المكتبة ، نقوم بتعديل ملف Makefile على النحو التالي:
all: gcc main.c -o main.elf -lmylib1 -L.
- 1
- 2

ثالثًا ، قم بإنشاء واستخدام مكتبة الارتباط الديناميكي
3.1 الإنتاج والإصدار
يشبه إنتاج مكتبة الارتباط الديناميكي فكرة المكتبة الثابتة ، لكن اسم اللاحقة هو.so(windowsالتالي هوdll)،بواسطةgccلحزم بدلا من ذلكar،متجانسMakefileكما يلي:
lib: gcc -c mylib2.c -o mylib2.o -fPIC gcc mylib2.o -o libmylib2.so -shared
- 1
- 2
- 3
- -fPICإنه رمز مستقل عن الموضع ، يعمل في مرحلة التجميع ويخبر المترجم بإنشاء رمز مستقل عن الموضع(Position-Independent Code). أي أنه لا يوجد عنوان مطلق في الكود الذي تم إنشاؤه ، ويتم استخدام جميع العناوين النسبية ، ويمكن تنفيذه بشكل صحيح عندما يتم تحميله بواسطة المُحمل إلى أي مكان في الذاكرة. هذا هو بالضبط ما تتطلبه المكتبة المشتركة. عندما يتم تحميل المكتبة المشتركة ، لا يتم إصلاح موقعها في الذاكرة.
- -sharedوهي مرتبطة حسب المكتبة المشتركة
3.2 الاستخدام
من خلال تجربة المكتبات الثابتة ، نعلم أن تعليمات التجميع والربط يجب أن تكون:
all: gcc main.c -o main.elf -lmylib2 -L.
- 1
- 2

ولكن حدث خطأ أثناء التشغيل وتم الإبلاغ عن رسالة خطأ:error while loading shared libraries: libmylib2.so: cannot open shared object file: No such file or directory
هذا بسببيجب تحميل مكتبة الارتباط الديناميكي عند تشغيلها(وجدت بيئة وقت التشغيل الارتباط الديناميكي عند تنفيذ البرنامجlibxxx. so، لذلك سوف تذهبالدليل الثابت/usr/libتحميل libxxx، إذا فشل التحميل ، ستتم طباعة رسالة الخطأ أعلاه. )
المحلول
- ضع libaston.so في الدليل الثابت / usr / lib
- 1
- استخدم متغير البيئة LD_LIBRARY_PATH
export LD_LIBRARY_PATH=D_LIBRARY_PATH:\ /mnt/hgfs/VMShare/C/6.PreprocessFunction/funclib/dynamiclib/publib
- 1
- 2

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

إذا قمنا بتعيين متغير البيئة على فارغ:
export LD_LIBRARY_PATH=
- 1

يمكننا أن نرى main.elfمرتبطlibmylib2.soفيnot foundالحالة ، لا يمكن تنفيذها بشكل صحيح