Make

در توسعه نرم‌افزار، make ابزاری برای ساختن اتوماتیک فایلهای اجرایی از کد منبع است. فایلی که Makefile خوانده می‌شود روند کامپایل قطعات پروژه را بر اساس پیش‌نیازهای آن معلوم می‌کند. اگر چه ابزارهای بسیار زیادی برای توسعه مداوم و اجرا کردن تست‌ها در محیط‌های برنامه‌نویسی موجود است، اما MakeFile به صورت گسترده و مخصوصاً در سیستم‌های مبتنی بر یونیکس استفاده می‌شود.

مقدمه

قوی‌ترین ابزار برنامه‌نویسان برای جلوگیری از پیچیدگی‌های بیش از حد در پروژه‌ها استفاده از روش برنامه‌نویسی ماژولار (Modular) است.
در این روش بخش‌های مختلف پروژه به صورت ماژول‌های مجزا قابل کامپایل هستند؛ ولی از طرفی هم عملیات کامپایل تک‌تک ماژول‌ها و چسباندن نهایی آن‌ها به یکدیگر، فرایندی زمان‌بر و پراشتباه است.
خوشبختانه ابزار Make برای تسهیل این مراحل و خودکارسازی این فرایند ساخته شده‌است. روند کامپایل این ماژول‌ها در فایلی به‌نام Makefile تعریف می‌شوند.
در یک نگاه کلی، make فقط برای کامپایل برنامه‌ها استفاده نمی‌شود. شما می‌توانید در هر کاری که در آن نیاز به بروزرسانی بعضی فایل‌ها متناسب با تغییر در فایل‌های دیگر است از make استفاده کنید.
بطور مثال معمولاً در یک برنامه رایانه‌ای نیاز است از کدهای منبع فایل‌های آبجکت و سپس از این فایل‌های آبجکت، فایل اجرایی ساخته شود.
وقتی شما برنامه‌ای می‌نویسید، باید برای آن یک Makefile هم درست کنید و سپس برای کامپایل و نصب آن از Make کمک می‌گیرید.
make بطور خودکار تشخیص می‌دهد چه قسمت‌هایی از یک برنامهٔ بزرگ به چه صورت باید کامپایل شوند.
همچنین می‌توان از آن برای کامپایل برنامه‌ها به هر زبانی که نوشته شده‌اند استفاده کرد، به‌شرط آنکه کامپایلر آن زبان توانایی اجرا از طریق پوسته (Shell) را داشته‌باشد.
ابزار make بطور گسترده‌ای به‌خصوص در سیستم‌های مبتنی بر یونیکس استفاده می‌شود.

Ruleها

Ruleها در Makefile مشخص می‌کنند که برای ساخت یک Target چه دستورهایی باید اجرا شود. همچنین می‌توان برای ساخت هدف، فهرستی از پیش‌نیازها (Dependencies) را نیز تعریف کرد. در این فهرست باید تمام فایل‌های مورد نیاز (کدمنبع یا هر نوع فایل دیگری) که برای ساخت هدف مورد نیاز است تعریف شود.
# Comments use the hash symbol

target: dependencies
command 1command 2
           .
           .
           .
command n
معمولاً Target نام فایلی است که قرار است توسط یک برنامه ایجاد شود. مثلاً فایل‌های آبجکت یا اجرایی. همچنین می‌تواند نام کاری باشد که قرار است اجرا شود. مثل تمیز کردن یک پروژه (Clean)
پیش‌نیازها (Dependencies) فایل‌های ورودی‌ای هستند که برای ساختن هدف مورد نیازند که به هر تعدادی می‌توانند باشند.
در صورت تغییر در هر یک از این پیش‌نیازها، هدف باید دوباره ساخته شود.
البته هدف‌هایی هم هستند که نیاز به پیش‌نیازی ندارند. بطور مثال هدفی مانند Clean که باید بعضی از فایل‌ها را پاک کند.
فرمان‌های (Command) هم کارهایی هستند که Make برای ساخت هدف انجام خواهد داد. برای ساخت یک هدف ممکن است چندین دستور نیاز باشد که باید در خطوط جداگانه نوشته شوند.
توجه کنید که حتماً باید در ابتدای دستورات یک کارکتر تب (TAB) قرار دهید.

متغیرها کارها را ساده می‌کنند

مثال زیر را در نظر بگیرید:
edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o
چنین قواعدی در Makefile، به‌شدت مستعد خطا هستند. اگر نیاز به اضافه کردن فایل آبجکت جدیدی به پروژه باشد، ما باید در تمام مکان‌های مورد نیاز آن را اضافه کنیم.
می‌توان بوسیلهٔ متغیرها این کار را ساده‌تر و مطمئن‌تر انجام داد.
متغیرها این امکان را می‌دهند تا بتوانیم متنی را در آن‌ها ذخیره کنیم و در چندین مکان مورد استفاده قرار دهیم.
تقریباً تمام Makefileها متغیری با نامی شبیه به objects , OBJECTS , objs , OBJS , obj یا OBJ دارند که فهرستی از نام تمام آبجکت‌های مورد نیاز در پروژه را در خود نگه داشته‌است.
ما می‌توانیم برای مثال خود متغیری بنام objects را با نوشتن چنین خطی در Makefile تعریف کنیم:
objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o
از این به بعد هر کجا نیاز به نوشتن فهرستی از فایل‌های آبکجت مورد استفاده بود، می‌توان از متغیر تعریف شده به صورت (objects)$ استفاده کرد.
edit : $(objects)
cc -o edit $(objects)

Makefile چطور پردازش می‌شود؟

بطور پیش‌فرض، Make با اولین Target موجود در Makefile شروع می‌کند (اولین هدفی که با نقطه شروع نشده است). این هدف Default Goal نامیده می‌شود. (می‌توان این هدف پیش‌فرض را توسط خط فرمان تغییر داد)
وقتی شما دستور make را در خط فرمان می‌نویسید، برنامهٔ Make در دایرکتوری فعلی‌ای که در آن قرار دارید فایلی به‌نام Makefile را می‌خواند و شروع به پردازش اولین هدف موجود در آن می‌کند (Default Goal). اما قبل از اینکه دستورات موجود در این هدف اجرا شوند، Make باید تمام پیش‌نیازهای مربوط به آن هدف را پردازش کند. هر یک از این پیش‌نیازها نیز برای خود Rule دارند که برای ساخت آن‌ها پردازش خواهد شد.
بطور مثال در یک برنامه کامپایل دوباره یک فایل آبجکت زمانی اتفاق می‌افتد که فایل سورس یا هیدر مربوط به آن بعد از ساخت فایل آبجکت تغییر کرده باشند یا اساساً فایل آبجکت هنوز ساخته نشده‌باشد.
به این ترتیب است که قواعد (Rules) دیگر موجود در Makefile پردازش و اجرا می‌شوند. زیرا آن‌ها پیش‌نیازهای ساخت هدف اصلی هستند.
روشن است که اگر یک قاعده جزء پیش‌نیازهای هدف اصلی نباشد پردازش نخواهد شد. مگر اینکه بطور صریح از Make بخواهید آن را پردازش کند (مثلاً با دستور make target-name)