بیلد سیستم یا Make چیست ؟
خب ! Build System چیست ؟
تمام برنامههایی که مینویسیم، معمولاً یک main.c
دارند که نقطهٔشروع (start point) برنامهٔما هست. آیا همیشه همین یک فایله ؟ آیا همیشه نیازه که به یکصورت برنامه را کامپایل کنیم ؟ خب مسلماً جواب "نه" هست. چرا که ممکنه برنامهٔ شما دارای دهها فایل داشتهباشه، و نیاز داشتهباشید که هر فایل رو به صورتخاصی با فلگهای خاصی کامپایلکنید. اینجاس که "بیلد سیستم"ها وارد کار میشوند.
به احتمال زیاد نمونههای زیادی مشاهده کردید که وقتی یک سورسیرا (source) از مخازن آنلاین گیت، مثل گیتهاب یا گیتلب دریافت میکنید در فایل راهنما (README.md) در بخش Build نوشته که وارد دایرکتوری بشید و دستور make
و بعد make install
را وارد کنید، دقیقاً کاری که میکنید اینکه برنامهٔ GNU Make را صدا میزنید که فایل تنظیمات رو از دایرکتوری جاری بخواند و دستورات تعیین شده رو انجام بده، این دستورات در فایلی به نام Makefile
نوشته میشود.
نصب کردن GNU Make
این برنامه معمولاً روی تمام سیستمعاملهای معقول مثل GNU/Linux یا اقوام BSD نصب هست، درصورتیکه نبود میتوانید با استفاده از مدیربستهٔ سیستمعاملتون اقدام به نصب کنید، مثلاً برای نصب روی سیستمعامل Debian - Ubuntu - Ubuntu Mint میتوانید به اینصورت عمل کنید :
$> apt install make
چه کنیم با GNU Make ؟
اوّل از همه باید یک برنامهای داشتهباشیم که بخوایم براش Build System تعیین کنیم و دستورات Makefile
ش رو بنویسیم. یک نمونهٔ ساده کد چند تکهای را میتوانید از اینقسمت دریافت کنید. ما سه فایل arg.c/arg.h
و main.c
را به اینصورت داریم (یک ساختار معقول) :
.
├── build
├── obj
└── src
├── arg.c
├── arg.h
└── main.c
خب حالا ما باید Makefile
خودمان را داخل دایرکتوری ریشه درست کنیم، قبلاً هم گفتم : "برنامهٔ GNU Make به دنبال فایلی به اسم Makefile
یا GNUmakefile
یا makefile
میگرده". در Makefile
میتوانیمما قوانین (rule) برای ساخته شدن چیزی و متغیرهایی تعریف کنیم. اینجا من توضیحات خلاصهای را میگویم، باقیماندهٔ مطالب را باید از مستنداترسمی GNU Make یا راهنمای سریع دنبال کنید. هر قوانینای که تعریف میکنیم دارای این ساختار هست :
نیازها : هدفها
دستورات
مثلاً ما میخواهیم که برنامهٔکامپایل شدهٔمان، با اسم args
در دایرکتوری build/
قرار بگیره. اینجا "هدف"ما میشه build/args
و نیازما هم فایلهای کامپایل شدهٔ arg.c
و main.c
هست. اوه ! یک هدف دیگههم پیدا شد؛ الآن هدف دوّمما فایلهای کامپایل شدهٔ obj/arg.o
و obj/main.o
هست و نیازمان هم سورسهای این فایلها یعنی src/arg.h
و src/arg.c
و src/main.c
.
خب خیلی زیاد شدن، بهتره که از آخر شروع کنیم و نیازهایمان را برطرف کنیم، اوّلین نیاز فایلهای کامپایلشده هستن :
obj/main.o obj/arg.o : src/main.c src/arg.c src/arg.h
gcc -c -o obj/main.o src/main.c
gcc -c -o obj/arg.o src/arg.o
* نکته : سعی نکنید دستورات Makefile
را از منطقهٔ کد کپی نکنید، کمی تلاش کنید و بنویسید.
خب قبول دارم خیلی زیاد و زشت شد، بیاید این قانون (rule) را به دو تیکه قسمت کنیم :
obj/arg.o : src/arg.c src/arg.h
gcc -c -o obj/arg.o src/arg.c
obj/main.o : src/main.c
gcc -c -o obj/main.o src/main.c
اگر تا انتها متن ادامه بدید حتماً کوتاهترم خواهد شد :).
خب؛ object fileها یا همان فایلهای کامپایل شدهیمان را به دستآوردیم. حالا باید قانون (rule) نیاز اوّلمان را بنویسیم، چه چیزی نیاز داشتیم ؟ فایل کامپایل شدهٔ build/args
که نیاز به object fileها داشت، حالا object fileها را داریم و باید نیاز هدفمان را برطرف کنیم :
build/args : obj/main.o obj/arg.o
gcc -o build/args obj/main.o obj/arg.o
obj/arg.o : src/arg.c src/arg.h
gcc -c -o obj/arg.o src/arg.c
obj/main.o : src/main.c
gcc -c -o obj/main.o src/main.c
تمام شد. ما دستورات Build System خودمان را به زبان برنامهٔ GNU Make نوشتیم؛ حالا کافیه که فقط وارد دایرکتوریای که فایل Makefile
هست بشیم و از ترمینال برنامهٔ make
را فراخوانی کنیم :
$> make
gcc -c -o obj/main.o src/main.c
gcc -c -o obj/arg.o src/arg.c
gcc -o build/args obj/main.o obj/arg.o
حالا میتوانیم برنامهٔ خودمان را اجرا کنیم :
$> build/args -name Ghasem -family Ramezani
Input Name is [Ghasem]
Input Family is [Ramezani]
دقّت کرده باشید ما توی نوشتن Makefile
مان نیازمندیهارو یکی بالاتر از دیگری نوشتیم. چرا ؟ به خاطر اینکه GNU Make میاد از اوّل فایل شروع میکنه و قوانین (rules)ها را اجرا میکنه. بزارید با یک مثال نشان بدم. Makefile
زیر را مدنظرتون داشتهباشید :
obj/arg.o : src/arg.c src/arg.h
gcc -c -o obj/arg.o src/arg.c
obj/main.o : src/main.c
gcc -c -o obj/main.o src/main.c
build/args : obj/main.o obj/arg.o
gcc -o build/args obj/main.o obj/arg.o
ما نیاز اصلی خودمان را آخرین قانون (rule) نوشتیم. حالا برنامهٔ make
را اجرا میکنیم تا رفتارَش را بهتر متوجه بشیم :
$> make
gcc -c -o obj/arg.o src/arg.c
دیدید ؟ خیلی ساده برخورد کرد، اوّلین قانون (rule) را نگاه کرد تنها نیازمندیش فایلهای src/arg.c
و src/arg.v
بودن که وابسته به چیزی نبودند و هدفشان را تأمین کردند. اگر بخواهیم باقی قوانین (rules) را فراخوانی کنیم، باید صراحتاً مشخص کنیم :
$> make obj/main.o
gcc -c -o obj/main.o src/main.c
$> make build/args
gcc -o build/args obj/main.o obj/arg.o
خب دیگه امیدوارم دلیل اینکهما نیازمندی اصلیه خودمان را اوّلین قانون (rule) قرار دادیم را متوجه شده باشید. وقتی make
به نیازمندیه obj/arg.o
و obj/main.o
برای تأمین build/args
برمیخوره ادامهٔ قوانین را پیمایش میکنه تا نیازمندیها را برطرف کنه. (اگر گیج شدید احتمالاً، پیشنهاد میکنم همین موارد را روی کاغذ کشیده و قسمت : نیازمندیها و هدفها و دستورات هر قانون را مشخص کنید.)
میتوانیم قوانینی (rules) تعریف کنیم برای کارهای خاصی، مثلاً همان make install
، یعنی قانون install
را فراخوانی کن؛ حالا ما قانون clean
را برای حذف کردن فایلهای کامپایلشده مینویسیم :
clean :
yes | rm -vf build/* obj/*
البته باید در اینجا نکتهای را هم حواسمان باشد، باید به GNU Make
بگوییم که قانون clean
، یک قانون الکیهست، و با یک "هدف" اشتباه نشود. به اینصورت قانون را ویرایش میکنیم :
.PHONY : clean
clean :
yes | rm -vf build/* obj/*
نگرانیای هم دربارهٔ Wildcard ها نداشتهباشید، GNU Make دستتون را باز گذاشته :).
متغیرها در GNU Make
مسلماً هرجا سخنی از متغیراست، سر و کلهٔ راحتیکار (و تا حدودی پیچیدگی) پیدا میشود. ما میتوانیم متغیرهم داخل Makefile
خودمان داشتهباشیم. مثلاً فرض کنید که نیاز دارید تمام سورسکدها با کامپایل clang
و سطحبهینهسازیه 3
کامپایل بشند. نیازی نیستکه هربار اینارو تایپ کنیم. کافیه براشون متغیرتعریف کنیم :
CC = clang
OP = -O3
OBJECT = obj/main.o obj/arg.o
ARGS = src/arg.c src/arg.h
build/args : $(OBJECT)
$(CC) $(OP) -o build/args $(OBJECT)
obj/arg.o : $(ARGS)
$(CC) $(OP) -c -o obj/arg.o src/arg.c
obj/main.o : src/main.c
$(CC) $(OP) -c -o obj/main.o src/main.c
clean :
yes | rm -vf build/* obj/*
متغیرهای به خصوصی نیز در GNU Make
تعریف شدهاند که میتوانند کار مارا بسیار راحتتر کنند، برای مثال میتوانیم قانون object fileها را به اینصورت بازنویسی کنیم :
obj/%.o : src/%.c
$(CC) $(OP) -c -o $@ $?
برای اطلاعات بیشتر به راهنمایسریع GNU Make مراجعه کنید.
یادداشتها یا Code Comments
برای استفاده از قابلیت Comment گذاری در کد، کافیه که اوّل خط خودتون از کاراکتر #
استفاده کنید.
خب دوستان، سعی کردم کلیّات مبحث را بگم؛ ابزار Make قابلیتهای بسیار زیادی داره که حتماً باید خودتون مطالعه کنید. مثلاً خواستید Makefile
شما یک Makefile
دیگه را صدا بزنه، یا حتیٰ دستورات شرطی اجرا بکند و یا از همه مهمتر بر اساس معماری پلتفرم شما عملیات کامپایل را انجام بده و ... .
- موفقوپیروز باشید.
- 1
- 1
- 3
1 دیدگاه
نظرهای پیشنهاد شده