لف إصدارات مختلفة من المكتبة الثابتة في المكتبات الديناميكية

StackOverflow https://stackoverflow.com/questions/2801666

  •  25-09-2019
  •  | 
  •  

سؤال

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

أنا أستخدم MSVC2005 على WinXP ، الهدف الثانوي هو أن أكون مستعدًا للتبديل إلى Linux و GCC.

منذ كلا الإصدارين من libsomething يستخدمون نفس الرموز ، وربطها في كل من بلدي القابلة للتنفيذ أمر غير وارد لأن رموز كلا الإصدارين سوف تصطدم في كل مكان في الوقت.

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

توصلت إلى فكرة إنشاء غلاف مكتبة ديناميكي لكل إصدار من libsomething وربطها في وقت التشغيل اعتمادًا على بعض ملفات التكوين. مع MSCV ، هذا يعني السير في طريق الاستخدام LoadLibrary(), GetProcAddress(), ، وما إلى ذلك ، بينما على Linux يجب أن أستخدمه dlopen() و dlsym().

أنا أفهم ذلك باستخدام libtool (بمعنى آخر، libtldl) يلف هذا الاعتماد على النظام الأساسي لاستخدام المكتبات المشتركة. هل هذا طريق مناسب لمتابعة؟ هل هناك طرق أفضل (أو ، على الأقل ، مختلفة)؟ هل بدائل ل libtldl موجود كمصدر مفتوح؟

هل كانت مفيدة؟

المحلول

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

يمكنك كتابة برنامج نصي مصمم خصيصًا لمشروعك أو استخدامه Implib.so أداة:

# This will generate mylib.so.init.c and mylib.so.tramp.S
# which implement stubs. These need to be linked to your
# executable.
$ implib-gen.py mylib.so

Implib.so هو ATM Linux فقط ولكن يجب أن تكون قابلة للتكيف بسهولة مع النوافذ.

نصائح أخرى

أعلم أنك قلت إنه لا يمكنك استخدام اثنين من المديرين التنفيذيين بسبب قرار تنفيذها ، لكن لم تستطع أن تستهلك exec ذهابًا وإيابًا بين التنفيذيين اعتمادًا على الإصدار المحدد في التكوين؟

على Linux ، سيكون من الأسهل عليك ربط المكتبة المشتركة واستخدام Symlinks لتصحيح الإصدار - IMO أسهل بكثير من استخدام dlopen() + dlsym().

وبالتالي ، يمكنك إنشاء مكتبات مشتركة للإصدارات القديمة والجديدة من مكتبتك:

g++ -shared -o libshared.so.1.1 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.old -Wl,-no-whole-archive

و

g++ -shared -o libshared.so.1.2 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.new -Wl,-no-whole-archive

قم بإنشاء Symlinks:

ln -s libshared.so.1.1 libshared.so.1
ln -s libshared.so.1 libshared.so

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

g++ -o myapp myapp.cpp -L. -lshared

منذ مكتبة مشتركة SONAME هو libshared.so.1 سيعتمد تطبيقك عليه وسيبحث libshared.so.1 في مسارات من /etc/ld.so.conf أو LD_LIBRARY_PATH

قبل تشغيل التطبيق الخاص بك ، يمكنك تعيين ملف libshared.so.1 Symlink للإشارة إلى libshared.so.1.2 أو libshared.so.1.1.


معلومات قليلة حول خيارات الارتباط المستخدمة هنا:

-
لكل أرشيف مذكور في سطر الأوامر بعد الخيار-المختلط ، قم بتضمين كل ملف كائن في الأرشيف في الرابط ، بدلاً من البحث عن أرشيف ملفات الكائن المطلوبة. يتم استخدام هذا عادة لتحويل ملف الأرشيف إلى مكتبة مشتركة ، مما يجبر كل كائن على تضمينه في المكتبة المشتركة الناتجة. يمكن استخدام هذا الخيار أكثر من مرة.
ملاحظتان عند استخدام هذا الخيار من GCC: أولاً ، لا تعرف GCC عن هذا الخيار ، لذلك يجب عليك استخدام -WL ، -خطي. ثانياً ، لا تنس استخدام -wl ، -no-whole-archive بعد قائمة المحفوظات الخاصة بك ، لأن GCC ستضيف قائمة الأرشيف الخاصة بك إلى الرابط الخاص بك وقد لا ترغب في أن تؤثر هذه العلامة على هذه العلامة أيضًا.

-soname = الاسم
عند إنشاء كائن مشترك ELF ، قم بتعيين حقل DT_Soname الداخلي على الاسم المحدد. عندما يتم ربط قابلة للتنفيذ مع كائن مشترك يحتوي على حقل DT_Soname ، عند تشغيل القابل للتنفيذ ، سيحاول الرابط الديناميكي تحميل الكائن المشترك المحدد بواسطة حقل DT_SONAME بدلاً من استخدام اسم الملف المعطى إلى الرابط.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top