102.3 - مدیریت کتابخانههای مشترک (Shared Libraries)¶
اهداف یادگیری¶
در این فصل با موارد زیر آشنا میشوید:
- شناسایی کتابخانههای مشترک
- شناسایی محلهای معمول کتابخانههای سیستم
- بارگذاری کتابخانههای مشترک
کلیدواژهها¶
ldd, ldconfig, /etc/ld.so.conf, LD_LIBRARY_PATH
Linking (لینک کردن)¶
هنگام نوشتن برنامهها، از کتابخانهها استفاده میکنیم. برای مثال، اگر نیاز به خواندن متن از ورودی استاندارد دارید، باید یک کتابخانه که این را فراهم میکند لینک کنید. لینک کردن دو شکل دارد:
- Static Linking (لینک ایستا): کتابخانهها را به برنامه اجرایی خود اضافه میکنید. در این روش، حجم برنامه بزرگ است زیرا همه کتابخانههای مورد نیاز را دارد. یک مزیت خوب این است که برنامه میتواند بدون وابستگی به برنامهها/کتابخانههای دیگر اجرا شود.
- Dynamic Linking (لینک پویا): فقط اعلام میکنید که برنامه به کتابخانههای خاصی نیاز دارد. این روش برنامه را کوچکتر میکند اما باید کتابخانهها را جداگانه نصب کنید. این برنامهها را امنتر میکند (زیرا کتابخانهها میتوانند بهصورت مرکزی بهروزرسانی شوند، و پیشرفتهتر هر بهبود در کتابخانه کل برنامه را بهبود میبخشد)، و کوچکتر.
کتابخانههای پویا لینوکس نامهایی مانند libLIBNAME.so.VERSION دارند و در مکانهایی مانند /lib*/ و /usr/lib*/ قرار دارند. در ویندوز، آنها را Dynamic Linked Libraries (DLLs) مینامیم.
نکته
Dynamic linking همچنین shared libraries نامیده میشود زیرا همه برنامهها یک کتابخانه مشترک را که جداگانه نصب شده است به اشتراک میگذارند.
کتابخانههای مورد نیاز من چیست¶
کتابخانههای مربوط به ابزارهای سیستم در /lib و /lib64 (برای کتابخانههای 32بیتی و 64بیتی) نصب میشوند و کتابخانههای نصب شده توسط نرمافزارهای دیگر در /usr/lib و /usr/lib64 قرار دارند.
ldd¶
دستور ldd به شما کمک میکند پیدا کنید:
- آیا برنامه به صورت پویا یا ایستا لینک شده است
- کتابخانههای مورد نیاز برنامه چیست
بیایید به دو فایل نگاه کنیم:
[jadi@fedora ~]$ ldd /sbin/ldconfig
not a dynamic executable
[jadi@fedora ~]$ ldd /bin/ls
linux-vdso.so.1 (0x00007ffdd53eb000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f5cbc7b0000)
libcap.so.2 => /lib64/libcap.so.2 (0x00007f5cbc7a6000)
libc.so.6 => /lib64/libc.so.6 (0x00007f5cbc5a5000)
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 (0x00007f5cbc50f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5cbc813000)
همانطور که میبینید، ldd به ما میگوید که /sbin/ldconfig به صورت پویا لینک نشده است اما کتابخانههای مورد نیاز /bin/ls را نشان میدهد.
Symbolic links برای کتابخانهها¶
اگر در حال نوشتن برنامهای هستید و از توابع udev استفاده میکنید، از کتابخانهای به نام libudev.so.1 درخواست خواهید کرد. اما یک توزیع لینوکس ممکن است نسخه کتابخانه udev خود را libudev.so.1.4.0 بنامد. چگونه این مشکل را حل کنیم؟ پاسخ symbolic links است؛ درباره آنها در فصلهای بعدی بیشتر یاد خواهید گرفت اما به اختصار، یک نام نمادین نام جدیدی برای همان فایل است.
ابتدا محل libudev.so.1 روی سیستم خود را پیدا میکنم:
سپس فایل را چک میکنم:
# ls -la /lib/i386-linux-gnu/libudev.so.1
lrwxrwxrwx 1 root root 16 Nov 13 23:05 /lib/i386-linux-gnu/libudev.so.1 -> libudev.so.1.4.0
همانطور که میبینید، این یک symbolic link است که به نسخه libudev نصب شده من (1.4.0) اشاره میکند بنابراین حتی اگر نرمافزاری بگوید نیاز به libudev.so.1 دارد، سیستم من از libudev.so.1.4.0 استفاده خواهد کرد.
پیکربندی و cache کتابخانههای پویا¶
مانند اکثر ابزارهای دیگر لینوکس، linking پویا نیز با یک فایل پیکربندی متنی پیکربندی میشود. این در /etc/ld.so.conf قرار دارد. روی یک سیستم Ubuntu فقط به فایلهای پیکربندی دیگر در /etc/ld.so.conf.d/ اشاره میکند اما همه آن خطوط میتوانند در فایل اصلی نیز گنجانده شوند:
[jadi@fedora ~]$ cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
[jadi@fedora ~]$ ls /etc/ld.so.conf.d/
llvm13-x86_64.conf pipewire-jack-x86_64.conf
[jadi@fedora ~]$ cat /etc/ld.so.conf.d/llvm13-x86_64.conf
/usr/lib64/llvm13/lib
دستور ldconfig همه این فایلها را پردازش میکند تا بارگذاری کتابخانهها سریعتر شود. این دستور ld.so.cache را ایجاد میکند تا فایلهایی که باید به صورت پویا بارگذاری و لینک شوند را پیدا کند.
نکته
اگر ld.so.conf (یا زیرشاخهها) را تغییر دهید، باید ldconfig را اجرا کنید. با سوئیچ -v امتحان کنید تا پیشرفت/داده را ببینید.
برای پایان این بخش، بیایید ldconfig را با سوئیچ -p اجرا کنیم تا ببینیم چه چیزی در ld.so.cache ذخیره شده است:
[jadi@fedora ~]$ ldconfig -p | head
1373 libs found in cache `/etc/ld.so.cache'
libzstd.so.1 (libc6,x86-64) => /lib64/libzstd.so.1
libzmf-0.0.so.0 (libc6,x86-64) => /lib64/libzmf-0.0.so.0
libzip.so.5 (libc6,x86-64) => /lib64/libzip.so.5
libzhuyin.so.13 (libc6,x86-64) => /lib64/libzhuyin.so.13
libzck.so.1 (libc6,x86-64) => /lib64/libzck.so.1
libz.so.1 (libc6,x86-64) => /lib64/libz.so.1
libyui.so.15 (libc6,x86-64) => /lib64/libyui.so.15
libyui-mga.so.15 (libc6,x86-64) => /lib64/libyui-mga.so.15
libyelp.so.0 (libc6,x86-64) => /lib64/libyelp.so.0
همانطور که میبینید، این فایل به کرنل میگوید که اگر کسی از libzstd.so.1 درخواست کند، فایل /lib64/libzstd.so.1 باید بارگذاری و استفاده شود.
سیستم عامل کتابخانههای پویا را از کجا پیدا میکند¶
وقتی برنامهای نیاز به یک shared library دارد، سیستم فایلها را به این ترتیب جستجو میکند:
- متغیر محیطی LD_LIBRARY_PATH
- PATH برنامه
/etc/ld.so.conf(که ممکن است فایلهای بیشتری از/etc/ld.so.conf.d/در ابتدای یا انتهای خود بارگذاری کند)/lib/,/lib64/,/usr/lib/,/usr/lib64/
در برخی موارد، ممکن است نیاز به override کردن کتابخانههای پیشفرض سیستم داشته باشید. برخی مثالها:
- اجرای نرمافزار قدیمی که نیاز به نسخه قدیمی کتابخانه دارد.
- توسعه یک shared library و میخواهید آن را بدون نصب تست کنید
- اجرای برنامه خاصی (مثلاً از opt) که نیاز به دسترسی به کتابخانههای خود دارد
در این موارد، میتوانید متغیر محیطی LD_LIBRARY_PATH را به کتابخانه مورد نیاز خود اشاره دهید و سپس برنامه خود را اجرا کنید. یک لیست جدا شده با کولون (:) از دایرکتوریها به برنامه شما میگوید کجا برای کتابخانههای مورد نیاز جستجو کند قبل از چک کردن کتابخانهها در /etc/ld.so.cache.
برای مثال، اگر این دستور را بدهید:
تمرینها¶
تمرین 1: بررسی وابستگیهای برنامه¶
تمرین 2: بررسی cache کتابخانهها¶
تمرین 3: استفاده از LD_LIBRARY_PATH¶
نکات کلیدی برای آزمون
- تفاوت static و dynamic linking
- استفاده از ldd برای بررسی وابستگیها
- نقش ldconfig و ld.so.cache
- ترتیب جستجوی کتابخانهها
- استفاده از LD_LIBRARY_PATH
مثال:
ldd /sbin/ldconfig
# not a dynamic executable
ldd /bin/ls
libselinux.so.1 => /lib64/libselinux.so.1
libc.so.6 => /lib64/libc.so.6
...
لینکهای نمادین (Symbolic Links)¶
گاهی نسخههای مختلف یک کتابخانه با نامهای متفاوت وجود دارند. برای سازگاری، از لینکهای نمادین استفاده میشود.
مثال:
ls -la /lib/i386-linux-gnu/libudev.so.1
lrwxrwxrwx 1 root root 16 Nov 13 23:05 libudev.so.1 -> libudev.so.1.4.0
نکته
حتی اگر برنامهای به libudev.so.1 نیاز داشته باشد، سیستم نسخه نصبشده (libudev.so.1.4.0) را استفاده میکند.
پیکربندی و کش کتابخانهها¶
- فایل پیکربندی:
/etc/ld.so.conf - در اوبونتو: شامل فایلهای
/etc/ld.so.conf.d/
مثال:
دستور ldconfig¶
- پردازش فایلهای پیکربندی
- ایجاد کش (
ld.so.cache) برای دسترسی سریعتر به کتابخانهها
مشاهده کش:
هشدار
پس از تغییر فایلهای پیکربندی باید ldconfig اجرا شود تا کش بهروزرسانی شود.
مسیر جستجوی کتابخانهها¶
ترتیب جستجو:
- متغیر محیطی
LD_LIBRARY_PATH - مسیر برنامه
- فایل
/etc/ld.so.confو زیرشاخههای آن - مسیرهای پیشفرض:
/lib,/lib64,/usr/lib,/usr/lib64
مثال استفاده از LD_LIBRARY_PATH:
کاربرد
این روش برای تست نسخههای قدیمی یا توسعه کتابخانهها بدون نصب دائمی استفاده میشود.
بارگذاری پویا (Dynamic Loading)¶
برنامهها توسط Dynamic Loader اجرا میشوند (معمولاً ld-linux).
یافتن Loader:
اجرای برنامه با Loader:
ترفند
حتی اگر فایل اجرایی بیت اجرا (x) نداشته باشد، میتوانید آن را با ld-linux اجرا کنید!
تمرینهای عملی¶
تمرین 1: بررسی وابستگیها¶
تمرین 2: مشاهده کش کتابخانهها¶
تمرین 3: تغییر مسیر کتابخانهها¶
تمرین 4: اجرای برنامه با Loader¶
خلاصه¶
در این فصل یاد گرفتیم:
- تفاوت لینک ایستا و پویا
- محل ذخیره کتابخانههای سیستمی و نرمافزاری
- استفاده از دستور
lddبرای بررسی وابستگیها - نقش لینکهای نمادین در سازگاری نسخهها
- پیکربندی و کش کتابخانهها با
ld.so.confوldconfig - ترتیب جستجوی کتابخانهها در سیستم
- استفاده از
LD_LIBRARY_PATHبرای override کتابخانهها - اجرای برنامهها با Dynamic Loader (
ld-linux)
نکات کلیدی برای آزمون
- تفاوت Static و Dynamic Linking
- مسیرهای
/lib,/usr/libبرای کتابخانهها - دستورهای
lddوldconfig - نقش
LD_LIBRARY_PATH - مفهوم Symbolic Links برای کتابخانهها