در این قسمت از آموزش RTOS به ادامه معرفی و آموزش ابزار GNU Make می پردازیم، با ما همراه باشید.
متغیرها همواره کاربردهای زیادی در برنامهنویسی داشتهاند. بهطورکلی شما هر الگوریتمی را که بخواهید با یکزبان برنامهنویسی اجرایی کنید، بدون شک به متغیرها برخورد میکنید. ازآنجاکه ما در Makefile در حال نوعی برنامهنویسی برای مدیریت کامپایل پروژمون هستیم، متغیرها کمک بسیار زیادی به ما میکنند؛ اما معنا و مفهوم متغیر در GNU Make با آن چیزی که در زبانهای برنامهنویسی میشناسیم، کمی متفاوت است.
برای مثال شما میتوانید بهجای اینکه در جایجای Makefileتون از gcc در Recipeها استفاده کنید، یک متغیر تعریف و مقدار آن را gcc قرار دهید. در این صورت اگر روزی روزگاری تصمیم گرفتید بهجای gcc مثلاً با کامپایلر clang پروژتون رو کامپایل کنید، کافی است تنها مقدار آن متغیر را از gcc به clang تغییر دهید. در ادامه بامعنا و مفهوم متغیرها در Make بیشتر آشنا میشویم. پس با سیسوگ همراه باشید.
بر اساس داکیومنتهای GNU، متغیر نامی است که در یک Makefile برای نمایش رشتهای از متن تعریف شده که مقدار متغیر نامیده میشود. این مقادیر معمولاً با استفاده از متغیرها در Target یا Prerequisite(s) یا Recipe ها جایگزین میشوند. در برخی از نسخههای Make، متغیرها ماکرو نیز نامیده میشوند. |
برای تعریف یک متغیر در Makefile ابتدا باید بدانیم از چه کاراکترهایی برای نامگذاری میتوانیم استفاده کنیم و سپس اینکه چه مقادیری به یک متغیر میتوانیم اختصاص دهیم:
نامگذاری متغیر باید از قواعد زیر پیروی کند:
متغیرها میتوانند فهرستی از نام فایلها، سوئیچهایی برای استفاده در دستورات کامپایلرها، برنامههایی برای اجرا، دایرکتوریهایی برای جستجوی سورس فایلها، فهرستهایی برای نوشتن خروجی یا هر چیز دیگری که میتوانید تصور کنید را نشان دهند.
نکته: هر فاصلهای که قبل از مقدار متغیر وجود داشته باشد، در نظر گرفته نمیشود.
مثالهای زیر نمونههایی از یک متغیر مجاز را به نمایش میگذارند:
1 2 3 4 | cc = gcc switchcompiler = -o print = echo "Hello World\n" sourcefile = a.c b.c d.c e.c ... |
به عبارت خیلی ساده پس از تعریف یک متغیر میتوان آن را به یکی از دو صورت زیر استفاده کرد یا بهعبارتدیگر به مقدارش ارجاع داد:
1 2 | var = metech name = $(var) or name = ${var} |
حالا میخواهم یک مثال بسیار کاربردی و ساده بزنم: فرض کنید ما تعداد پنج تا آبجکت فایل داریم که برای ساخت یک فایل اجرایی باید به یکدیگر لینک شوند.بنابراین Makefile با استفاده از متغیرها بهصورت زیر میشود:
1 2 3 4 | cc = gcc objects = main.o sum.o mine.o output : $(objects) $(cc) $(objects) -o program |
زمانی که ما از یک متغیر استفاده میکنیم، یعنی از () $ یا {}$ استفاده میکنیم، در واقع در حال جایگزینی نام متغیر با مقدار آن هستیم. به این کار در داکیومنتهای گنو Expanding یک متغیر گفته میشود. در Expanding یک متغیر، محتوای متغیر واو به واو جایگزین ارجاع متغیر میشود. |
نکته: زمانی که میگوییم محتوای متغیر حرفبهحرف جایگذاری میشود، یعنی ما متغیر را در هر قسمتی از Makefile میتوانیم استفاده کنیم:
1 2 3 4 | foo = c cc = g$(foo)$(foo) prog.o : prog.$(foo) $(cc) -$(foo) prog.$(foo) |
بر اساس داکیومنتهای گنو :”راههای مختلفی وجود دارد که یک متغیر در GNU make میتواند یک مقدار را دریافت کند. ما آنها را Flavor متغیرها مینامیم. Flavorها در نحوه برخورد با مقادیری که در Makefile تخصیص داده شدهاند و نحوه مدیریت آن مقادیر زمانی که متغیر بعداً مورداستفاده قرار میگیرد و گسترش مییابد، متفاوت میشوند. برایناساس متغیرها به دو گروه اصلی تقسیمبندی میشوند:
اولین Flavor متغیرها، حالت مقداردهی بازگشتی است. برای استفاده از این نوع مقداردهی باید متغیر در تعریف اولیه بهصورت زیر تعریف شود:
1 | varRec = metech |
در این حالت تنها زمانی متغیر مقداردهی میشود که از متغیر استفاده کنیم. هنگامی که از متغیر استفاده کنیم، Make برای مقدار متغیر شروع به اسکن کل فایل میکند و آخرین مقداری که به متغیر اختصاصدادهشده است را جایگزین متغیر میکند، یا بهعبارتدیگر فرض کنید دو متغیر a و b داشته باشیم که محتوای متغیر a بهعنوان مقدار متغیر b قرار گیرد، آنگاه اگر هر زمانی که از متغیر b استفاده میکنیم، یکبار مقدار متغیر a نیز خوانده شود و سپس مقدار متغیر b جایگزین شود، به این حالت Recursively Expantion گفته میشود. برای مثال:
1 2 3 4 5 6 7 | foo = $(bar) bar = $(ugh) ugh = Huh all: echo $(foo) .PHONY = all |
نتیجه Makefile بالا:
بنابراین، هنگام استفاده از متغیرها بهصورت بازگشتی، هر باری که متغیر فراخوانده میشود، یکبار کل فایل اسکن میشود و بهصورت بازگشتی (همانطور که در بالا گفتیم) مقدار متغیر جایگزین ارجاع آن میشود. این حالت استفاده از متغیرها تنها نوعی است که توسط بیشتر نسخههای make پشتیبانی میشود؛ اما دو مشکل بزرگ دارد:
شاید برای شما مفید باشد: آموزش AVR از 0 تا 100 کاملا رایگان
1 2 | foo = Huh foo = $(foo) Huh |
با این پیغام روبهرو میشویم:
البته برای حل این مشکل یک راهحل وجود دارد و آن هم در بخش چسباندن یک مقدار به مقدار فعلی متغیر توضیح داده شده است. اما بنا بر دلایل گفته شده نوع دوم از متغیرها وارد شدند.
دومین Flavor متغیرها، حالت مقداردهی ساده است. در این حالت مقداردهی و اسکن فایل برای مقداردهی متغیر فقط یکبار، آن هم زمانی که متغیر تعریف میشود، انجام میشود؛ بنابراین اگر خروجی تابعی بهعنوان مقدار متغیر قرار گیرد، فقط یکبار آن هم زمان تعریف متغیر تابع اجرا میشود. برای استفاده از این حالت، متغیر باید بهصورت زیر تعریف شود:
1 2 3 | x := foo y := $(x) bar x := slm |
نتیجه Makefile بالا:
1 2 3 | x = foo y = foo bar x = slm |
همچنین مشکل چسباندن یک مقدار به مقدار قبلی متغیر نیز در این حالت رفع شده است:
1 2 3 | x = foo x = ${x} bar #Result is : x = foo bar |
علاوه بر نوع تعریف متغیر که نحوه Expanding آن را تعیین میکند، جایی که متغیر را استفاده میکنیم نیز تعیینکننده نوع برخورد Make با آن متغیر است و در واقع بهتر است بگویم که بر نوع تعریف متغیر اولویت دارد. همانطور که در بخش قبل گفتیم Make به دو صورت عمل میکند:
حال هر گاه ما از متغیر در سمت چپ علامت انتساب مقدار به متغیر یا در Target یا در Prerequisite(s) استفاده میکنیم، make به صورت فوری ارجاع متغیر را با مقدارش جایگزین میکند اما اگر از متغیر در سمت راست علامت انتساب مقدار به متغیر یا در Recipe استفاده شود، آنگاه make به صورت تاخیری ارجاع متغیر را با مقدارش جایگزین میکند.
بنابراین، بهصورت کلی:
متغیرهای چندخطی متغیرهایی هستند که مقدار آنها در چند خط گسترش داده شده است. برای تعریف متغیرهای چندخطی میتوان بهصورت زیر عملکرد:
شاید برای شما مفید باشد: آموزش STM32 با توابع HAL و LL
برای مثال:
1 2 3 4 5 6 | define var = Hello World echo "salam" foo bar endef |
این کار بسیار ساده است. تنها کافی است از یک علامت بهصورت زیر استفاده کنیم:
1 2 3 | var = foo var += bar #Result is: var -> foo bar |
این روش هم برای متغیرهایی که بهصورت بازگشتی و هم متغیرهایی که بهصورت ساده تعریف شدهاند، جوابگوست.
در بین تنظیمات دستور make قالبی وجود دارد که در آن میتوان با مقداردهی مستقیم به یک متغیر، بدون تعریف آن در Makefile از آن متغیر استفاده کرد. برای مثال فرض کنید Makefile زیر را داریم:
1 2 3 | print: echo $(var) .PHONY : print |
در فایل بالا متغیر var تعریف نشده و به همین دلیل میتوان از دستور make بهصورت زیر برای مقداردهی به متغیر استفاده کرد:
1 | make var=bar |
حال نکتهای که وجود دارد این است که اگر متغیر در بخشی از Makefile مانند Recipe استفاده شده باشد، بهصورت Referred مقداردهی شده و مقداری که در دستور make به این متغیر اختصاص میدهیم بهعنوان آخرین مقدار متغیر در فایل شناخته میشود. اگر بخواهیم مقداری که توسط دستور make به یک متغیر اختصاص داده میشود، نادیده گرفته شود، کافی است آن متغیر را بهصورت override تعریف کنیم:
1 | override var = bar |
در این قسمت به شرح موضوعاتی در زمینه متغیرها در make پرداختیم. با استفاده از اطلاعاتی که در این قسمت و قسمت بعدی (که آشنایی و کار با توابع است) به دست میآورید، میتوانید Makefileهای حرفهایتر و هوشمندتری بنویسید.
عالی بود.
سپاس.
بسیار کار سودمندی کردید.
ادامه بدید.
نویسنده شو !
سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.