آموزش LPIC1 – بخش چهارم

Shared Library

برنامه نویسی در لینوکس به این شکل است که یک مجموعه ی نسبتا کامل از Library ها درون دایرکتوری lib/ قرار دارد و هر برنامه از این Library ها جهت اجرا و انجام دستورات استفاده می نماید. مثلا در برنامه ای که نیاز به خواندن Keyboard دارد، بخش خواندن Keyboard آن مجدد از نو نوشته نمیشود و در عوض از Library ای که به همین منظور در دایرکتوری lib/ وجود دارد استفاده میگردد. یکی از دلایل حجیم بودن برنامه های ویندوزی عدم استفاده از Library ها بدین صورت می باشد. مورد مثبت این قضیه این است که به طور مثال اگر ما در Library تایپ از زبان فارسی پشتیبانی کنیم و این زبان را به این Library اضافه کنیم، تمام برنامه هایی که از تایپ استفاده مینمایند فارسی را پشتیبانی میکنند. تنها کاری که ما لازم است انجام دهیم بهروز رسانی این Library است.

 

Library های استاتیک

اگر به هنگام برنامه نویسی در انتهای پروسه تمامی Library هایی که در برنامه از آن ها استفاده نموده ایم را در فایل قابل اجرای برنامه قرار دهیم، مفهموم لایبری استاتیک را پیاده سازی نموده ایم. در این صورت هرچیزی که برنامه برای اجرا نیاز دارد در خود برنامه وجود دارد. حجم برنامه افزایش یافته و معمولا برنامه های ویندوز به این صورت هستند. مانند برنامه ی photoshop در ویندوز.

 

Library های داینامیک

اگر کتابخانه ها خارج از برنامه و در سیستم عامل قرار گرفته باشد Library ها به صورت داینامیک پیاده سازی شده اند. معمولا برنامه های لینوکس به این صورتند. در این صورت به هنگام نصب میبایست چک گردد که برنامه به چه کتابخانه هایی نیاز دارد. هم yum هم apt-get قابلیت هایی دارند برای درک Dependency و در صورت نیاز برنامه هایی که قصد نصب آنها را داریم به کتابخانه ها، آنها را هم به عنوان Dependency نصب مینمایند. این روش بسیار امن تر است Library ها به روز میشوند و در نتیجه تمامی برنامه هایی که از آن Library استفاده میکنند امن میگردند.

 

کتابخانه ها در lib/ و usr/lib/ قرار میگیرند. همچنین در صورتی که از سیستم عامل 64 بیتی استفاده کنیم دایرکتوری هایی با نام lib64/ و usr/lib64/ نیز وجود خواهند داشت که کتابخانه های 64 بیتی در آن قرار میگیرند. کتابخانه ها در این 4 پوشه نصب خواهند شد.

 

چگونه بفهمیم برنامه های ما به چه کتابخانه هایی نیاز دارند؟

به طور مثال برنامه ی ldconfig را در نظر بگیرید. میخواهیم ببینیم این برنامه از چه کتابخانه هایی استفاده مینماید. در ابتدا باید ببینیم مسیر فایل اجرایی برنامه کجاست. بدین منظور از دستور زیر استفاده میکنیم.

root@regux:~# whereis ldconfig
ldconfig: /sbin/ldconfig /usr/share/man/man8/ldconfig.8.gz

همانطور که مشاهده میکنید مسیر فایل برنامه sbin/ldconfig/ است. برای مشاهده ی Library ها از دستور ldd استفاده مینماییم.

root@regux:~# ldd /sbin/ldconfig
 not a dynamic executable

این پیغام نشان میدهد که این برنامه از کتابخانه های استاتیک استفاده مینماید. به طور مثال این مورد را برای برنامه htop و ls تست میکنیم.

root@regux:~# ldd /usr/bin/htop
 linux-vdso.so.1 (0x00007ffff0bea000)
 libncursesw.so.5 => /lib/x86_64-linux-gnu/libncursesw.so.5 (0x00007f4112294000)
 libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f411206a000)
 libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f4111d66000)
 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f41119c8000)
 libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f41117c4000)
 /lib64/ld-linux-x86-64.so.2 (0x00005589e60de000)
root@regux:~# ldd /bin/ls
 linux-vdso.so.1 (0x00007ffd3237a000)
 libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007fad0668d000)
 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fad062ef000)
 libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007fad0607c000)
 libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fad05e78000)
 /lib64/ld-linux-x86-64.so.2 (0x0000555bde1af000)
 libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fad05c5b000)

همانطور که مشخص است لایبری ها و بخشی از کد که به این لایبری ها refer داده شده است مشخص است.

پس دستور ldd در صورت داشتن Dynamic Link بخشی از کد را که کتابخانه در آن استفاده شده است و خود کتابخانه را نمایش میدهد. حالا موردی را در نظر بگیرید. سیستم عامل از کجا میفهمد فایل یک لایبری خاص در کجا قرار گرفته است؟

تمامی کانفیگ ها در این رابطه در فایل ld.so.conf در دایرکتوری etc قرار گرفته است.

# cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf

# ls /etc/ld.so.conf.d/
fakeroot-x86_64-linux-gnu.conf          i686-linux-gnu.conf                     x86_64-linux-gnu_EGL.conf               
i386-linux-gnu.conf                     libc.conf                               x86_64-linux-gnu_GL.conf                
i386-linux-gnu_GL.conf                  x86_64-linux-gnu.conf                   x86_64-linux-gnu_mirclient8driver.conf  

