فصل ۲۳ – کامپایل برنامهها
تا اینجا در سراسر کتاب از برنامههایی استفاده کردهایم که به صورت «بستهٔ دودویی» (binary package) در توزیعهای لینوکس موجودند.
بیشتر کاربران هم هرگز با ساخت یک برنامه از منبع روبهرو نمیشوند. بااینحال، آشنایی با روند ساخت از منبع مهارتی ارزشمند است؛
گاهی نسخهٔ جدید هنوز در مخازن قرار نگرفته، یا اصلاً بستهٔ آمادهای برای نرمافزار مورد نظر وجود ندارد،
یا میخواهیم قابلیتهای سفارشی را فعال یا غیرفعال کنیم. در این فصل قدمبهقدم فرآیند کلاسیک «configure → make → make install» را بررسی میکنیم،
میآموزیم هر مرحله دقیقاً چه میکند و چگونه میتوان با مشکلات رایج کنار آمد.
چرا باید برنامهها را از منبع بسازیم؟
دلایل رایجی که ما را وادار به کامپایل میکند عبارتاند از:
- دسترسی به جدیدترین نسخه – توسعهدهندگان منتشر کردهاند، اما بستهٔ توزیع هنوز بهروزرسانی نشده است.
- نبود بستهٔ دودویی – پروژهای کوچک یا قدیمی ممکن است هرگز در مخازن رسمی قرار نگرفته باشد.
- سفارشیسازی – برخی برنامهها دهها گزینهٔ قابل کامپایل دارند که تنها از طریق ساخت از منبع قابل فعالسازی هستند.
- یادگیری – کنار زدن پردهها و دیدن نحوهٔ تبدیل کد منبع به برنامهٔ اجرایی درک عمیقتری از سیستم به ما میدهد.
نکتهٔ خوب این است که بیشتر پروژهها روندی بسیار مشابه دارند،
پس اگر یک بار آن را تمرین کنید، باقی پروژهها نیز برایتان آشنا خواهند بود.
پیشنیازها و ابزارهای لازم
ساخت از منبع نیازمند «زنجیرهٔ ابزار توسعه» (toolchain) است:
کامپایلر C یا C++، کتابخانههای توسعه، ابزار پیوند (linker)، و برنامهٔ make.
در توزیعهای مبتنی بر Debian میتوانید همهٔ ابزارهای پایه را با بستهٔ build-essential نصب کنید:
[me@linuxbox ~]$ sudo apt update
[me@linuxbox ~]$ sudo apt install build-essential
در خانوادهٔ Fedora/Red Hat گروه بستهٔ «Development Tools» یا دستور مشابهی در اختیار دارید:
[me@linuxbox ~]$ sudo dnf groupinstall "Development Tools"
علاوه بر ابزارهای عمومی، هر پروژه ممکن است به هدرها و کتابخانههای مخصوصی نیاز داشته باشد.
این وابستگیها معمولاً با پسوند -dev یا -devel شناخته میشوند.
وقتی اجرای configure به خطای «header not found» یا «library not found» برخورد میکند،
نام بستهٔ مورد نیاز را ذکر میکند و میتوانید آن را نصب کنید.
بهدست آوردن بستهٔ منبع
نرمافزارهای آزاد غالباً به صورت آرشیوهای فشرده در قالبهایی مثل tar.gz، tar.bz2 یا tar.xz منتشر میشوند.
پس از دانلود، آرشیو را در یک دایرکتوری کاری استخراج میکنیم:
[me@linuxbox ~]$ tar xvf tree-1.6.0.tgz
[me@linuxbox ~]$ cd tree-1.6.0
درون دایرکتوری استخراجشده معمولاً فایلهایی با نامهای README، INSTALL یا NEWS میبینید که باید قبل از ادامه مطالعه شوند.
این فایلها وابستگیهای اضافی، گزینههای پشتیبانیشده و نکتههای ویژهٔ پروژه را توضیح میدهند.
ساختار یک بستهٔ مبتنی بر Autotools معمولاً شبیه این است:
configure فایل اجرایی برای پیکربندی سیستم هدف
configure.ac ورودی autoconf
Makefile.am ورودی automake
Makefile.in قالبی برای ساخت فایل Makefile نهایی
src/ کد منبع برنامه
man/ صفحات راهنما
ما مستقیماً با configure و خروجی آن یعنی Makefile سروکار داریم.
فایلهای *.in و *.am توسط توسعهدهندگان استفاده میشوند تا این فرآیند را خودکار کنند.
انجام مراحل استاندارد configure/make/make install
تقریباً همهٔ پروژههای مبتنی بر Autotools مراحل زیر را دارند:
- اجرای اسکریپت
configureبرای بررسی سیستم و تولید فایلهای ساخت. - اجرای
makeبرای کامپایل برنامه. - اجرای
make install(معمولاً به صورت ریشه یا باsudo) برای کپی فایلهای ساختهشده در مقصد.
بیایید این مراحل را روی بستهٔ tree انجام دهیم تا روند واقعی را ببینیم.
اجرای configure
در ریشهٔ دایرکتوری منبع دستور زیر را اجرا میکنیم:
[me@linuxbox tree-1.6.0]$ ./configure
در طول اجرا، اسکریپت به دنبال ویژگیهای سیستم میگردد، وجود کتابخانهها، کامپایلر و امکانات اختیاری را بررسی میکند و در نهایت فایل Makefile و تعدادی فایل کمکی تولید میکند. بخشی از خروجی ممکن است چیزی شبیه زیر باشد:
checking for gcc... gcc
checking whether the C compiler works... yes
checking for ncursesw/ncurses.h... yes
checking for ranlib... ranlib
config.status: creating Makefile
اگر وابستگیای یافت نشود، اسکریپت معمولاً متوقف میشود و پیام روشنی چاپ میکند؛
در آن صورت باید بستهٔ توسعهٔ مربوطه را نصب کرده و دوباره ./configure را اجرا کنید.
اسکریپت configure مجموعهٔ بزرگی از گزینهها دارد. با ./configure --help میتوانید فهرست کامل را ببینید. متداولترین گزینهها عبارتاند از:
--prefix=/usr/local– تعیین شاخهٔ نصب (پیشفرض معمولاً/usr/localاست).--sysconfdir=/etc– محل فایلهای پیکربندی.--enable-/--disable-– فعال یا غیرفعال کردن قابلیتهای اختیاری.--with-/--without-– استفاده یا عدم استفاده از کتابخانهها/ویژگیهای خارجی.
مثلاً اگر بخواهیم tree را در شاخهٔ خانگی نصب کنیم، میتوانیم از ./configure --prefix=$HOME/.local استفاده کنیم.
ساخت با make
پس از موفقیت configure، دستور make را اجرا میکنیم:
[me@linuxbox tree-1.6.0]$ make
خروجی make نشان میدهد که فایلهای منبع در حال کامپایل شدن هستند:
gcc -c -O2 -Wall -o tree.o tree.c
gcc -c -O2 -Wall -o unix.o unix.c
gcc -o tree tree.o unix.o -lncurses
در سیستمهای چند هستهای میتوانید از گزینهٔ -j برای موازیسازی استفاده کنید:
[me@linuxbox tree-1.6.0]$ make -j$(nproc)
بسیاری از پروژهها هدفهای دیگری مانند make check یا make test را نیز ارائه میکنند تا مجموعهٔ آزمونها را پیش از نصب اجرا کنید.
اجرای این آزمونها کمک میکند مطمئن شوید برنامه روی سیستم شما بهدرستی کامپایل شده است.
اگر همه چیز به درستی پیش برود، برنامهٔ قابل اجرا در همان دایرکتوری ظاهر میشود. میتوانید بدون نصب هم آن را اجرا کنید:
[me@linuxbox tree-1.6.0]$ ./tree --version
tree v1.6.0 (c) 1996-2023 by Steve Baker, Thomas Moore, Francesc Rocher, and Florian Sesser
نصب برنامه
برای کپی فایلها در سیستم از make install استفاده میکنیم. این مرحله معمولاً نیازمند دسترسی ریشه است:
[me@linuxbox tree-1.6.0]$ sudo make install
[sudo] password for me:
فایلهای نصبشده در مقصدی که با --prefix تعیین کردهایم قرار میگیرند. اگر پیشفرض /usr/local باشد، برنامه در /usr/local/bin/tree و صفحات راهنما در /usr/local/share/man/man1/tree.1 نصب میشوند.
بسیاری از پروژهها هدف make uninstall را هم تعریف میکنند تا در صورت نیاز فایلهای نصبشده حذف شوند؛ این هدف تنها زمانی کار میکند که همان نسخه و همان مسیر نصب را نگه داشته باشید.
بهتر است تمام مراحل تا قبل از make install را به عنوان کاربر عادی انجام دهید. اجرای configure یا make با دسترسی ریشه میتواند فایلهای موقت را با مالکیت root ایجاد کند و در مراحل بعدی دردسرساز شود.
برای حذف فایلهای واسط (object files) و تمیز کردن دایرکتوری منبع، هدف make clean را اجرا میکنیم:
[me@linuxbox tree-1.6.0]$ make clean
بعضی پروژهها هدف make distclean را هم فراهم میکنند که فایلهای تولید شده توسط configure را حذف میکند تا دایرکتوری به حالت اولیه برگردد.
اسکریپت configure چه میکند؟
configure بخشی از سیستم ساخت GNU Autotools است. این اسکریپت مجموعهای از آزمونها را اجرا میکند تا ببیند سیستم شما چه امکاناتی دارد:
- وجود یا عدم وجود کتابخانهها (
libncurses,libssl, ...) - بررسی نسخههای برنامهها (
gcc,make) - تعیین مسیرهای استاندارد
- شناسایی تفاوتهای سیستمعامل (GNU/Linux، macOS، *BSD)
بر خلاف بستههای دودویی که برای یک توزیع خاص ساخته میشوند،
این روش اجازه میدهد توسعهدهندگان با یک کد منبع واحد، بستهای بسازند که روی سیستمهای مختلف کامپایل شود.
اگر گزینههای سفارشی نیاز دارید (مثلاً فعال کردن پشتیبانی از قابلیت خاص)،
دستور ./configure --help اطلاعات لازم را ارائه میدهد. بسیاری از پروژهها فایل INSTALL را هم شامل میکنند که گزینههای مهم را توضیح میدهد.
برنامهٔ make چگونه کار میکند؟
make ابزاری است برای مدیریت فرآیند ساخت. این برنامه فایل Makefile را میخواند،
در آن فایل هدفها (targets) و وابستگیها تعریف شدهاند. ساختار کلی یک قاعده در Makefile چنین است:
هدف: فهرستِ-وابستگیها
<TAB> دستوراتی که باید اجرا شوند
به عنوان مثال، فایل Makefile سادهای برای برنامهای به نام hello ممکن است اینگونه باشد:
hello: hello.o util.o
gcc -o hello hello.o util.o
hello.o: hello.c hello.h
gcc -c -Wall hello.c
util.o: util.c util.h
gcc -c -Wall util.c
clean:
rm -f hello hello.o util.o
وقتی make را بدون آرگومان اجرا کنید، اولین هدف در فایل ساخته میشود (در این مثال hello).
اگر تغییری در یکی از فایلهای منبع ایجاد شود، make با مقایسهٔ زمان تغییر فایلها فقط همان بخشهای لازم را دوباره کامپایل میکند.
هدفهایی مانند install یا clean معمولاً دستورات سادهای هستند که ترتیب اجرای عملیات را استاندارد میکنند.
سیستمهای ساخت دیگر
همهٔ پروژهها از Autotools استفاده نمیکنند. گاهی در فایل README اشاره میشود که باید دستورهای دیگری اجرا کنید:
- CMake – ابتدا دستور
cmake .یاcmake -S . -B buildاجرا میشود، سپسcmake --build build. - Meson + Ninja – معمولاً با
meson setup buildو سپسninja -C build(و در نهایتninja -C build install). - SCons, Waf, setup.py (برای پروژههای Python) و ابزارهای دیگر.
اصل ماجرا تغییر نمیکند: اسکریپت پیکربندی اجرا میشود، فایلهای ساخت ایجاد میشوند و در پایان مرحلهٔ نصب انجام میگیرد.
مدیریت وابستگیها و مشکلات رایج
هنگام کامپایل احتمالاً با یکی از سناریوهای زیر روبهرو میشوید:
- کمبود کتابخانه – پیام خطا معمولاً نام فایل مورد نیاز را ذکر میکند. در توزیعهای Debian/Ubuntu بستهٔ
apt-fileمیتواند محل قرار گرفتن فایل را بیابد. - ابزارهای قدیمی – گاهی نسخهٔ قدیمی
automakeیاautoconfباعث میشود لازم باشد دستوراتautoreconfرا اجرا کنید. - نصب در محل دلخواه – اگر حق دسترسی ریشه ندارید، با
--prefix=$HOME/.localیا استفاده از متغیرDESTDIRفایلها را در شاخهٔ خانگی نگه دارید.
مستندسازی خطاها و راهحلها عادت خوبی است. فایل خروجی configure.log همواره اطلاعات دقیقی از خطاها ارائه میدهد.
ردیابی فایلهای نصبشده
از آنجا که make install فایلها را خارج از کنترل مدیر بستهٔ توزیع کپی میکند،
بهتر است فهرستی از فایلهای نصبشده داشته باشید. چند روش رایج:
- استفاده از DESTDIR – با اجرای
make install DESTDIR=$HOME/pkg/tree-1.6.0همهٔ فایلها ابتدا در دایرکتوری موقتی قرار میگیرند و میتوانید آنجا آنها را بررسی یا بستهبندی کنید. - ابزار checkinstall – این ابزار اجرا شدن
make installرا زیر نظر میگیرد و بستهای متناسب با مدیر بستهٔ سیستمتان تولید میکند تا بتوانید بعداً آن را حذف کنید. - GNU Stow – با نصب برنامهها در زیرشاخههایی مانند
/usr/local/stow/tree-1.6.0و استفاده ازstow, لینکهای نمادین در مکانهای مناسب ایجاد میشود و حذف نسخهٔ نصبشده سادهتر خواهد بود.
پیگیری نسخهها و مکان نصبشان از بروز تداخل جلوگیری میکند؛ بهخصوص اگر برنامه را بعداً بهروزرسانی یا حذف کنید.
جمعبندی
- بیشتر نرمافزارهای آزاد را میتوان با توالی
configure،makeوmake installساخت. configureسیستم شما را آزمایش میکند وMakefileتولید میکند؛makeکد را کامپایل میکند؛make installفایلها را در مقصد قرار میدهد.- دقت در خواندن فایلهای
README/INSTALL، نصب پیشنیازهای توسعه و تمیز کردن پس از نصب باعث میشود روند کامپایل بدون دردسر انجام شود.
تمرینها
- آخرین نسخهٔ برنامهٔ
treeیاncduرا از سایت رسمی دانلود کنید، سپس آن را با گزینهٔ--prefix=$HOME/.localبسازید و نصب کنید. - بستهای را انتخاب کنید که از CMake استفاده میکند (برای مثال
CMakeخود یاneovim). مراحلcmake -S . -B build,cmake --build buildوcmake --install buildرا تمرین کنید. - با استفاده از
DESTDIRنصب آزمایشی انجام دهید و فهرستی از فایلهای نصبشده تهیه کنید. این فهرست را برای آگاهیهای بعدی ذخیره کنید.
مطالعهٔ بیشتر
- صفحهٔ راهنمای
info makeو راهنمای آنلاین GNU Make. - «The Autoconf Manual» برای آشنایی عمیق با اسکریپتهای
configure. - ویکی Arch Linux و Debian دربارهٔ ساخت بسته از منبع و ابزارهایی مانند
checkinstallیاstow.