# cat /etc/ld.so.conf.d/libc.conf 
# libc default configuration
/usr/local/lib

root@funlife:/sbin# cat /etc/ld.so.conf.d/x86_64-linux-gnu_GL.conf 
/usr/lib/x86_64-linux-gnu/mesa

دو خط اول فایل کانفیگ را نشان میدهد که داخل آن کلیه فایل های کانفیگ در پوشه ی ld.so.conf.d به صورت Include شده قرار دارند. که در بالا از این دایرکتوری ls گرفتیم تا محتوای آن قابل مشاهده باشد. به طور مثال در فایل libc.conf ذکر شده که تمام کتابخانه های داخل دایرکتوری usr/local/lib/ خوانده شود.

با توجه به اینکه لینوکس نیاز به سریع بودن دارد، نمیتواند تمام این مسیر ها را طی کند. به همین دلیل دستور ldconfig تمام این فایل ها را خوانده و تمامی آنها را در فایل ld.so.cache ذخیره مینماید. لازم به ذکر است به دلیل نیاز به سرعت، این فایل نیاز دارد که سریع باشد. برای مشاهده ی محتویات این فایل نیز میتوانید از فلگ p استفاده نمایید.

root@regux:~# ldconfig -p | head -n 20
1316 libs found in cache `/etc/ld.so.cache'
 libzzipwrap-0.so.13 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzzipwrap-0.so.13
 libzzipmmapped-0.so.13 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzzipmmapped-0.so.13
 libzzipfseeko-0.so.13 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzzipfseeko-0.so.13
 libzzip-0.so.13 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzzip-0.so.13
 libzvbi.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzvbi.so.0
 libzvbi-chains.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzvbi-chains.so.0
 libzmq.so.5 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzmq.so.5
 libzip.so.4 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzip.so.4
 libzeitgeist-2.0.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzeitgeist-2.0.so.0
 libzbar.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzbar.so.0
 libzapojit-0.0.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzapojit-0.0.so.0
 libz.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libz.so.1
 libyelp.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libyelp.so.0
 libyara.so.3 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libyara.so.3
 libyaml-0.so.2 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libyaml-0.so.2
 libx265.so.95 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libx265.so.95
 libx264.so.148 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libx264.so.148
 libx86.so.1 (libc6,x86-64) => /lib/x86_64-linux-gnu/libx86.so.1
 libxvidcore.so.4 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libxvidcore.so.4

همانطور که مشاهده میکنید 20 خط اول این فایل نمایش داده میشوند. تمامی کتابخانه ها با مسیر ذخیره سازی آن در این فایل ذکر میگردند.

همانطور که گفتیم کتابخانه ها مدام به روز میشوند و نام آنها، به خصوص عدد کوچکی که در انتهای آنها است به طور مداوم تغییر می یابد. بهتر است با مفهومی با نام symbolic links آشنا شوید. همانطور که در پایین مشاهده میکنید، فایل libudev.so.1 در برنامه های مختلف به عنوان کتابخانه مورد استفاده قرار میگیرد، ولی این فایل، یک فایل حقیقی نیست، در اصل یک symbolic links است به libudev.so.1.6.5 که برای راحتی جزئیات را حذف نموده است.

root@regux:~# locate libudev.so.1
/lib/x86_64-linux-gnu/libudev.so.1
/lib/x86_64-linux-gnu/libudev.so.1.6.5
root@regux:~# ls -la /lib/x86_64-linux-gnu/libudev.so.1
lrwxrwxrwx 1 root root 16 Jul 16 00:43 /lib/x86_64-linux-gnu/libudev.so.1 -> libudev.so.1.6.5

حالا متوجه میشوید که چرا دستور ldconfig از کتابخانه های استاتیک استفاده مینماید. چون مسئول ایجاد کش است و نیاز است بدون دانستن اطلاعاتی در ارتباط با کتابخانه ها آن ها را مدیریت کند.

در آخر این درس قصد داریم یک متغیر محیطی با نام LD_LIBRARY_PATH را معرفی کنیم. فرض کنین ما یک برنامه ی قدیمی داریم که نیاز به یکسری کتابخانه قدیمی دارد که در حال حاضر موجود نیست، ما میتوانیم این کتابخانه را در یک مسیر قرار داده و آن مسیر را با استفاده از این متغیر محیطی معرفی نمائیم. پس از آن ابتدا کتابخانه های موجود در این مسیر بررسی میگردند و اگر کتابخانه موجود نبود، مسیر استاندارد را بررسی می نمائیم.

root@regux:~# export LD_LIBRARY_PATH=/usr/lib/myoldlibs

مورد استفاده ی دیگر این است که ما قصد داریم خودمان یک کتابخانه بنویسیم. در آن صورت میتوانیم مسیر کتابخانه خود را نیز با : به سایر سیر های قبلی اضافه کنیم.

export  LD_LIBRARY_PATH=/usr/lib/myoldlibs:/home/regux/lpic/libs/

باید توجه داشته باشید که تعریف LD_LIBRARY_PATH تغییری در کتابخانه های پیش فرض اعمال نمی نماید، تنها برنامه ها را مجبور میکند ابتدا مسیری که ما معرفی کردیم را برای کتابخانه ها بررسی کنند.

 

 

نویسنده: میلاد خوشدل

منابع:

-جادی
-sybex
-کتاب راهنمای جامع مدرک بین المللی Lpic1


پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

بیست − شش =