.TH "tup" "1" "2023/10/14" "http://gittup.org/tup" "tup manual" .\" disable hyphenation/justification .nh .ad l .SH "نام (NAME)" tup \- ابزار به‌روزرسانی و سامانه ساخت پروژه .SH "خلاصه دستور (SYNOPSIS)" .RS .nf tup [--debug-sql] [--debug-fuse] [SECONDARY_COMMAND] [ARGS] .fi .RE .SH "توضیحات (DESCRIPTION)" برنامه tup یک سامانه ساخت (build system) مبتنی بر فایل است. اگر در حال توسعه نرم‌افزاری هستید که باید از فایل‌های ورودی (نوشته‌شده توسط شما) به قالب خروجی متفاوتی تبدیل شود، باید از tup استفاده کنید. برای مثال، اگر در حال نوشتن یک برنامه به زبان C هستید، می‌توانید با استفاده از tup و بر اساس یک گراف وابستگی (dependency graph) مشخص کنید که کدام فایل‌ها نیاز به کامپایل مجدد، آرشیو شدن و پیوند (link) دارند. .P ابزار tup هیچ دانش خاصی از دامنه کاری ندارد. شما باید نحوه ساخت برنامه خود را به tup مشخص کنید؛ به عنوان مثال با تعیین اینکه تمام فایل‌های .c با استفاده از gcc به فایل‌های .o تبدیل شوند. این کار با نوشتن یک یا چند Tupfile انجام می‌شود. .SH "دستور اصلی: tup (PRIMARY COMMAND: tup)" شما می‌توانید تمام فرآیند توسعه خود را تنها با 'tup' و در کنار نوشتن Tupfileها انجام دهید. همچنین بخش‌های \fBINI FILE\fR، \fBOPTIONS FILES\fR و \fBTUPFILES\fR را در ادامه ببینید. .TP .B tup [ ... ] مجموعه خروجی‌ها را بر اساس گراف وابستگی و وضعیت فعلی سیستم‌فایل به‌روزرسانی می‌کند. اگر خروجی مشخص نشود، کل پروژه به‌روزرسانی می‌شود. این همان دستوری است که هر بار تغییری در نرم‌افزار خود ایجاد می‌کنید، برای به‌روز نگه‌داشتن آن اجرا می‌نمایید. می‌توانید این دستور را در هر کجای سلسله‌مراتب tup اجرا کنید و همواره خروجی درخواستی را به‌روز خواهد کرد. به طور پیش‌فرض، فهرست فایل‌های تغییریافته با پویش سیستم‌فایل و بررسی زمان تغییرات مشخص می‌شود. این کار برای پروژه‌های بسیار بزرگ ممکن است کُند باشد، اما می‌توانید با اجرای پایشگر فایل (file monitor) از زمان پویش صرف‌نظر کنید (برای توضیحات پایشگر به بخش SECONDARY COMMANDS مراجعه کنید). .RS .TP .B -jN به طور موقت گزینه updater.num_jobs را با مقدار 'N' بازنویسی می‌کند. این کار با توجه به محدودیت‌های گراف جهت‌دار غیرمدور (DAG)، تا N وظیفه را به صورت موازی اجرا خواهد کرد. به عنوان مثال: 'tup -j2' تا دو وظیفه را به طور موازی اجرا می‌کند، در حالی که 'tup' تا میزان تعیین‌شده در updater.num_jobs وظیفه موازی اجرا خواهد کرد. دستور ثانویه option را در ادامه ببینید. .TP .B --verbose باعث می‌شود tup به جای نمایش رشته ساده‌شده، رشته کامل دستور را برای دستوراتی که از پیشوند ^ TEXT^ استفاده می‌کنند، نمایش دهد. .TP .B --quiet به طور موقت گزینه display.quiet را به '1' تغییر می‌دهد. دستور ثانویه option را در ادامه ببینید. .TP .B -k .PD 0 .TP .B --keep-going .PD به طور موقت گزینه updater.keep_going را به '1' تغییر می‌دهد. دستور ثانویه option را در ادامه ببینید. .TP .B --no-keep-going به طور موقت گزینه updater.keep_going را به '0' تغییر می‌دهد. دستور ثانویه option را در ادامه ببینید. .TP .B --no-scan پروژه را برای یافتن فایل‌های تغییریافته پویش نمی‌کند. این گزینه صرفاً برای آزمایش‌های داخلی tup است و نباید در توسعه معمول استفاده شود. .TP .B --no-environ-check به‌روزرسانی‌های متغیرهای محیطی صادرشده به زیرفرآیندها را بررسی نمی‌کند؛ در عوض، متغیرهای محیطی از پایگاه‌داده استفاده خواهند شد. این مورد توسط پایشگر در حالت autoupdate/autoparse استفاده می‌شود تا تازه‌ترین متغیرهای محیطی به جای مقادیر زمان راه‌اندازی پایشگر مورد استفاده قرار گیرند. .TP .B -d خروجی گزارش اشکال‌زدایی را روی صفحه نمایش می‌دهد. .TP .B --debug-run قواعد :- تولیدشده توسط یک run-script را نمایش می‌دهد. ویژگی 'run ./script args' را در بخش TUPFILES ببینید. .B --debug-logging بخشی از خروجی‌های اشکال‌زدایی و گراف‌های ساخت را در .tup/log ذخیره می‌کند. گراف‌ها در هر بار فراخوانی همراه با --debug-logging چرخش (rotate) می‌یابند. .RE .SH "دستورهای ثانویه (SECONDARY COMMANDS)" این دستورها برای اصلاح رفتار tup یا بررسی ساختار درونی آن به کار می‌روند. احتمالاً به دفعات زیاد به آنها نیاز نخواهید داشت. دستورهای ثانویه به صورت زیر فراخوانی می‌شوند: tup [--debug-sql] [--debug-fuse] SECONDARY_COMMAND [SECONDARY_COMMAND_ARGS] .TP .B init [directory] یک دایرکتوری '.tup' در دایرکتوری مشخص‌شده ایجاد کرده و پایگاه‌داده tup را مقداردهی اولیه می‌کند. اگر نام دایرکتوری مشخص نشود، به طور پیش‌فرض '.tup' در دایرکتوری جاری ایجاد می‌شود. این دایرکتوری بالاترین سطح پروژه شما را از دید tup مشخص می‌کند. همه موارد موجود در دایرکتوری جاری و زیردایرکتوری‌های آن به عنوان "سلسله‌مراتب tup" شناخته می‌شوند. اگر می‌خواهید از اجرای 'tup init' در هر بار clone کردن مخزن به مکانی جدید بی‌نیاز شوید، می‌توانید یک فایل خالی با نام 'Tupfile.ini' در ریشه پروژه بسازید. اگر 'tup' در شرایطی اجرا شود که دایرکتوری '.tup' وجود نداشته باشد، به طور خودکار آن را هم‌سطح با فایل Tupfile.ini ایجاد می‌کند، گویی که 'tup init' را در آن دایرکتوری اجرا کرده‌اید. در صورتی که چندین فایل Tupfile.ini در مسیرهای والد وجود داشته باشد، فایلی که در بالاترین نقطه درخت قرار دارد انتخاب خواهد شد. .RS .TP .B --no-sync گزینه 'db.sync' پروژه را روی '0' تنظیم می‌کند. به طور پیش‌فرض گزینه 'db.sync' برابر با '1' است. این پرچم عمدتاً برای موارد آزمایشی کاربرد دارد، اما می‌توانید در هر محیطی که مایلید برای tup اسکریپت‌نویسی کنید و به صورت پیش‌فرض از همگام‌سازی استفاده نکنید نیز از آن بهره ببرید. .RE .TP .B refactor .PD 0 .TP .B ref .PD 1 دستور refactor می‌تواند به بازسازی ساختار (refactor) فایل‌های Tupfile کمک کند. این کار باعث می‌شود tup مرحله تجزیه (parsing) را اجرا کند اما هیچ دستوری را به اجرا درنیاورد. اگر تجزیه هر یک از Tupfileها منجر به تغییر در پایگاه‌داده شود، این موارد به عنوان خطا گزارش می‌شوند. برای مثال، ممکن است Tupfile ساده زیر را داشته باشیم: .nf : foreach *.c |> gcc -c %f -o %o -Wall |> %B.o .fi پس از یک اجرای اولیه 'tup'، تصمیم می‌گیریم که -Wall را به متغیری به نام CFLAGS منتقل کنیم. اکنون Tupfile به این شکل درمی‌آید: .nf CFLAGS = -Wall : foreach *.c |> gcc -c %f -o %o $(CFLAGS) |> %B.o .fi اجرای 'tup refactor' باعث می‌شود tup فایل Tupfile را تجزیه کند و در صورت وجود اشتباه، پیام خطا نمایش داده خواهد شد. سپس می‌توان Tupfileها را برای رفع این خطاها اصلاح کرد و اجرای 'tup refactor' را تا زمانی که تمام Tupfileها با موفقیت تجزیه شوند ادامه داد. خطاها در صورت اضافه یا حذف هر یک از موارد زیر گزارش می‌شوند: دستورها، ورودی‌هایی که فایل‌های تولیدشده هستند، خروجی‌ها، دستورالعمل .gitignore، گروه‌های ورودی یا خروجی، و وابستگی‌های سطح دایرکتوری. در غیر این صورت، تا زمانی که نتیجه نهایی مجموعه قواعد :- یکسان باقی بماند، می‌توانید هر رشته‌ای را به متغیرهای -$، ماکروهای -! و مواردی از این دست انتقال دهید. .TP .B monitor *تنها در لینوکس* پایشگر فایل مبتنی بر inotify را آغاز می‌کند. پایشگر باید یک‌بار سیستم‌فایل را پویش کرده و ردیاب‌ها (watches) را روی هر دایرکتوری مقداردهی اولیه نماید. پس از آن با اعمال تغییرات در فایل‌ها، پایشگر آن‌ها را تشخیص داده و مستقیماً در پایگاه‌داده می‌نویسد. در صورت فعال بودن پایشگر، 'tup' نیازی به پویش اولیه نخواهد داشت و می‌تواند بلافاصله شروع به ساخت گراف وابستگی کند. زمان پویش سیستم‌فایل در 'tup' تقریباً معادل زمانی است که با اجرای پایشگر صرفه‌جویی خواهید کرد. هنگامی که پایشگر در حال اجرا است، اجرای 'tup' در وضعیتی که فایلی تغییر نکرده باشد تنها باید چند میلی‌ثانیه طول بکشد (در سیستم‌های من زمانی که همه چیز در حافظه نهان دیسک باشد حدود ۲ یا ۳ میلی‌ثانیه زمان می‌برد). اگر رایانه خود را بازراه‌اندازی کنید، باید پایشگر را دوباره راه‌اندازی نمایید. آرگومان‌های زیر را می‌توان در خط فرمان مشخص کرد. هر آرگومان دیگری که توسط پایشگر مدیریت نشود، در صورت فعال بودن monitor.autoupdate یا monitor.autoparse به ابزار به‌روزرسان منتقل می‌شود. به عنوان مثال، می‌توانید پایشگر را به صورت 'tup monitor -f -a -j2' اجرا کنید تا در پیش‌زمینه اجرا شود و هنگام تشخیص تغییرات، به طور خودکار با ۲ وظیفه موازی به‌روزرسانی را انجام دهد. همچنین دستور ثانویه option را در ادامه ببینید. .RS .TP .B -d اشکال‌زدایی فرآیند پایشگر را فعال می‌کند. .TP .B -f .PD 0 .TP .B --foreground .PD به طور موقت گزینه monitor.foreground را به 1 تغییر می‌دهد. پایشگر در پیش‌زمینه اجرا خواهد شد (دیمن نمی‌شود). .TP .B -b .PD 0 .TP .B --background .PD به طور موقت گزینه monitor.foreground را به 0 تغییر می‌دهد. پایشگر در پس‌زمینه اجرا خواهد شد (دیمن می‌شود). .TP .B -a .PD 0 .TP .B --autoupdate .PD به طور موقت گزینه monitor.autoupdate را به 1 تغییر می‌دهد. این گزینه هنگام تشخیص تغییرات فایل‌ها، به طور خودکار فرآیند به‌روزرسانی را اجرا می‌کند. .TP .B -n .PD 0 .TP .B --no-autoupdate .PD به طور موقت گزینه monitor.autoupdate را به 0 تغییر می‌دهد. این کار از اجرای خودکار به‌روزرسانی توسط پایشگر هنگام تشخیص تغییرات فایل‌ها جلوگیری می‌کند. .TP .B --autoparse .PD 0 .TP .B --autoparse .PD به طور موقت گزینه monitor.autoparse را به 1 تغییر می‌دهد. این گزینه هنگام تشخیص تغییرات فایل‌ها، به طور خودکار تجزیه‌کننده را اجرا می‌کند. .TP .B --no-autoparse .PD به طور موقت گزینه monitor.autoparse را به 0 تغییر می‌دهد. این کار از اجرای خودکار تجزیه‌کننده توسط پایشگر هنگام تشخیص تغییرات فایل‌ها جلوگیری می‌کند. .RE .TP .B stop در صورت در حال اجرا بودن پایشگر، آن را متوقف می‌کند. در واقع شما را از زحمت یافتن شناسه فرآیند (PID) و پایان دادن به آن بی‌نیاز می‌سازد. .TP .B variant foo.config [bar.config] [...] به ازای هر آرگومان، این دستور یک دایرکتوری variant با پیوند نمادین (symlink) از tup.config به فایل پیکربندی مشخص‌شده ایجاد می‌کند. برای مثال، اگر یک دایرکتوری حاوی چند پیکربندی متغیر باشد، می‌توان به سادگی برای هر فایل پیکربندی یک variant ساخت: .nf $ ls configs/ bar.config foo.config $ tup variant configs/*.config tup: Added variant 'build-bar' using config file 'configs/bar.config' tup: Added variant 'build-foo' using config file 'configs/foo.config' .fi این معادل دستورهای زیر است: .nf $ mkdir build-bar $ ln -s ../configs/bar.config build-bar/tup.config $ mkdir build-foo $ ln -s ../configs/foo.config build-foo/tup.config .fi برای پروژه‌هایی که معمولاً از چندین حالت variant استفاده می‌کنند، فایل‌های موجود در دایرکتوری configs/ را می‌توان در سامانه کنترل نسخه ثبت کرد. هر توسعه‌دهنده در طول checkout اولیه نرم‌افزار، پس از 'tup init' دستور 'tup variant' را اجرا می‌کند. این گونه‌ها (variants) را می‌توان به صورت دستی نیز با ساخت یک دایرکتوری ساخت و ایجاد فایل tup.config درون آن ایجاد کرد (بخش VARIANTS را ببینید). این دستور صرفاً به صرفه‌جویی در چند مرحله کمک می‌کند تا نیازی به ساخت دستی هر دایرکتوری ساخت و پیوند نمادین tup.config نباشد. .TP .B dbconfig پیکربندی فعلی پایگاه‌داده tup را نمایش می‌دهد. این مقادیر داخلی توسط tup مورد استفاده قرار می‌گیرند. .TP .B options تمام گزینه‌های کنونی tup و همچنین منشأ تعیین آنها را نمایش می‌دهد. برای اطلاع از جزئیات تمام گزینه‌های موجود و نحوه تنظیم آنها، بخش \fBOPTIONS FILES\fR را در ادامه ببینید. .TP .B graph [--dirs] [--ghosts] [--env] [--combine] [--stickies] [ ... ] گرافی از پایگاه‌داده tup را با قالب .dot ابزار graphviz در خروجی استاندارد چاپ می‌کند. به طور پیش‌فرض فقط بخش‌هایی از گراف را که دارای تغییر هستند نمایش می‌دهد. اگر آرگومان‌های دیگری مشخص کنید، به عنوان فایل‌هایی که می‌خواهید برای آن‌ها گراف ترسیم شود در نظر گرفته می‌شوند. این دستور مستقیماً روی پایگاه‌داده tup عمل می‌کند، بنابراین مگر در حالتی که پایشگر فایل فعال باشد، بهتر است ابتدا دستور 'tup scan' را اجرا کنید. این مورد عموماً برای اشکال‌زدایی tup استفاده می‌شود -- ممکن است برای مشاهده ساختار برنامه شما نیز مفید باشد یا نباشد. .RS .TP .B --dirs به طور موقت گزینه graph.dirs را روی '1' بازنویسی می‌کند. این کار گره‌های دایرکتوری و Tupfileها را نمایش می‌دهد. .TP .B --ghosts به طور موقت گزینه graph.ghosts را روی '1' بازنویسی می‌کند. این کار گره‌های شبح (فایل‌هایی که یک دستور تلاش کرده به آن‌ها دسترسی پیدا کند اما وجود ندارند) را نشان می‌دهد. .TP .B --env به طور موقت گزینه graph.environment را روی '1' بازنویسی می‌کند. این کار متغیرهای محیطی نظیر PATH را نشان می‌دهد. .RE .TP .B todo [ ... ] مراحل بعدی فرآیند tup را که هنگام به‌روزرسانی خروجی‌های مشخص‌شده اجرا خواهند شد، چاپ می‌کند. اگر خروجی مشخص نشود، مراحل مورد نیاز برای به‌روزرسانی کل پروژه را نمایش می‌دهد. همانند دستور 'upd'، دستور 'todo' نیز در صورتی که پایشگر فایل اجرا نشده باشد، به طور خودکار پروژه را برای یافتن تغییرات فایل پویش می‌کند. .RS .TP .B --no-scan پروژه را برای یافتن فایل‌های تغییریافته پویش نمی‌کند. این گزینه فقط برای آزمایش‌های داخلی tup است و نباید در توسعه معمول استفاده شود. .TP .B --verbose باعث می‌شود tup به جای نمایش رشته ساده‌شده، رشته کامل دستور را برای دستوراتی که از پیشوند ^ TEXT^ استفاده می‌کنند، نمایش دهد. .RE .TP .B generate [--config config-file] [--builddir directory] script.sh (or script.bat on Windows) [ ... ] دستور generate تمام Tupfileها را تجزیه کرده و یک اسکریپت شل ایجاد می‌کند که می‌تواند برنامه را بدون نیاز به اجرا در محیط tup بسازد. کاربرد مورد انتظار آن در محیط‌های یکپارچه‌سازی مداوم (CI) است که با سازوکار بررسی وابستگی‌های tup سازگار نیستند (برای مثال، اگر FUSE پشتیبانی نشود). در ویندوز، اگر نام فایل اسکریپت دارای پسوند ".bat" باشد، خروجی به جای اسکریپت شل یک batch script خواهد بود. برای مثال: .nf git clone ... myproj cd myproj tup generate build.sh \&./build.sh # Copy out build artifacts / logs here git clean -f -x -d .fi اسکریپت شل به صورت افزایشی (incremental) کار نمی‌کند، بنابراین عملاً یک‌بار مصرف است. پیش از فراخوانی بعدی 'tup generate' و اجرای اسکریپت، باید درخت فایل‌ها را پاک‌سازی کنید. به طور پیش‌فرض، فایل tup.config در بالاترین سطح برای تعریف متغیرهای پیکربندی استفاده می‌شود. به صورت اختیاری، یک فایل پیکربندی جداگانه می‌تواند با آرگومان --config ارسال شود. اگر آرگومان --builddir مشخص شود، اسکریپت شل طوری تولید می‌شود که گویی یک ساخت variant است. تمام مصنوعات ساخت در دایرکتوری مشخص‌شده قرار می‌گیرند. در غیر این صورت، رفتار پیش‌فرض این است که تمام مصنوعات ساخت درون خود درخت قرار گیرند. دایرکتوری ساخت نباید از قبل در درخت وجود داشته باشد. پس از نام اسکریپت، می‌توان فایل‌های خروجی مجزا را مشخص کرد تا دامنه اسکریپت شل تنها به ساخت آن خروجی‌ها محدود شود. اگر خروجی مشخص نشود، اسکریپت شل تمام خروجی‌ها را خواهد ساخت. .RE.TP .B compiledb دستور compiledb یک فایل compile_commands.json برای استفاده در ابزارهای شخص ثالث که از این فایل به عنوان مرجعی برای تعیین نحوهٔ کامپایل فایل‌ها بهره می‌برند، ایجاد می‌کند. این فایل در بالاترین سطح سلسله‌مراتب tup ساخته می‌شود، یا اگر از variantها استفاده می‌کنید، هر variant یک compile_commands.json اختصاصی در ریشهٔ خود خواهد داشت. شما باید فایل‌هایی را که می‌خواهید صادر (export) شوند با پرچم ^j نشانه‌گذاری کنید. به عنوان مثال، می‌توانید پرچم ^j را به فراخوانی‌های کامپایلر خود اضافه کنید: .nf : foreach *.c |> ^j^ gcc -c %f -o %o |> %B.o .fi برنامهٔ tup به‌طور خودکار پیش از تولید پایگاه‌داده، هرگونه Tupfile قدیمی را (معادل 'tup parse') تجزیه می‌کند. با توجه به هزینه و بار پردازشی به‌روزرسانی compile_commands.json در پروژه‌های بزرگ، این فایل هنگام تغییر Tupfileها به‌طور خودکار به‌روزرسانی *نمی‌شود*. هر زمان که نسخهٔ به‌روز را بخواهید، باید 'tup compiledb' را به صورت دستی دوباره اجرا کنید. برای دریافت خودکار آخرین خط فرمان مستقیماً از پایگاه‌داده به جای استفاده از compile_commands.json به عنوان واسطه، دستور 'commandline' را ببینید. همچنین ببینید: https://clang.llvm.org/docs/JSONCompilationDatabase.html .RE .TP .B commandline [ ... ] دستور commandline اطلاعات مورد نیاز برای کامپایل نام‌فایل ارائه‌شده به عنوان آرگومان را چاپ می‌کند. اطلاعات با همان قالب JSON مربوط به فایل compile_commands.json حاصل از 'tup compiledb' در خروجی استاندارد (stdout) چاپ می‌شود. توجه داشته باشید که در مقایسه با دستور compiledb، دستور 'tup commandline' پیش از تلاش برای یافتن دستور، به‌طور خودکار Tupfileها را تجزیه نمی‌کند؛ این دستور صرفاً مستقیماً از پایگاه‌داده پرس‌وجو می‌کند. برای مشاهدهٔ نمونه‌ای از نحوهٔ استفاده از این دستور، فایل .ycm_extra_conf.py واقع در ریشهٔ مخزن git برنامهٔ tup را ببینید: https://github.com/gittup/tup .RE .TP .B varsed دستور varsed به عنوان یک زیربرنامه در یک Tupfile استفاده می‌شود؛ نباید آن را دستی در خط فرمان اجرا کنید. این دستور برای خواندن یک فایل، جایگزینی هرگونه ارجاع به متغیرها و نوشتن خروجی در یک فایل دوم به کار می‌رود. ارجاعات متغیر به شکل @VARIABLE@ هستند و با مقدار متناظر @-variable جایگزین می‌شوند. برای نمونه، اگر foo.txt حاوی متن زیر باشد: .nf The architecture is set to @ARCH@ .fi و شما یک قاعدهٔ :- در Tupfile داشته باشید به این صورت: .nf : foo.txt |> tup varsed %f %o |> foo-out.txt .fi آنگاه در هنگام به‌روزرسانی، فایل خروجی همسان با فایل ورودی خواهد بود، به جز رشتهٔ @ARCH@ که با مقدار تنظیم‌شده برای CONFIG_ARCH در tup.config جایگزین خواهد شد. دستور varsed به‌طور خودکار وابستگی از CONFIG_ARCH به گرهٔ دستوری خاصی که از آن استفاده کرده است را اضافه می‌کند (بنابراین اگر CONFIG_ARCH تغییر کند، فایل خروجی با مقدار جدید به‌روزرسانی خواهد شد). .TP .B scan شما هرگز نباید نیازی به اجرای این دستور داشته باشید، مگر اینکه بخواهید پیش از اجرای 'tup graph'، پایگاه‌داده تغییرات فایل‌سیستم را منعکس کند. اگر ناظر (monitor) در حال اجرا نباشد، scan به‌طور خودکار توسط 'upd' فراخوانی می‌شود. .TP .B upd دستور فرعی قدیمی (Legacy). فراخوانی 'tup upd' معادل فراخوانی سادهٔ 'tup' است. .SH "فایل INI (INI FILE)" دستور tup می‌تواند از هر کجای درخت سورس اجرا شود. این دستور از اطلاعات تمام Tupfileها (بخش \fBTUPFILES\fR را ببینید) و همچنین پایگاه‌دادهٔ پویای خود که در دایرکتوری .tup واقع در ریشهٔ پروژه نگهداری می‌شود، استفاده می‌کند. دایرکتوری .tup می‌تواند به‌طور دستی با دستور 'tup init' ایجاد شود، یا می‌توانید با افزودن یک فایل خالی Tupfile.ini در ریشهٔ مخزن کنترل نسخهٔ پروژه، کاری کنید که به‌طور خودکار اجرا شود. محتویات فایل Tupfile.ini نادیده گرفته می‌شوند. .SH "فایل‌های گزینه‌ها (OPTIONS FILES)" برنامهٔ tup امکان استفاده از فایل‌های پیکربندی متنوعی را فراهم می‌کند. این فایل‌ها بر رفتار tup به عنوان یک برنامه تأثیر می‌گذارند، اما تأثیری بر tup به عنوان یک سامانه ساخت ندارند. به عبارت دیگر، تغییر هر یک از این گزینه‌ها نباید بر نتیجهٔ نهایی یک ساخت موفق اثر بگذارد، بلکه ممکن است بر نحوهٔ رسیدن tup به آن نتیجه اثرگذار باشد (برای مثال، تعداد کارهای کامپایل که به صورت موازی اجرا می‌شوند). گزینه‌ها به ترتیب تقدم و اولویت زیر خوانده می‌شوند: .nf command-line overrides (eg: -j flag passed to 'tup') \&.tup/options file ~/.tupoptions file /etc/tup/options file tup's compiled in defaults .fi در Windows، فایل‌های گزینه‌ها به ترتیب زیر خوانده می‌شوند: .nf command-line overrides \&.tup/options file tup.ini in the Application Data path (usually C:\\ProgramData\\tup\\tup.ini) tup's compiled in defaults .fi برای مشاهدهٔ فهرست دقیق مسیرها در پلتفرم خود، 'tup options' را تایپ کنید. تمامی فایل‌ها از ساختار دستوری مشابه با فرمت .ini استفاده می‌کنند. سرآیند هر بخش درون قلاب‌ها (کروشه‌ها) قرار می‌گیرد، به این صورت: .nf [updater] .fi پس از سرآیند بخش، یک یا چند تعریف متغیر به صورت 'variable = value' قرار می‌گیرد. کامنت‌ها با یک نقطه-ویرگول (;) آغاز شده و تا انتهای خط ادامه می‌یابند. تمامی مقادیر متغیرها می‌توانند به صورت عدد صحیح تنظیم شوند. برای پرچم‌های بولی، "true"/"yes" و "false"/"no" به ترتیب مترادف با 1 و 0 هستند. برای نمونه، اگر فایل .tup/options داشته باشید که شامل موارد زیر باشد: .nf [updater] num_jobs = 2 keep_going = true .fi آنگاه 'tup' به‌طور پیش‌فرض از ۲ کار (job) استفاده خواهد کرد و پرچم updater.keep_going فعال خواهد بود. گزینه‌های فهرست‌شده در زیر به فرم 'section.variable' هستند؛ بنابراین برای تنظیم 'db.sync' شما نیاز به یک بخش '[db]' خواهید داشت که به دنبال آن مثلاً 'sync = 0' آمده باشد. پیش‌فرض‌های فهرست‌شده در اینجا، پیش‌فرض‌های زمان کامپایل (درون‌ساخت) هستند. .RS .TP .B db.sync (پیش‌فرض '1') اگر ویژگی synchronous مربوط به SQLite فعال باشد، روی '1' تنظیم می‌شود. هنگامی که فعال باشد، پایگاه‌داده به درستی با دیسک همگام‌سازی می‌شود به گونه‌ای که همواره سازگار و یکپارچه باقی می‌ماند. هنگامی که غیرفعال باشد، برنامه سریع‌تر اجرا می‌شود زیرا عملیات نوشتن برای مدتی پیش از تخلیه روی دیسک در حافظهٔ نهان می‌ماند. با این حال، اگر رایانهٔ شما پیش از نوشته شدن کامل اطلاعات دچار کرش شود، ممکن است پایگاه‌دادهٔ tup خراب شود. برای اطلاعات بیشتر http://www.sqlite.org/pragma.html را ببینید. .TP .B updater.num_jobs (پیش‌فرض برابر با تعداد پردازنده‌های سیستم) روی بیشینهٔ تعداد دستوراتی که tup به‌طور هم‌زمان اجرا خواهد کرد تنظیم می‌شود. پیش‌فرض به‌طور پویا بر اساس تعداد پردازنده‌های موجود در سیستم تعیین می‌شود. اگر updater.num_jobs بزرگ‌تر از 1 باشد، دستورات تنها در صورتی به صورت موازی اجرا می‌شوند که مستقل از یکدیگر باشند. همچنین گزینهٔ -j را ببینید. .TP .B updater.keep_going (پیش‌فرض '0') روی '1' تنظیم کنید تا حتی در صورت بروز خطا، فرایند ساخت تا جای ممکن ادامه یابد. هر چیزی که وابسته به یک دستور شکست‌خورده باشد اجرا نخواهد شد، اما سایر دستورات مستقل اجرا می‌شوند. پیش‌فرض '0' است که باعث می‌شود tup پس از نخستین دستور شکست‌خورده متوقف شود. همچنین گزینهٔ -k را ببینید. .TP .B updater.full_deps (پیش‌فرض '0') روی '1' تنظیم کنید تا وابستگی‌ها به فایل‌های خارج از سلسله‌مراتب tup نیز ردگیری شوند. پیش‌فرض '0' است که تنها وابستگی‌های درون سلسله‌مراتب tup را ردگیری می‌کند. برای نمونه، اگر می‌خواهید با به‌روزرسانی gcc در سیستم، تمامی فایل‌های C دوباره کامپایل شوند، باید این مقدار را روی '1' قرار دهید. در Linux و OSX، استفاده از وابستگی‌های کامل مستلزم این است که باینری tup دارای دسترسی suid به عنوان کاربر root باشد تا بتواند زیرفرایندها را در محیط chroot اجرا کند. همچنین در Linux، اگر هستهٔ شما از user namespaces پشتیبانی کند، نیازی به suid کردن باینری نخواهید داشت. توجه داشته باشید که اگر این مقدار از '0' به '1' تغییر کند، tup کل پروژه را دوباره خواهد ساخت. غیرفعال کردن این گزینه در صورتی که قبلاً فعال بوده باشد، نیازی به بازسازی کامل ندارد اما مدتی زمان می‌برد، چرا که گره‌های نمایانگر فایل‌های خارجی پاک‌سازی می‌شوند. توجه: این قابلیت در حال حاضر به دلیل مسائل مربوط به قفل‌گذاری، با ccache یا سایر برنامه‌هایی که ممکن است در فایل‌های خارجی بنویسند کار نمی‌کند. این موضوع ممکن است در آینده رفع شود. .TP .B updater.warnings (پیش‌فرض '1') روی '0' تنظیم کنید تا هشدارهای مربوط به نوشتن در فایل‌های پنهان غیرفعال شوند. tup فایل‌های پنهان را ردگیری نمی‌کند. اگر یک زیرفرایند در فایلی پنهان بنویسد، tup به‌طور پیش‌فرض هشداری مبنی بر ایجاد این فایل نمایش می‌دهد. با غیرفعال کردن این گزینه، این هشدارها نمایش داده نمی‌شوند. نام فایل‌ها (یا دایرکتوری‌های) پنهان شامل موارد زیر است: .، ..، .tup، .git، .hg، .bzr، .svn. .TP .B display.color (پیش‌فرض 'auto') روی 'never' تنظیم کنید تا کدهای فرار ANSI برای خروجی رنگی غیرفعال شوند، یا روی 'always' تنظیم کنید تا همواره از کدهای فرار ANSI برای خروجی رنگی استفاده شود. مقدار پیش‌فرض 'auto' است که اگر خروجی استاندارد (stdout) به یک tty متصل باشد از خروجی رنگی استفاده می‌کند و در غیر این صورت رنگی به کار نمی‌برد (یعنی اگر خروجی استاندارد به یک فایل هدایت شده باشد). .TP .B display.width (پیش‌فرض برابر با عرض ترمینال) برای اعمال یک عرض ثابت برای نوار پیشرفت، آن را روی هر عدد ۱۰ یا بزرگ‌تر تنظیم کنید. این مقدار به عنوان عرض کل در نظر گرفته می‌شود که بخشی از آن برای فاصله‌گذاری، قلاب‌ها و درصد پیشرفت استفاده می‌شود. اگر این مقدار کمتر از ۱۰ باشد، نوار پیشرفت غیرفعال می‌شود. .TP .B display.progress (پیش‌فرض '1' در صورتی که stdout یک TTY باشد) روی '1' تنظیم کنید تا نوار پیشرفت فعال شود، یا '0' برای خاموش کردن آن. به‌طور پیش‌فرض اگر خروجی استاندارد یک TTY باشد فعال و اگر خروجی استاندارد TTY نباشد غیرفعال است. .TP .B display.job_numbers (پیش‌فرض '1') روی '0' تنظیم کنید تا از نمایش رشتهٔ "N) " پیش از نتایج یک کار جلوگیری شود. حالت پیش‌فرض نمایش این شماره است. .TP .B display.job_time (پیش‌فرض '1') روی '0' تنظیم کنید تا از نمایش زمان اجرای کار در کنار نتایج خودداری شود. حالت پیش‌فرض نمایش زمان اجرا است. توجه داشته باشید زمان اجرای نمایش‌داده‌شده شامل زمانی است که tup برای ذخیرهٔ وابستگی‌ها صرف می‌کند. بنابراین، این زمان اجرا احتمالاً بیشتر از زمان اجرای دستی همان کار در شل خواهد بود. .TP .B display.quiet (پیش‌فرض '0') روی '1' تنظیم کنید تا از نمایش بخش عمدهٔ خروجی توسط tup جلوگیری شود. tup همچنان بنر و خروجی مربوط به هر کاری را که در stdout/stderr می‌نویسد، یا هر کاری را که کد خروج غیرصفر بازمی‌گرداند، نمایش خواهد داد. نوار پیشرفت همچنان نمایش داده می‌شود؛ همچنین display.progress را برای خروجی کاملاً بی‌صدا ببینید. .TP .B monitor.autoupdate (پیش‌فرض '0') روی '1' تنظیم کنید تا در صورت تشخیص تغییر در فایل‌ها، بازسازی به‌طور خودکار انجام شود. این مورد تنها در صورتی اثرگذار است که ناظر (monitor) در حال اجرا باشد. مقدار پیش‌فرض '0' است، به این معنی که هر زمان آمادهٔ به‌روزرسانی بودید باید 'tup' را تایپ کنید. .TP .B monitor.autoparse (پیش‌فرض '0') روی '1' تنظیم کنید تا در صورت تشخیص تغییر در فایل‌ها، تجزیه‌کننده به‌طور خودکار اجرا شود. این مورد مشابه monitor.autoupdate است، با این تفاوت که به‌روزرسانی پس از مرحلهٔ تجزیه متوقف می‌شود و تا زمانی که به‌طور دستی 'tup' را تایپ نکنید هیچ دستوری اجرا نمی‌شود. این گزینه تنها زمانی اثر دارد که monitor در حال اجرا باشد. توجه داشته باشید که اگر هر دو گزینهٔ autoupdate و autoparse تنظیم شده باشند، autoupdate اولویت خواهد داشت. .TP .B monitor.foreground (پیش‌فرض '0') روی '1' تنظیم کنید تا ناظر در پیش‌زمینه اجرا شود؛ به این ترتیب کنترل تا زمانی که ناظر متوقف نشود به ترمینال برنمی‌گردد (چه از طریق ctrl-C در ترمینال جاری، چه با اجرای 'tup stop' در یک ترمینال دیگر). پیش‌فرض '0' است که یعنی ناظر در پس‌زمینه اجرا خواهد شد. .TP .B graph.dirs (پیش‌فرض '0') روی '1' تنظیم کنید تا دستور 'tup graph' گره‌های دایرکتوری و پیوندهای مالکیت آن‌ها را نمایش دهد. Tupfileها نیز نمایش داده می‌شوند، چرا که به گره‌های دایرکتوری اشاره دارند. به‌طور پیش‌فرض دایرکتوری‌ها و Tupfileها نمایش داده نمی‌شوند زیرا در برخی موارد می‌توانند گراف را شلوغ کنند و همیشه مفید نیستند. .TP .B graph.ghosts (پیش‌فرض '0') روی '1' تنظیم کنید تا گره‌های شبح (ghost nodes) نمایش داده شوند. برخی دستورها ممکن است تلاش کنند فایل‌های ناموجود متعددی را بخوانند که باعث ایجاد گره‌های شبح می‌شود. به‌طور پیش‌فرض، شبح‌ها نمایش داده نمی‌شوند تا درک گراف ساده‌تر باشد. .TP .B graph.environment (پیش‌فرض '0') روی '1' تنظیم کنید تا گره‌های محیطی (مانند PATH) و وابستگی‌های آن‌ها نمایش داده شوند. به‌طور پیش‌فرض متغیرهای محیطی نمایش داده نمی‌شوند زیرا تقریباً همه چیز به PATH وابسته خواهد بود. .TP .B graph.combine (پیش‌فرض '0') روی '1' تنظیم کنید تا سعی شود گره‌های مشابه در گراف با یکدیگر ترکیب شوند. به عنوان مثال، به جای نمایش ۱۰ دستور کامپایل مجزا که همگی یک ورودی فایل .c و یک خروجی فایل .o دارند، این گزینه آن‌ها را در قالب یک دستور ادغام می‌کند تا دیدن ساختار کلی گراف آسان‌تر شود. به‌طور پیش‌فرض تمام گره‌ها به صورت جداگانه نمایش داده می‌شوند. .RE.SH "فایل‌های تپ (TUPFILES)" هر جا در سلسله‌مراتب tup که می‌خواهید بر اساس فایل‌های ورودی یک فایل خروجی ایجاد کنید، باید فایلی به نام «Tupfile» ایجاد نمایید. فایل‌های ورودی می‌توانند در هر جای دیگری از سلسله‌مراتب tup قرار داشته باشند، اما فایل(های) خروجی باید در همان دایرکتوری Tupfile نوشته شوند. .TP .B : [foreach] [inputs] [ | order-only inputs] |> command |> [outputs] [ | extra outputs] [] [{bin}] قواعد : (یا :-rules) ابزار اصلی برای ایجاد دستورها هستند و با قرار گرفتن نویسهٔ «:» در ستون اول Tupfile مشخص می‌شوند. نحوِ دستور به‌گونه‌ای طراحی شده که شبیه یک خط‌لوله (pipeline) به نظر برسد؛ به این صورت که فایل‌های ورودی در سمت چپ وارد دستورِ میانی شده و فایل‌های خروجی در سمت راست تولید می‌شوند. .RS .TP .B foreach این بخش یا شامل رشتهٔ دقیق «foreach» است و یا خالی رها می‌شود. تفاوت در تعداد دستورهایی است که هنگام وجود چندین فایل ورودی تولید می‌شوند. اگر «foreach» مشخص شده باشد، برای هر فایل در بخش inputs یک دستور جداگانه ایجاد می‌شود. اگر مشخص نشده باشد، تنها یک دستور شامل تمام فایل‌های موجود در بخش inputs ایجاد خواهد شد. برای مثال، دو Tupfile زیر معادل یکدیگر هستند: .nf # Tupfile 1 : foo.c |> gcc -c foo.c -o foo.o |> foo.o : bar.c |> gcc -c bar.c -o bar.o |> bar.o # Tupfile 2 : foreach foo.c bar.c |> gcc -c %f -o %o |> %B.o .fi علاوه بر این، استفاده از «foreach» امکان استفاده از پرچم «%e» را نیز فراهم می‌کند (به ادامه مراجعه کنید). .TP .B inputs فایل‌های ورودی برای دستور. یک فایل ورودی می‌تواند در هر کجای سلسله‌مراتب tup قرار داشته باشد و به صورت نسبی نسبت به دایرکتوری جاری مشخص می‌شود. فایل‌های ورودی بر پرچم‌های % (به ادامه مراجعه کنید) تأثیر می‌گذارند. تطبیق الگو (wildcarding) درون یک دایرکتوری با استفاده از تابع glob مربوط به SQLite پشتیبانی می‌شود. نویسه‌های ویژهٔ glob عبارت‌اند از «*»، «?» و «[]». برای مثال، «*.c» با هر فایل .c تطبیق داده می‌شود، «fo?.c» با هر فایل سه‌نویسه‌ای .c که دو نویسه اول آن «f» و «o» باشند مطابقت دارد، و «fo[xyz].c» با fox.c، foy.c و foz.c تطبیق می‌یابد. الگوهای glob دایرکتوری‌ها را تطبیق نمی‌دهند، بنابراین «src/*.c» کار خواهد کرد، اما «*/*.c» کار نخواهد کرد. هر ورودی که با «^» آغاز شود، به عنوان یک عبارت منظم سازگار با پرل برای مستثنی کردن فایل‌هایی که در یک glob قبلی مطابقت یافته بودند در نظر گرفته می‌شود. برای مثال، می‌توانید تمام فایل‌های *.c به جز main.c را با قطعه‌کد زیر کامپایل کنید: .nf : foreach *.c ^main.c |> ... |> .fi این استثناهای ورودی در زمان تجزیه (parser time) پردازش می‌شوند و از استثناهای وابستگی در بخش خروجی‌ها (outputs) متمایز هستند. .TP .B order-only inputs این‌ها نیز به عنوان ورودی برای دستور استفاده می‌شوند، اما در هیچ‌یک از پرچم‌های % به جز %i ظاهر نخواهند شد. آن‌ها با استفاده از نویسهٔ «|» از ورودی‌های معمولی جدا می‌شوند. در عمل، می‌توان از این‌ها برای مشخص کردن ورودی‌های اضافی به دستوری استفاده کرد که نباید در خط فرمان ظاهر شوند. الگوهای glob همانند بخش inputs پشتیبانی می‌شوند. برای مثال، یک کاربرد آن‌ها تعیین وابستگی‌های هدر خودکار تولید شده است: .nf : |> echo "#define FOO 3" > %o |> foo.h : foreach foo.c bar.c | foo.h |> gcc -c %f -o %o |> %B.o .fi این کار وابستگی foo.h را به دستورهای gcc برای foo.c و bar.c اضافه می‌کند، تا tup بداند که قبل از تلاش برای کامپایل، هدر را تولید کند. دستور foreach بر روی ورودی‌های معمولی (اینجا foo.c و bar.c) پیمایش می‌کند، نه بر روی ورودی‌های فقط-ترتیب (order-only inputs مانند foo.h). اگر اضافه کردن چنین وابستگی را فراموش کنید، tup هنگام اجرای دستور خطایی را گزارش می‌کند. توجه داشته باشید که وابستگی foo.h فقط به این دلیل در اینجا فهرست شده که توسط دستور دیگری ساخته می‌شود -- نیازی به تعیین هدرهای معمولی نیست. .TP .B command رشتهٔ دستوری که توسط tup به فراخوانی system(3) ارسال می‌شود. این دستور مجاز است از هر فایلی که به عنوان ورودی یا ورودی فقط-ترتیب مشخص شده، و همچنین هر فایل دیگری در سلسله‌مراتب tup که خروجی دستور دیگری نباشد، بخواند. به عبارت دیگر، یک دستور نمی‌تواند از خروجی دستور دیگری بخواند مگر اینکه به عنوان ورودی مشخص شده باشد. این محدودیت چیزی است که امکان اجرای موازی ایمن (parallel safe) را به tup می‌دهد. علاوه بر این، دستور باید در تمام فایل‌های خروجی مشخص‌شده در بخش «outputs» (در صورت وجود) بنویسد. .IP هنگام اجرا، دسترسی‌های فایلِ دستور توسط tup نظارت می‌شوند تا اطمینان حاصل شود که از این قوانین پیروی می‌کنند. هر فایلی که برای خواندن باز شود و از دستور دیگری تولید شده باشد اما به عنوان ورودی مشخص نشده باشد، به عنوان خطا گزارش می‌شود. به همین ترتیب، هر فایلی که برای نوشتن باز شود و به عنوان خروجی مشخص نشده باشد، به عنوان خطا گزارش می‌شود. تمام فایل‌های باز شده برای خواندن به عنوان وابستگی‌های دستور ثبت می‌شوند. اگر هر یک از این فایل‌ها تغییر کند، tup در به‌روزرسانی بعدی دستور را دوباره اجرا خواهد کرد. توجه داشته باشید که اگر ورودیِ فهرست‌شده در Tupfile تغییر کند، لزوماً باعث اجرای مجدد دستور نمی‌شود، مگر اینکه دستور در طول اجرای قبلی واقعاً از آن ورودی خوانده باشد. ورودی‌های فهرست‌شده در Tupfile فقط ترتیب بین دستورها را اعمال می‌کنند، در حالی که دسترسی‌های فایل در حین اجرا مشخص می‌کنند چه زمانی دستورها دوباره اجرا شوند. .IP یک رشتهٔ دستور می‌تواند با توالی ویژهٔ ^\ TEXT^ شروع شود، که به tup می‌گوید هنگام اجرای دستور فقط «TEXT» را به جای کل رشتهٔ دستور چاپ کند. این کار زحمت استفاده از echo را برای چاپ زیبای یک دستور طولانی کاهش می‌دهد. رفتار نمایش کوتاه را می‌توان با دادن پرچم --verbose به tup لغو کرد، که باعث می‌شود tup رشتهٔ واقعی دستور را به جای «TEXT» نمایش دهد. فاصلهٔ بعد از اولین «^» حائز اهمیت است. هر نویسه‌ای بلافاصله پس از اولین «^» به عنوان پرچم در نظر گرفته می‌شود. برای جزئیات به بخش پرچم‌های ^ در ادامه مراجعه کنید. برای مثال، این دستور هنگام اجرای system(gcc -c foo.c -o foo.o) عبارت «CC foo.c» را چاپ خواهد کرد: .nf : foo.c |> ^ CC %f^ gcc -c %f -o %o |> foo.o .fi .IP یک رشتهٔ دستور می‌تواند با نویسهٔ ویژهٔ «!» نیز آغاز شود، که در این حالت ماکروی ! مشخص‌شده جایگزین دستور واقعی می‌شود. تعریف ماکروهای ! را در ادامه ببینید. دستورها می‌توانند خالی نیز باشند، که برای قرار دادن تمام فایل‌های ورودی در یک {bin} برای استفاده در یک قاعدهٔ بعدی کاربرد دارد. .TP .B outputs بخش خروجی‌ها (outputs) فایل‌هایی را مشخص می‌کند که توسط دستور در آن‌ها نوشته خواهد شد. تنها یک دستور می‌تواند در یک فایل خاص بنویسد، اما یک دستور واحد می‌تواند چندین فایل خروجی تولید کند (همانند دستوری در bison که هم یک فایل .c و هم یک فایل .h تولید می‌کند). خروجی می‌تواند از هر پرچم % به جز %o استفاده کند. به محض اینکه فایلی در بخش خروجی مشخص شود، در پایگاه‌دادهٔ tup قرار می‌گیرد. هر قاعدهٔ بعدی می‌تواند از آن فایل به عنوان ورودی استفاده کند، حتی اگر هنوز در سیستم‌فایل وجود نداشته باشد. خروجی‌هایی که با «^» شروع می‌شوند برای نادیده گرفتن وابستگی‌ها به فایل‌ها به کار می‌روند. این استثناها عبارات منظم سازگار با پرل هستند که در پایگاه‌داده ذخیره می‌شوند. هر فایلی که در زمان اجرای زیرپروسه خوانده یا در آن نوشته شود و با این الگوها مطابقت داشته باشد، توسط tup نادیده گرفته می‌شود. برای مثال، اگر کامپایلر شما در یک «license_file.txt» می‌نویسد، می‌توانید به tup دستور دهید خطاهای وابستگی این فایل را به این صورت نادیده بگیرد: .nf : foreach *.c |> ... |> %B.o ^license_file.txt .fi توجه داشته باشید که این کار همچنین به tup دستور می‌دهد وابستگی‌های ورودی به این فایل را نیز نادیده بگیرد. اگر فقط می‌خواهید فایل‌ها را در یک glob نادیده بگیرید، نحو مشابه «^» در بخش inputs را ببینید. نمی‌توان از یک استثنا برای مطابقت با فایلی که توسط همان قاعده تولید شده است (یعنی فایلی که به عنوان خروجی در دستور فهرست شده) استفاده کرد. انجام این کار منجر به خطای «Unable to exclude a generated file» خواهد شد. نادیده گرفتن وابستگی‌ها را تنها باید با احتیاط فراوان انجام دهید. بسیار محتمل است باعث شوید tup در زمانی که باید به‌روزرسانی شود، شکست بخورد؛ زیرا به آن دستور داده شده که وابستگی‌ها را نادیده بگیرد. .TP .B extra-outputs بخش extra-outputs مشابه بخش ورودی‌های فقط-ترتیب (order-only inputs) است. این بخش با نویسهٔ «|» از خروجی‌های معمولی جدا می‌شود. رفتار extra-outputs دقیقاً مانند خروجی‌های معمولی است، با این تفاوت که در پرچم %o ظاهر نمی‌شوند. در صورتی که دستوری فایل‌هایی تولید کند که نام آن‌ها در خط فرمان ظاهر نمی‌شود، می‌توان از این بخش استفاده کرد. اگر دقیقاً یک خروجی توسط قاعده مشخص شده باشد، بخش extra-outputs می‌تواند از پرچم %O برای نمایش نام پایه (basename) خروجی استفاده کند. این ویژگی می‌تواند در extra-outputs برای ماکروهای ! مفید باشد. .TP .B فایل‌های خروجی را می‌توان با مشخص کردن یک پس از خروجی‌ها اما قبل از bin، در گروه‌های سراسری دسته‌بندی کرد. گروه‌ها امکان وابستگی‌های فقط-ترتیب بین پوشه‌ها را فراهم می‌کنند. با این حال، توجه داشته باشید که گروه‌ها مختص دایرکتوری هستند، بنابراین هنگام ارجاع به یک گروه باید مسیر جایی که به آن اختصاص داده شده است را مشخص کنید. برای مثال، اگر یک پروژهٔ اصلی به خروجی چند زیرماژول وابسته باشد، می‌توانید ساختار Tup را به شکل زیر تنظیم کنید تا مطمئن شوید زیرماژول‌ها قبل از پروژهٔ اصلی ساخته می‌شوند: .nf #./submodules/sm1/Tupfile : foo.c |> gcc -c %f -o %o |> %B.o ../ #./submodules/sm2/Tupfile : bar.c |> gcc -c %f -o %o |> %B.o ../ #./project/Tupfile : baz.c | ../submodules/ |> gcc -c %f -o %o |> %B.o .fi توجه کنید که چگونه گروه‌ها مختص دایرکتوری هستند و مسیر در خارج از <> مشخص می‌شود. با تعیین به عنوان ورودی فقط-ترتیب، Tup قبل از اقدام به ساخت کل پروژه، زیرماژول‌ها را خواهد ساخت. .TP .B {bin} خروجی‌ها را می‌توان با استفاده از نحو «{bin}» در یک مخزن (bin) گروه‌بندی کرد. یک قاعدهٔ بعدی می‌تواند از «{bin}» به عنوان ورودی برای استفاده از تمام فایل‌های درون آن مخزن استفاده کند. برای مثال، قاعدهٔ foreach هر فایل .o را در مخزن objs قرار می‌دهد، که سپس به عنوان ورودی در قاعدهٔ پیونددهنده (linker) استفاده می‌شود: .nf : foreach *.c |> gcc -c %f -o %o |> %B.o {objs} : {objs} |> gcc %f -o %o |> program .fi .IP در این حالت می‌توان به جای آن از *.o به عنوان ورودی استفاده کرد، اما گاهی اوقات تفکیک خروجی‌ها به گروه‌های مختلف مفید است، حتی اگر پسوند یکسانی داشته باشند (مثلاً اگر یک دایرکتوری چندین فایل اجرایی ایجاد کند، استفاده از *.o درست نخواهد بود). اگر یک {bin} در بخش خروجیِ چندین قاعده مشخص شده باشد، bin حاصل اجتماع تمام آن خروجی‌ها خواهد بود. نمی‌توان موردی را از یک bin حذف کرد، و bin پس از تجزیهٔ Tupfile جاری ناپدید می‌شود. .RE .TP .B ^-flags در رشتهٔ دستوری که از توالی ^\ TEXT^ استفاده می‌کند، نویسه‌های پرچم می‌توانند بلافاصله پس از ^ تا اولین نویسهٔ فاصله یا علامت توان پایانی قرار گیرند. برای مثال: .nf : foo.c |> ^c CC %f^ gcc --coverage %f -o %o |> foo | foo.gcno : bar.c |> ^c^ gcc --coverage %f -o %o |> bar | bar.gcno .fi در مورد foo.c، دستور نیازمند فضاهای نام (namespaces) (یا suid) است و «CC foo.c» را نمایش می‌دهد. در مورد bar.c، دستور نیازمند فضاهای نام (یا suid) است و رشتهٔ «gcc --coverage bar.c -o bar» نمایش داده می‌شود. نویسه‌های پرچم پشتیبانی‌شده عبارت‌اند از: .RS .TP .B b پرچم «b» باعث می‌شود دستور از طریق «/usr/bin/env bash -e -o pipefail -c » به جای حالت پیش‌فرض «/bin/sh -e -c » اجرا شود. علاوه بر امکان استفاده از افزونه‌های bash در قاعدهٔ :، گزینهٔ «-o pipefail» مقرر می‌دارد که «مقدار بازگشتی یک خط‌لوله، مقدار آخرین (راست‌ترین) دستوری است که با وضعیت غیرصفر خارج شده، یا اگر همه دستورات در خط‌لوله با موفقیت خارج شوند، صفر است». .TP .B c پرچم «c» در صورتی که tup از فضاهای نام کاربر (در لینوکس) پشتیبانی نکند یا suid root نباشد، باعث شکست دستور می‌شود. در این حالت‌ها، tup در یک حالت تنزل‌یافته (degraded mode) اجرا می‌شود که در آن دایرکتوری‌های کاری ساختگی در زیرپروسه‌ها قابل مشاهده هستند و ممکن است برخی وابستگی‌ها نادیده گرفته شوند. اگر این رفتارهای تنزل‌یافته باعث شکست دستوری خاص در ساخت شما می‌شود، پرچم «c» را اضافه کنید تا کاربران بدانند که باید بیت suid را اضافه کنند یا هستهٔ سیستم‌عامل خود را ارتقا دهند. این پرچم در ویندوز نادیده گرفته می‌شود. .TP .B j پرچم «j» دستور را برای برون‌بری در دستور «tup compiledb» علامت‌گذاری می‌کند. اگر مایل به استفاده از compile_commands.json هستید، دستورهایی را که می‌خواهید برون‌بری شوند با ^j حاشیه‌نویسی کرده و سپس «tup compiledb» را اجرا نمایید. برای جزئیات بیشتر به دستور compiledb مراجعه کنید. .TP .B o پرچم «o» باعث می‌شود دستور، خروجی‌های جدید را با خروجی‌های اجرای قبلی مقایسه کند. هر خروجی‌ای که یکسان باشد، موجب اجرای دستورهای وابسته در گراف جهت‌دار بدون دور (DAG) نخواهد شد. برای مثال، افزودن این پرچم به یک دستور کامپایل، در صورتی که فایل شیء (object file) نسبت به اجرای قبلی تغییری نکرده باشد، از مرحلهٔ پیوند (linking) صرف‌نظر می‌کند. پرچم «o» با پرچم «t» ناسازگار است. .TP .B s پرچم «s» بافر کردن stdout/stderr را برای زیرپروسه‌ها غیرفعال کرده و «حالت جاری» (streaming mode) را فعال می‌کند. هنگام استریم، stdout/stderr از پروسهٔ tup به ارث برده می‌شوند، بنابراین پیام‌ها معمولاً هنگام اجرای زیرپروسه، به همان ترتیبی که تولید می‌شوند، روی ترمینال نمایش داده خواهند شد. توجه داشته باشید که پروسه‌هایی که 's' برای آن‌ها فعال است ممکن است پیام‌هایشان با یکدیگر و همچنین با نوار پیشرفت tup یا سایر پیام‌های tup تداخل پیدا کند. این پرچم ممکن است برای پروسه‌های طولانی‌مدت که مایلید خروجی را هم‌زمان با وقوع ببینید مفید باشد، هرچند اگر برای دستورهای پر سر و صدای متعددی که به صورت موازی اجرا می‌شوند به کار رود، ممکن است گزارش‌ها را گیج‌کننده کند. به صورت پیش‌فرض، tup پیام‌های یک دستور را بافر می‌کند (برای مثال، پیام‌های هشدار کامپایلر) و پس از تکمیل دستور، آن‌ها را زیر بنر مربوط به آن دستور نمایش می‌دهد. بنابراین پیام‌های دستورهای جداگانه همیشه متمایز بوده و با دستوری که آن‌ها را ایجاد کرده مرتبط هستند. .TP .B t پرچم «t» باعث می‌شود خروجی‌های دستور به صورت گذرا (transient) باشند. خروجی‌ها ممکن است به عنوان ورودی برای دستورهای دیگر استفاده شوند، اما پس از اجرای تمام دستورهای وابسته، خروجی‌های گذرا از سیستم‌فایل حذف خواهند شد. این ویژگی می‌تواند برای صرفه‌جویی در فضا در مواقعی که مراحل پردازش متعددی وجود دارد و هر کدام خروجی‌های بزرگی تولید می‌کنند اما فقط خروجی نهایی باید نگه داشته شود، استفاده شود. پرچم «t» با پرچم «o» ناسازگار است. یک مثال که در آن پرچم «t» در یک خط‌لولهٔ ساخت منطقی است، زمانی است که دارایی‌های بزرگی وجود دارند که چندین مرحله پردازش را طی می‌کنند؛ برای مثال، یک فایل صوتی یا ویدیویی بزرگ که مراحل اعمال جلوه‌ها روی آن، هر کدام به عنوان یک مرحلهٔ مجزا در Tupfile تعریف شده‌اند. در مقابل، پرچم «t» برای فایل‌های شیء در یک برنامهٔ C منطقی *نیست*، حتی اگر از نظر تئوری بتوان آن‌ها را پس از پیوند خوردن فایل اجرایی نهایی حذف کرد. اگر فایل‌های شیء در این مورد به عنوان گذرا علامت‌گذاری شوند، تغییر در هر یک از فایل‌های C ورودی مستلزم ساخت مجدد *همهٔ* فایل‌های شیء برای تولید فایل اجرایی خواهد بود، به جای اینکه فقط همان تک فایلی که تغییر کرده بازسازی شود. .RE .TP .B %-flags درون یک رشتهٔ دستور یا رشتهٔ خروجی، می‌توان از پرچم‌های % زیر برای جایگزینی مقادیر از ورودی‌ها یا خروجی‌ها استفاده کرد. به‌طور کلی، پرچم‌های % به تمام نام‌های فایل در یک فهرست گسترش می‌یابند. برای مثال، %o به تمام فایل‌های خروجی بسط داده می‌شود. برای ارجاع به یک فایل تکی، می‌توانید از %1o، %2o و غیره برای اشاره به اولین، دومین (و به همین ترتیب) نام فایل در فهرست استفاده کنید. .RS .TP .B %% به یک نویسهٔ تکی «%» در رشتهٔ دستور گسترش می‌یابد. این مورد زمانی باید استفاده شود که بخواهید نویسهٔ درصد توسط خودِ دستور تفسیر شود، نه توسط تجزیه‌گر tup. .TP .B %f نام فایل‌ها از بخش «inputs». این شامل مسیر و پسوند می‌شود. این پرچم بیشترین کاربرد را در یک دستور دارد، زیرا نام هر فایل ورودی را با مسیر نسبی به دایرکتوری جاری فهرست می‌کند. برای مثال، «src/foo.c» دقیقاً به صورت «src/foo.c» درج می‌شود. فایل‌های تکی را می‌توان با %1f، %2f و غیره مورد ارجاع قرار داد. .TP .B %i نام فایل‌ها از بخش «order-only inputs». این شامل مسیر و پسوند می‌شود. معمولاً ورودی‌های فقط-ترتیب برای نام فایل‌هایی استفاده می‌شوند که نمی‌خواهید در خط فرمان ظاهر شوند، اما اگر نیاز به ارجاع به آن‌ها داشته باشید، می‌توانید از %i استفاده کنید. فایل‌های تکی را می‌توان با %1i، %2i و غیره ارجاع داد. .TP .B %b مانند %f است، اما فقط نام پایهٔ (basename) فایل است. بخش دایرکتوری حذف می‌شود. برای مثال، «src/foo.c» تبدیل به «foo.c» می‌شود. فایل‌های تکی را می‌توان با %1b، %2b و غیره مورد ارجاع قرار داد. .TP .B %B مانند %b است، اما پسوند را نیز حذف می‌کند. این پرچم بیشترین کاربرد را در تبدیل یک فایل ورودی به یک فایل خروجی با همان نام اما با پسوندی متفاوت دارد، زیرا فایل خروجی باید در همان دایرکتوری باشد. برای مثال، «src/foo.c» تبدیل به «foo» می‌شود. فایل‌های تکی را می‌توان با %1B، %2B و غیره مورد ارجاع قرار داد. .TP .B %e پسوند فایلِ پروندهٔ جاری در هنگام استفاده در یک قاعدهٔ foreach. این پرچم می‌تواند برای متغیرهایی استفاده شود که می‌توانند مقادیر متفاوتی بر اساس پسوند فایل داشته باشند. برای مثال، می‌توانید پرچم‌های خاصی را برای فایل‌های اسمبلی (.S) تنظیم کنید که با فایل‌های .c متفاوت باشند، و سپس از ساختاری مانند $(CFLAGS_%e) برای ارجاع به متغیر CFLAGS_S یا CFLAGS_c بسته به نوع فایلی که کامپایل می‌شود استفاده کنید. برای مثال، «src/foo.c» تبدیل به «c» می‌شود، در حالی که «src/foo.S» تبدیل به «S» خواهد شد. .TP .B %o نام فایل(های) خروجی. این پرچم در یک دستور مفید است تا نام فایل ارسال‌شده به دستور همیشه با آنچه tup به عنوان خروجی می‌داند مطابقت داشته باشد. این مورد فقط در بخش «command» کار می‌کند، نه در بخش «outputs». فایل‌های تکی را می‌توان با %1o، %2o و غیره مورد ارجاع قرار داد. .TP .B %O نام فایل خروجی بدون پسوند. این پرچم تنها در صورتی در بخش extra-outputs کار می‌کند که دقیقاً یک فایل خروجی مشخص شده باشد. کاربرد این مورد زمانی است که ماکرویی با ! دارید که فایل‌هایی تولید می‌کند که در خط فرمان مشخص نشده‌اند، اما بر اساس خروجی نام‌گذاری شده هستند. برای مثال، اگر یک پیونددهنده با گرفتن خروجی مشخص‌شده «foo.so»، حذف «.so» و افزودن «.map» یک فایل نقشه (map file) ایجاد کند، ممکن است ماکروی ! را به این صورت بخواهید: .nf !ldmap = |> ld ... -o %o |> | %O.map : foo1.o foo2.o |> !ldmap |> foo.so .fi .TP .B %d نام پایین‌ترین سطح دایرکتوری. برای مثال، در foo/bar/Tupfile، این رشتهٔ «bar» خواهد بود. یک مورد که می‌تواند مفید باشد، در نام‌گذاری کتابخانه‌ها بر اساس دایرکتوری است که در آن قرار دارند، مانند ماکروی ! زیر: .nf !ar = |> ar crs %o %f |> lib%d.a .fi استفاده از این ماکرو در foo/bar/Tupfile سپس foo/bar/libbar.a را ایجاد خواهد کرد. .TP .B %g رشته‌ای که یک عملگر glob با آن مطابقت یافته است. برای مثال با فایل‌های a_text.txt و b_text.txt، قاعدهٔ: .nf : foreach *_text.txt |> foo %f |> %g_binary.bin .fi نام‌های فایل a_binary.bin و b_binary.bin را خروجی خواهد داد. تنها اولین glob بسط‌یافته جایگزین %g خواهد شد. %g فقط زمانی معتبر است که یک فایل ورودی واحد وجود داشته باشد یا از foreach استفاده شود. .TP .B % تمام فایل‌های موجود در «group». برای مثال: .nf #./submodules/sm1/Tupfile : foo.c |> gcc -c %f -o %o |> %B.o ../ #./submodules/sm2/Tupfile : bar.c |> gcc -c %f -o %o |> %B.o ../ #./project/Tupfile : ../submodules/ |> echo '%f' > %o |> submodules_f.txt : ../submodules/ |> echo '%' > %o |> submodules_group.txt .fi مقدار «../submodules/» را در submodules_f.txt تولید خواهد کرد، اما در submodules_group.txt مقدار «../submodules/sm1/foo.o ../submodules/sm2/bar.o» را تولید می‌کند. اگر ورودی شامل چندین گروه با نام یکسان اما در دایرکتوری‌های متفاوت باشد، % به تمام فایل‌های موجود در هر گروه فهرست‌شده گسترش می‌یابد. .RE .RE.TP .B var = value .PD 0 .TP .B var := value .PD 1 مقدار متغیر-$ با نام "var" را برابر با مقدار سمت راست قرار می‌دهد. هر دو شکل یکسان هستند و برای پشتیبانی آسان‌تر از تبدیل Makefileهای قدیمی مجاز شمرده شده‌اند. بعداً می‌توان با استفاده از "$(var)" به متغیر-$ با نام "var" ارجاع داد. متغیرهای ارجاع‌شده در اینجا همواره بلافاصله بسط می‌یابند. بنابراین، مقداردهی متغیر به‌گونه‌ای که شامل یک پرچم-% باشد بی‌معنی است، زیرا یک پرچم-% تنها در یک قاعده-: معتبر است. نحو $(var_%e) در یک قاعده-: مجاز است. ارجاع‌های متغیر تودرتو نمی‌شوند، بنابراین عبارتی مانند $(var1_$(var2)) بی‌معنی است. همچنین نمی‌توانید تعاریف متغیر را در خط فرمان یا از طریق محیط منتقل کنید. هرگونه ارجاع به متغیری که مقدار آن تعیین نشده باشد، یک رشته خالی بازمی‌گرداند. .nf CFLAGS = -Dfoo : bar.c |> cc $(CFLAGS) $(other) -o %o -c %f |> %B.o .fi در زمان اجرا، دستور "cc -Dfoo -o bar.o -c bar.c" را تولید خواهد کرد. .P هر متغیر-$ که با رشته "CONFIG_" آغاز شود، به‌طور خودکار به متغیر-@ با همان نام منهای پیشوند "CONFIG_" تبدیل می‌شود. به عبارت دیگر، $(CONFIG_FOO) و @(FOO) قابل تعویض با یکدیگرند. تلاش برای انتساب مقدار به یک متغیر CONFIG_ در یک Tupfile منجر به بروز خطا می‌شود، زیرا این متغیرها تنها در فایل tup.config قابل تنظیم هستند. .P توجه داشته باشید که ممکن است هنگام مقداردهی متغیرها با نحوی مواجه شوید که از بک‌تیک‌ها استفاده می‌کند، مانند: .nf CFLAGS += `pkg-config fuse3 --cflags` .fi ابزار tup هیچ‌گونه پردازش ویژه‌ای روی بک‌تیک‌ها انجام نمی‌دهد، بنابراین در این مثال هنگام مقداردهی متغیر، دستور pkg-config واقعاً اجرا نمی‌شود. در عوض، این عبارت عیناً به هر مکانی که از آن استفاده کند منتقل می‌شود. از این رو اگر دستوری بعداً به $(CFLAGS) ارجاع دهد، شامل رشته `pkg-config fuse3 --cflags` خواهد بود و بنابراین توسط پوسته (shell) تجزیه خواهد شد. .TP .B var += value مقدار "value" را به انتهای مقدار فعلی "var" الحاق می‌کند. اگر "var" مقداردهی نشده باشد، این عمل معادل یک عبارت معمولی '=' است. اگر "var" از قبل مقداری داشته باشد، پیش از الحاق مقدار جدید، یک فاصله به متغیر-$ اضافه می‌شود. .TP .B $(TUP_CWD) .PD 0 .TP .B [lua] tup.getcwd() متغیر-$ ویژه TUP_CWD همواره روی مسیر نسبی نسبت به Tupfile که اکنون در حال تجزیه است، تنظیم می‌شود. مقدار آن هنگام include کردن فایلی در یک دایرکتوری دیگر می‌تواند تغییر کند. برای مثال، اگر از "include ../foo.tup" استفاده کنید، آنگاه TUP_CWD هنگام تجزیه foo.tup روی ".." تنظیم خواهد شد. این قابلیت به foo.tup اجازه می‌دهد پرچم‌هایی مانند "CFLAGS += -I$(TUP_CWD)" را مشخص کند و CFLAGS صرف‌نظر از اینکه به صورت "../foo.tup" یا "../../foo.tup" یا "subdir/foo.tup" گنجانده شده باشد، همواره شامل دایرکتوری -I که foo.tup در آن قرار دارد خواهد بود. برای یافتن جایگزینی برای $(TUP_CWD) هنگام ارجاع به فایل‌ها، بخش مربوط به متغیرهای-& در زیر را ببینید. .TP .B $(TUP_VARIANTDIR) .PD 0 .TP .B [lua] tup.getvariantdir() مشابه $(TUP_CWD)، متغیر $(TUP_VARIANTDIR) نیز روی مسیر نسبی نسبت به Tupfile در حال تجزیه تنظیم می‌شود، اما به دایرکتوری متناظر در variant اشاره می‌کند. به‌عنوان مثالی از کاربرد این قابلیت، فرض کنید فرآیند ساخت شما هدرهای مشترک را در دایرکتوری با نام "include/" تولید می‌کند. یک فایل Tuprules.tup در سطح همان دایرکتوری می‌تواند -I$(TUP_VARIANTDIR) را به یک متغیر پرچم‌های کامپایلر اضافه کند. در صورت استفاده از یک variant، این مقدار به مسیری مانند "../build/path/to/include" ارزیابی می‌شود که در آن "build" نام دایرکتوری variant است. اگر از variantها استفاده نشود، TUP_VARIANTDIR معادل TUP_CWD خواهد بود. .TP .B $(TUP_VARIANT_OUTPUTDIR) .PD 0 .TP .B [lua] tup.getvariantoutputdir() متغیر $(TUP_VARIANT_OUTPUTDIR) همواره به دایرکتوری خروجی متناظر با variantای که اکنون در حال تجزیه است اشاره می‌کند. برخلاف $(TUP_VARIANTDIR)، هنگام گنجاندن فایل دیگری مانند Tuprules.tup یا سایر فایل‌های جزئی *.tup تغییر نمی‌کند. بدون استفاده از variantها، این مقدار همواره برای اشاره به دایرکتوری جاری به رشته "." ارزیابی می‌شود. .P هنوز هیچ متغیر-$ ویژه دیگری وجود ندارد، اما برای رعایت جانب احتیاط باید فرض کنید که تمام متغیرهای با نام *TUP_ رزرو شده‌اند. .TP .B &var = file .PD 0 .TP .B &var := file .PD 0 .TP .B &var += file .PD 1 متغیر-& را برای ارجاع به فایل یا دایرکتوری مشخص‌شده تنظیم می‌کند. این فایل باید یک فایل معمولی باشد، نه یک فایل تولیدشده (یک خروجی از یک قاعده-:). متغیرهای-& به شیوه‌ای مشابه $(TUP_CWD) برای ارجاع به فایل‌ها استفاده می‌شوند، با این تفاوت که به جای ذخیره مسیر نسبی به فایل، متغیرهای-& شناسه داخلی فایل در tup را ذخیره می‌کنند. این بدان معناست که مسیر نسبی به فایل زمانی تعیین می‌شود که متغیر-& به کار می‌رود، نه در زمان انتساب متغیر همانند آنچه در $(TUP_CWD) رخ می‌دهد. متغیرهای-& تنها در مکان‌های زیر قابل استفاده هستند: ورودی‌های قاعده-:، ورودی‌های فقط-ترتیبی (order-only) قاعده-:، دستورهای قاعده-:، خطوط include و خطوط run-script؛ و بعداً می‌توان با استفاده از "&(var)" به آن‌ها ارجاع داد. .nf # Tuprules.tup &libdir = src/lib !cc = |> cc -I&(libdir) -c %f -o %o |> %B.o # src/lib/Tupfile : foreach *.c |> !cc |> : *.o |> ar crs %o %f |> libstuff.a # src/lib/test/Tupfile : test_stuff.c |> !cc |> : test_stuff.o &(libdir)/libstuff.a |> cc -o %o %f |> test_stuff # src/Tupfile : main.c |> !cc |> main.o : main.o &(libdir)/libstuff.a |> cc -o %o %f |> main_app .fi دستورهای build.sh زیر را تولید خواهد کرد (از طریق "tup generate build.sh"): .nf cd src/lib cc -I. -c lib1.c -o lib1.o cc -I. -c lib2.c -o lib2.o ar crs libstuff.a lib1.o lib2.o cd test cc -I.. -c test_stuff.c -o test_stuff.o cc -o test_stuff test_stuff.o ../libstuff.a cd ../.. cc -Ilib -c main.c -o main.o cc -o main_app main.o lib/libstuff.a .fi .TP .B ifeq (lval,rval) پارامترهای 'lval' و 'rval' را ارزیابی می‌کند (یعنی: تمام متغیرهای-$ و متغیرهای-@ را جایگزین می‌کند) و یک مقایسه رشته‌ای انجام می‌دهد تا ببیند آیا با یکدیگر مطابقت دارند یا خیر. در این صورت، تمام خطوط بین 'ifeq' و عبارت 'endif' پس از آن پردازش می‌شوند؛ در غیر این صورت نادیده گرفته می‌شوند. توجه داشته باشید که هیچ فاصله خالی (whitespace) از مقادیر حذف نمی‌شود - تمام متن میان '(' و ',' تشکیل‌دهنده 'lval' است و تمام متن میان ',' و ')' تشکیل‌دهنده 'rval' است. این بدان معناست که ifeq (foo, foo) نادرست (false) است، در حالی که ifeq (foo,foo) درست (true) می‌باشد. این رفتار جهت سازگاری با دستورات شرطی if در Makefile است. .nf ifeq (@(FOO),y) CFLAGS += -DFOO else CFLAGS += -g endif .fi .TP .B ifneq (lval,rval) مشابه 'ifeq'، اما با منطق معکوس. .TP .B ifdef VARIABLE بررسی می‌کند که آیا متغیر-@ با نام VARIABLE اصلاً در tup.config تعریف شده است یا خیر. در این صورت، تمام خطوط بین 'ifdef' و عبارت 'endif' پس از آن پردازش می‌شوند؛ در غیر این صورت نادیده گرفته می‌شوند. برای مثال، فرض کنید tup.config شامل مورد زیر باشد: .nf CONFIG_FOO=n .fi در این حالت 'ifdef FOO' به مقدار درست (true) ارزیابی خواهد شد. اگر tup.config وجود نداشته باشد، یا CONFIG_FOO را به هیچ شکلی تنظیم نکرده باشد، آنگاه 'ifdef FOO' نادرست (false) خواهد بود. .TP .B ifndef VARIABLE مشابه 'ifdef'، اما با منطق معکوس. .TP .B else وضعیت درستی/نادرستی (true/false) عبارت شرطی if قبلی را معکوس می‌کند. .TP .B endif به عبارت شرطی قبلی ifeq/ifdef/ifndef پایان می‌دهد. توجه داشته باشید که تنها تا ۸ سطح تودرتویی برای عبارات if پشتیبانی می‌شود. .TP .B error [message] باعث توقف تجزیه در tup و شکست فرآیند شده و \fBmessage\fP را به عنوان توضیح به کاربر نمایش می‌دهد. .TP .B !macro = [inputs] | [order-only inputs] |> command |> [outputs] ماکروی-! را روی رشته دستور داده‌شده تنظیم می‌کند. این نحو بسیار مشابه با قاعده-: است، چرا که یک ماکروی-! در اصل ماکرویی برای آن قواعد است. ماکروی-! تا زمانی که در رشته دستور یک قاعده-: استفاده نشود بسط داده نمی‌شود. بنابراین، کاربرد اصلی ماکروی-! داشتن مکانی برای ذخیره رشته‌های دستور حاوی پرچم‌های-% است که می‌توانند مجدداً استفاده شوند. برای مثال، می‌توانیم یک ماکروی !cc در فایل ریشه Tuprules.tup به این شکل داشته باشیم: .nf !cc = |> ^ CC %f^ gcc -c %f -o %o |> .fi سپس یک Tupfile می‌تواند به شکل زیر عمل کند: .nf include_rules : foreach *.c |> !cc |> %B.o .fi شما مایل خواهید بود که پارامتر خروجی را یا در ماکروی-! یا در قاعده-: که از آن استفاده می‌کند مشخص کنید، نه در هر دو. اگر هرگونه ورودی در ماکروی-! تعیین کنید، معمولاً ورودی‌های فقط-ترتیبی (order-only) خواهند بود. برای مثال، اگر قاعده !cc دارید که در آن از کامپایلری استفاده می‌کنید که توسط tup تولید شده است، می‌توانید فایل کامپایلر را در فهرست order-only ماکروی-! قید کنید. فایل کامپایلر سپس به یک وابستگی ورودی برای هر قاعده-: که از آن ماکرو استفاده می‌کند تبدیل خواهد شد. .TP .B include file فایل مشخص‌شده را می‌خواند و روند تجزیه را ادامه می‌دهد، تقریباً به همان شکل که گویی آن فایل به‌طور درون‌خطی در Tupfile فعلی چسبانده شده است. تنها فایل‌های معمولی مجاز به گنجانده شدن هستند -- تلاش برای include کردن یک فایل تولیدشده منجر به خطا می‌شود. هر دستور include که در فایل گنجانده‌شده رخ دهد، نسبت به دایرکتوری همان فایل گنجانده‌شده تجزیه خواهد شد. .TP .B include_rules فایل‌های Tuprules.tup را در امتداد سلسله‌مراتب دایرکتوری به سمت بالا می‌خواند. نخستین فایل Tuprules.tup در بالاترین سطح ساختار سلسله‌مراتبی tup خوانده می‌شود، سپس زیردایرکتوری بعدی و به همین ترتیب تا فایل Tuprules.tup در دایرکتوری جاری ادامه می‌یابد. بدین ترتیب، فایل ریشه Tuprules.tup می‌تواند تنظیمات متغیرهای عمومی را مشخص کند و زیردایرکتوری‌های بعدی می‌توانند آن‌ها را با تنظیمات خاص‌تر بازنویسی (override) نمایند. عموماً include_rules را به عنوان نخستین خط در Tupfile قرار می‌دهید. این نام تا حدودی نام‌گذاری نادقیق است، زیرا شما معمولاً از Tuprules.tup برای تعریف متغیرها استفاده می‌کنید تا قواعد-:. .TP .B run ./script args یک اسکریپت خارجی را با آرگومان‌های داده‌شده برای تولید قواعد-: اجرا می‌کند. این یک ویژگی پیشرفته است و زمانی می‌تواند استفاده شود که نحو استاندارد Tupfile برای برنامه‌ای پیچیده بیش از حد ساده باشد. انتظار می‌رود این اسکریپت قواعد-: را در خروجی استاندارد (stdout) بنویسد. هیچ دستور دیگر Tupfile مجاز نیست - برای مثال، اسکریپت نمی‌تواند متغیرهای-$ یا ماکروهای-! ایجاد کند، اما می‌تواند قواعدی-: تولید کند که از این ویژگی‌ها بهره می‌برند. به عنوان یک مثال ساده، در نظر بگیرید اگر فرمانی باید ۵ بار اجرا شود، اما هیچ فایل ورودی وجود ندارد تا بتوان از کلیدواژه foreach در tup استفاده کرد. یک اسکریپت خارجی به نام 'build.sh' می‌تواند به شکل زیر نوشته شود: .nf #! /bin/sh -e for i in `seq 1 5`; do echo ": |> echo $i > %o |> $i.txt" done .fi سپس یک Tupfile می‌تواند برای دریافت این قواعد استفاده شود: .nf run ./build.sh .fi سپس tup با این حالت طوری رفتار می‌کند که گویی یک Tupfile با ۵ خط به این صورت نوشته شده است: .nf : |> echo 1 > %o |> 1.txt : |> echo 2 > %o |> 2.txt : |> echo 3 > %o |> 3.txt : |> echo 4 > %o |> 4.txt : |> echo 5 > %o |> 5.txt .fi از آنجا که مرحله تجزیه Tupfile برای ردیابی وابستگی‌ها پایش می‌شود، دسترسی این اسکریپت به هر فایلی درون سلسله‌مراتب tup باعث تجزیه مجدد Tupfile خواهد شد. با این حال محدودیت‌هایی وجود دارد. نخست اینکه فراخوانی ()readdir مجهز شده است تا فهرست فایل‌هایی را بازگرداند که در زمان آغاز اجرای اسکریپتِ run در دسترس بوده‌اند. این بدان معناست که فایل‌هایی که با دستور 'ls' در خط فرمان می‌بینید ممکن است با فایل‌هایی که اسکریپت شما هنگام تجزیه شدن مشاهده می‌کند متفاوت باشند. ابزار tup اساساً وانمود می‌کند که فایل‌های تولیدشده وجود ندارند تا زمانی که یک قاعده-: را تجزیه کند که آن فایل را به عنوان خروجی فهرست کرده باشد. توجه داشته باشید که هر قاعده-: اجراشده توسط خود اسکریپتِ run تا زمانی که اسکریپت با موفقیت اجرا نشود، تجزیه نخواهد شد. دوم اینکه به دلیل برخی محدودیت‌های ساختاری در tup، اسکریپت نمی‌تواند روی هیچ دایرکتوری به جز دایرکتوری Tupfile فراخوانی ()readdir انجام دهد. به عبارت دیگر، یک اسکریپت می‌تواند عبارت 'for i in *.c' را انجام دهد، اما نمی‌تواند 'for i in sub/*.c' را اجرا کند. پرچم '--debug-run' می‌تواند به 'tup' ارسال شود تا فهرست قواعدی-: که tup از اسکریپت دریافت می‌کند را نمایش دهد. با توجه به ابزارگذاری ()readdir، ممکن است این فهرست با خروجی اسکریپت در زمان اجرای دستی آن از خط فرمان تفاوت داشته باشد. .TP .B preload directory به‌طور پیش‌فرض، یک اسکریپتِ run تنها می‌تواند از ()readdir (یعنی: استفاده از نویسه عام / wildcard) روی دایرکتوری جاری استفاده کند. برای تعیین فهرستی از سایر دایرکتوری‌های مجاز برای نویسه‌های عام، از کلیدواژه preload استفاده کنید. برای مثال، اگر یک اسکریپت run نیاز به بررسی *.c و src/*.c داشته باشد، دایرکتوری src باید از قبل بارگذاری (preload) شود: .nf preload src run ./build.sh *.c src/*.c .fi .TP .B export VARIABLE دستور export متغیر محیطی VARIABLE را به فهرست صادرات (export) برای قواعد-: و اسکریپت‌های run آینده اضافه می‌کند. مقدار متغیر از محیط tup می‌آید، نه از خود Tupfile. عموماً این بدان معناست که اگر مایلید مقدار مورداستفاده در دستورها و اسکریپت‌ها را تغییر دهید، باید متغیر را در پوسته (shell) خود تنظیم کنید. به‌طور پیش‌فرض تنها PATH صادر می‌شود. ویندوز علاوه بر این چندین متغیر مناسب برای ساخت با مجموعه کامپایلر Visual Studio را صادر می‌کند. ابزار tup متغیرهای محیطی صادرشده را بررسی می‌کند تا ببیند آیا مقادیر آن‌ها بین به‌روزرسانی‌ها تغییر کرده است یا خیر، و هر دستوری که از آن متغیرهای محیطی استفاده می‌کند را مجدداً اجرا می‌نماید. توجه داشته باشید این بدان معناست که اگر PATH تغییر کند، تمام دستورها مجدداً اجرا خواهند شد. برای مثال: .nf : |> command1 ... |> export FOO : |> command2 ... |> .fi ابزار tup مقدار فعلی FOO را ذخیره کرده و هنگام اجرای command2 آن را به محیط منتقل می‌کند. اگر FOO هنگام به‌روزرسانی بعدی مقدار متفاوتی داشته باشد، آنگاه command2 مجدداً با مقدار جدید در محیط اجرا خواهد شد. در این مثال، command1 متغیر FOO را در محیط خود نخواهد داشت و با تغییر مقدار آن مجدداً اجرا نخواهد شد. توجه داشته باشید که FOO در بالا به محیط منتقل می‌شود؛ به عنوان یک متغیر داخلی در tup در دسترس قرار نمی‌گیرد. بنابراین، با در نظر گرفتن مورد زیر: .nf export FOO : |> echo myFOO=$(FOO) envFOO=${FOO} > %o |> foo.txt .fi هنگامی که به صورت "$ FOO=silly tup" اجرا شود، محتوای فایل foo.txt برابر با "myFOO= envFOO=silly" خواهد بود. اگر دستور "export FOO" از Tupfile حذف می‌شد، محتوای فایل برابر با "myFOO= envFOO=" می‌بود، زیرا tup متغیرهای محیطی را منتشر نمی‌کند مگر اینکه صراحتاً صادر (export) شده باشند. این کار به حفظ ساخت‌های تکرارپذیر و قطعی (deterministic) کمک می‌کند. اگر مایلید به جای دریافت مقدار از محیط، متغیری را با یک مقدار معین صادر کنید، می‌توانید این کار را در پوسته خود به جای tup انجام دهید. برای مثال در Linux می‌توانید انجام دهید: .nf : |> FOO=value command ... |> .fi این کاربرد وابستگی به متغیر محیطی FOO ایجاد نمی‌کند، زیرا از طریق Tupfile کنترل می‌شود..TP .B import VARIABLE[=default] دستور import متغیری را درون Tupfile تنظیم می‌کند که مقدار متغیر محیطی را در بر دارد. اگر متغیر محیطی مقداردهی نشده باشد، در صورت تعیین، مقدار پیش‌فرض به جای آن استفاده می‌شود. این کار وابستگی‌ای از متغیر محیطی به Tupfile ایجاد می‌کند، به طوری که در صورت تغییر متغیر محیطی، Tupfile مجدداً تجزیه می‌شود. برای مثال: .nf import CC=gcc : foreach *.c |> $(CC) -c %f -o %o |> %B.o .fi این دستور تمام فایل‌های ‎.c را با کامپایلر تعریف‌شده در متغیر محیطی CC کامپایل می‌کند. اگر CC در محیط تنظیم نشده باشد، از gcc به عنوان پیش‌فرض استفاده خواهد شد. در ساخت بعدی، اجرای دستور 'CC=clang tup' باعث تجزیهٔ مجدد این Tupfile و بازسازی تمام فایل‌های ‎.c با clang خواهد شد (زیرا خطوط فرمان تغییر کرده‌اند). برخلاف 'export'، دستور import متغیرها را به محیط زیرپردازه ارسال نمی‌کند. بنابراین در مثال قبلی، متغیر محیطی CC در زیرپردازه تنظیم نمی‌شود، مگر اینکه 'export CC' نیز در Tupfile قرار داده شده باشد. .TP .B .gitignore به tup اعلام می‌کند که به طور خودکار یک فایل .gitignore در دایرکتوری جاری بسازد که حاوی فهرستی از فایل‌های خروجی تولیدشده توسط tup است. در صورت استفاده از git، این قابلیت می‌تواند مفید باشد؛ زیرا مجموعه فایل‌های تولیدشده توسط tup دقیقاً منطبق بر فایل‌هایی است که می‌خواهید git نادیده بگیرد. اگر از فایل‌های Tuprules.tup استفاده می‌کنید، ممکن است ترجیح دهید تنها .gitignore را در سطح بالاترین Tuprules.tup مشخص کنید و سپس در سایر Tupfileها از include_rules برای اعمال تعریف .gitignore استفاده نمایید. با این روش نیازی به مدیریت دستی فایل‌های .gitignore نخواهید داشت. توجه داشته باشید که ممکن است بخواهید فایل‌های دیگری را که توسط tup ساخته نشده‌اند نیز نادیده بگیرید، مانند فایل‌های موقتی که توسط ویرایشگر شما ایجاد می‌شوند. در این حالت می‌توانید با استفاده از دستوری مانند 'git config --global core.excludesfile ~/.gitignore' یک فایل gitignore سراسری راه‌اندازی کنید و سپس ~/.gitignore را با فهرست شخصی خود تنظیم نمایید. برای سایر موارد، همچنین می‌توانید به سادگی هر قاعدهٔ نادیده‌گیری دلخواهی را در بالای خط "##### TUP GITIGNORE #####" اضافه کنید. .TP .B # در ابتدای یک خط، نویسهٔ '#' نشان‌دهندهٔ توضیح (کامنت) است. خط توضیح توسط تجزیه‌کننده نادیده گرفته می‌شود. توضیح می‌تواند فاصله‌های خالی ابتدایی داشته باشد که آن‌ها نیز نادیده گرفته می‌شوند. اگر قبل از نویسهٔ '#' هر نویسهٔ غیرفاصله‌ای وجود داشته باشد، خط به عنوان توضیح در نظر گرفته نمی‌شود. این همچنین بدین معنی است که اگر خط قبلی با '\\' (شکستن خط) خاتمه یافته باشد، '#' به عنوان یک نماد معمولی تفسیر می‌شود. .SH "نکات TUPFILE (TUPFILE NOTES)" بسط متغیرها در tup در همه موارد به جز برای ماکروهای ! فوری و آنی است؛ به این معنی که با دیدن یک قاعدهٔ : یا اعلان متغیر، می‌توانید مقادیر فعلی متغیرها را جایگزین کنید. ماکروهای ! تنها زمانی تجزیه می‌شوند که در یک قاعدهٔ : به کار روند. در آن حالت، قاعدهٔ : نهایی در واقع نوعی اجتماع میان قاعدهٔ : همان‌طور که نوشته شده و مقدار فعلی ماکروی ! خواهد بود. .P هنگامی که tup یک Tupfile را تجزیه می‌کند، در یک گذرِ تک‌مرحله‌ای فایل را پردازش کرده و هر بار یک خط را می‌خواند. در انتهای Tupfile، تمام تعاریف متغیرها، ماکروهای ! و {bin} کنار گذاشته می‌شوند. تنها اثرات ماندگار تجزیه یک Tupfile، گره‌های فرمان و وابستگی‌هایی هستند که اکنون در پایگاه داده tup ثبت شده‌اند. علاوه بر این، در صورت درخواست Tupfile، ممکن است یک فایل .gitignore نیز ایجاد شده باشد. .SH "متغیرهای @ (@-VARIABLES)" متغیرهای @ متغیرهای ویژه‌ای در tup هستند. از آن‌ها به عنوان متغیرهای پیکربندی استفاده می‌شود و می‌توان آن‌ها را در Tupfile خواند یا در دستور varsed به کار گرفت. دستورات نیز قادر به خواندن آن‌ها هستند، اما برنامه‌ای که توسط دستور اجرا می‌شود باید شناخت مستقیمی از این متغیرها داشته باشد. متغیرهای @ در فایل tup.config در بالای سلسله‌مراتب tup یا در یک دایرکتوری گونه (variant directory) مشخص می‌شوند. برای مثال، tup.config ممکن است حاوی این خط باشد: .nf CONFIG_FOO=y .fi سپس یک Tupfile می‌تواند متغیر @ را به شکل زیر بخواند: .nf srcs-@(FOO) += foo.c srcs-y += bar.c : foreach $(srcs-y) |> gcc -c %f -o %o |> %B.o .fi در این مثال، اگر CONFIG_FOO بر روی 'y' تنظیم شده باشد، فایل foo.c در فهرست ورودی قرار می‌گیرد و بنابراین کامپایل می‌شود. اگر CONFIG_FOO تعیین نشده یا روی مقدار دیگری تنظیم شده باشد، foo.c در ورودی گنجانده نخواهد شد. .P متغیرهای @ را می‌توان مشابه متغیرهای $ به کار برد، با تمایزهای زیر: ۱) متغیرهای @ در Tupfileها فقط‌خواندنی هستند، و ۲) متغیرهای @ در DAG قرار دارند، به این معنی که خواندن آن‌ها وابستگی‌ای از متغیر @ به Tupfile ایجاد می‌کند. بنابراین هر Tupfile که مانند مثال بالا @(FOO) را می‌خواند، در صورت تغییر مقدار CONFIG_FOO در tup.config، مجدداً تجزیه خواهد شد. .P دلیل افزودن پیشوند "CONFIG_" در فایل tup.config حفظ سازگاری با kconfig است که می‌تواند برای تولید این فایل استفاده شود. .P توجه داشته باشید که نحو نگارش tup.config کاملاً دقیق و سخت‌گیرانه است. برای عبارتی مانند "CONFIG_FOO=y"، دستور tup یک متغیر @ با استفاده از رشته‌ای که پس از "CONFIG_" شروع می‌شود و تا علامت '=' ادامه دارد، ایجاد می‌کند. مقدار متغیر، تمام محتوای بلافاصله پس از علامت '=' تا انتهای خط است؛ اما اگر جفتی از علامت‌های نقل‌قول در اطراف آن وجود داشته باشد، حذف می‌شوند. در این مثال، متغیر "FOO" برابر با "y" قرار می‌گیرد. توجه داشته باشید که اگر خط به صورت "CONFIG_FOO = y" می‌بود، متغیر "FOO " با مقدار " y" تنظیم می‌شد. .P در tup.config، توضیحات با نویسهٔ '#' در ستون نخست مشخص می‌شوند. این توضیحات نادیده گرفته می‌شوند، مگر اینکه توضیح به شکل زیر باشد: .nf # CONFIG_FOO is not set .fi در این حالت، متغیر @ با نام "FOO" به طور صریح روی "n" تنظیم می‌شود. .TP .B @(TUP_PLATFORM) یک متغیر @ ویژه است. اگر CONFIG_TUP_PLATFORM در فایل tup.config تنظیم نشده باشد، این متغیر دارای یک مقدار پیش‌فرض متناسب با بستری (پلتفرمی) است که tup در آن کامپایل شده است. در حال حاضر مقدار پیش‌فرض یکی از گزینه‌های "linux"، "solaris"، "macosx"، "win32"، "freebsd" یا "netbsd" است. .TP .B @(TUP_ARCH) یک متغیر @ ویژهٔ دیگر است. اگر CONFIG_TUP_ARCH در فایل tup.config تنظیم نشده باشد، این متغیر دارای مقدار پیش‌فرضی متناسب با معماری پردازنده‌ای است که tup در آن کامپایل شده است. در حال حاضر مقدار پیش‌فرض یکی از گزینه‌های "i386"، "x86_64"، "powerpc"، "powerpc64"، "ia64"، "alpha"، "sparc"، "riscv32"، "riscv64"، "arm64"، "arm" یا "s390x" است. .SH "گونه‌ها (VARIANTS)" ابزار tup از گونه‌ها (variants) پشتیبانی می‌کند که امکان ساخت پروژه با پیکربندی‌های مختلف را فراهم می‌سازد. رایج‌ترین کاربرد آن ساخت نسخه‌های release و debug با پرچم‌های کامپایلر متفاوت است؛ اگرچه می‌توان از هر تعداد گونه برای پشتیبانی از هر پیکربندی دلخواهی استفاده کرد. هر گونه در دایرکتوری اختصاصی خود، مجزا از سایرین و جدا از درخت منبع ساخته می‌شود. هنگام ساخت با گونه‌ها، ساخت درون‌درختی (in-tree) غیرفعال می‌شود. برای ایجاد یک گونه، یک دایرکتوری جدید در بالاترین سطح سلسله‌مراتب tup ایجاد کنید و یک فایل "tup.config" در آن بسازید. برای مثال: .nf $ mkdir build-default $ touch build-default/tup.config $ tup .fi در اینجا دایرکتوری جدیدی با نام "build-default" ایجاد کرده و یک tup.config خالی درون آن قرار دادیم. توجه داشته باشید که دایرکتوری ساخت باید در همان سطح دایرکتوری ".tup" قرار گیرد. پس از به‌روزرسانی، tup تمام Tupfileها را با استفاده از فایل پیکربندی ایجادشده تجزیه می‌کند و تمام خروجی‌های ساخت را در زیردایرکتوری‌هایی از build-default که بازتاب‌دهندهٔ درخت منبع هستند قرار می‌دهد. سپس می‌توانیم گونهٔ دیگری را به صورت زیر ایجاد کنیم: .nf $ mkdir build-debug $ echo "CONFIG_MYPROJ_DEBUG=y" > build-debug/tup.config $ tup .fi این بار تمام Tupfileها با مقدار "y" برای @(MYPROJ_DEBUG) تجزیه خواهند شد و تمام محصولات ساخت در دایرکتوری build-debug قرار می‌گیرند. توجه داشته باشید که تنظیم @(MYPROJ_DEBUG) تنها زمانی مؤثر خواهد بود که این متغیر واقعاً در یک Tupfile به کار رفته باشد (مثلاً از طریق افزودن پرچم‌های اشکال‌زدایی به خط فرمان کامپایلر). اجرای دستور "tup" تمام گونه‌ها را به‌روزرسانی خواهد کرد. برای مثال، به‌روزرسانی پس از اصلاح یک فایل C که در تمام پیکربندی‌ها استفاده می‌شود، منجر به کامپایل مجدد آن برای هر یک از گونه‌ها خواهد شد. مشابه هر فرمانی که اجرا می‌شود، این کار نیز بسته به محدودیت‌های DAG و تعداد پردازش‌های موازی مشخص‌شده (jobs) به صورت موازی انجام می‌گیرد. برای ساخت یک گونهٔ تکی (یا زیرمجموعه‌ای از گونه‌ها)، همانند هر به‌روزرسانی جزئی دیگر، دایرکتوری ساخت را به عنوان هدف به "tup" اعلام کنید. برای مثال: .nf $ tup build-default .fi برای حذف یک گونه، کافی است دایرکتوری ساخت آن را به طور کامل پاک کنید: .nf $ rm -rf build-debug .fi در صورت ساخت با استفاده از گونه‌ها، توصیه می‌شود همواره یک گونهٔ پیش‌فرض حاوی فایل tup.config خالی داشته باشید. این کار تضمین می‌کند که نرم‌افزار شما همیشه بتواند تنها از طریق دریافت کد و اجرای 'tup init; tup'، بدون وابستگی به یک پیکربندی خاص ساخته شود. .fi هنگام استفاده از ساخت‌های درون‌درختی، خروجی‌های ساخت ممکن است به فایل‌های زمان اجرا متکی باشند که در درخت منبع قرار دارند و توسط tup پردازش نمی‌شوند. ابزار tup این امکان را فراهم می‌کند که چنین فایل‌هایی با ارائه ماکروی توکار "!tup_preserve" به صورت عین‌به‌عین در دایرکتوری ساخت گونه کپی شوند: .nf :foreach *.png |> !tup_preserve |> .fi بسته به سیستم‌عامل و سیستم فایلی که استفاده می‌شود، یک پیوند نمادین (symbolic link) یا رونوشتی از فایل منبع ایجاد خواهد شد. .SH "مثال (EXAMPLE)" تجزیهٔ یک قاعدهٔ : ممکن است در ابتدا کمی پیچیده به نظر برسد. شاید ساده‌تر باشد که Tupfile را شبیه به یک اسکریپت شل با نشانه‌گذاری‌های ورودی/خروجی اضافی برای دستورات در نظر بگیرید. به عنوان مثال، این Tupfile را در نظر بگیرید: .nf WARNINGS += -W WARNINGS += -Wall CFLAGS = $(WARNINGS) -O2 CFLAGS_foo.c = -DFOO : |> echo '#define BAR 3' > %o |> foo.h : foreach *.c | foo.h |> gcc -c %f -o %o $(CFLAGS) $(CFLAGS_%f) |> %B.o : *.o |> gcc %f -o %o |> program .fi ابزار tup تجزیهٔ این Tupfile را با یک مجموعهٔ متغیر $ خالی آغاز می‌کند. خط نخست یعنی "WARNINGS += -W" متغیر WARNINGS را روی "-W" تنظیم می‌کند. خط دوم به آن اضافه می‌شود، بنابراین مقدار WARNINGS برابر با "-W -Wall" خواهد شد. خط سوم به این مقدار ارجاع می‌دهد، در نتیجه CFLAGS برابر با "-W -Wall -O2" می‌شود. خط چهارم متغیر جدیدی به نام CFLAGS_foo.c ایجاد کرده و آن را برابر با "-DFOO" قرار می‌دهد. قاعدهٔ نخست یک گره جدید به نام "foo.h" به همراه دستور متناظر با تولید آن در پایگاه داده ایجاد می‌کند. توجه داشته باشید این فایل تا زمانی که دستور پس از تجزیه تمام Tupfileها واقعاً اجرا نشود، در سیستم فایل وجود نخواهد داشت. .P قاعدهٔ : از نوع foreach فرمانی برای کامپایل هر فایل تولید خواهد کرد. ابتدا tup بخش ورودی را تجزیه کرده و به دلیل وجود نویسهٔ '*'، عملیات تطابق الگو (glob) را روی پایگاه داده اعمال می‌کند. این تطابق با فایل‌های foo.c و bar.c هم‌خوانی دارد. از آنجا که این یک قاعدهٔ foreach است، tup قاعده را ابتدا با ورودی "foo.c" و سپس بار دیگر با ورودی "bar.c" اجرا می‌کند. الگوی خروجی در هر گذر تجزیه می‌شود و به دنبال آن رشتهٔ فرمان پردازش خواهد شد. .P در گذر مربوط به foo.c، الگوی خروجی "%B.o" تجزیه شده و به "foo.o" تبدیل می‌شود. سپس رشتهٔ فرمان با جایگزینی "foo.c" به جای "%f" و "foo.o" به جای "%o" تجزیه می‌شود. سپس متغیرهای $ بسط می‌یابند، بنابراین $(CFLAGS) به "-W -Wall -O2" و $(CFLAGS_foo.c) به "-DFOO" تبدیل می‌شود. رشتهٔ فرمان نهایی که در پایگاه داده ثبت می‌شود عبارت است از "gcc -c foo.c -o foo.o -W -Wall -O2 -DFOO". یک پیوند خروجی به فایل foo.o ایجاد می‌شود و پیوندهای ورودی از foo.c و foo.h (ورودی فقط‌ترتیبی یا order-only) ثبت می‌گردند. .P در گذر دوم از قاعدهٔ foreach، تنها تفاوت این است که "bar.c" ورودی کار است. بنابراین الگوی خروجی تبدیل به "bar.o" شده و رشتهٔ فرمان نهایی به دلیل تعریف نشدن $(CFLAGS_bar.c) به صورت "gcc -c bar.c -o bar.o -W -Wall -O2 " درمی‌آید. .P برای مثال‌های بیشتر به همراه DAGهای متناظر، http://gittup.org/tup/examples.html را ببینید..SH "سایر سامانه‌های ساخت (OTHER BUILD SYSTEMS)" ابزار tup اندکی با سایر سامانه‌های ساخت تفاوت دارد. این سامانه از یک ساختار گراف کاملاً مشخص که در یک پایگاه‌داده مجزا نگهداری می‌شود، استفاده می‌کند. مجموعه‌ای از الگوریتم‌ها برای کار بر روی این گراف توسعه یافته‌اند تا مواردی نظیر ویرایش یک فایل موجود، ایجاد یا حذف فایل‌ها، تغییر خطوط فرمان و غیره را مدیریت کنند. این الگوریتم‌ها بسیار کارآمد هستند؛ به‌ویژه در حالتی که یک پروژه از قبل ساخته شده است و یک یا چند فایل موجود تغییر یافته‌اند، tup در میان سامانه‌های ساخت مبتنی بر فایل بهینه‌ترین عملکرد را دارد. برای سایر موارد، tup دست‌کم بسیار سریع عمل می‌کند، اما بهینه بودن قطعی آن هنوز اثبات نشده است. .P دلیل اصلی استفاده از پایگاه‌داده گراف این است که الگوریتم به‌روزرسانی tup بتواند به‌سادگی به اطلاعات مورد نیاز خود دسترسی یابد. به عنوان یک اثر جانبی بسیار مفیدِ این ساختار پایگاه‌داده خوش‌تعریف، tup می‌تواند تشخیص دهد که یک فایل تولیدشده چه زمانی دیگر مورد نیاز نیست. این بدان معناست که هیچ هدف clean وجود ندارد؛ همچنین نیازی به دریافت مجدد و دست‌نخورده کدها (\(lqfresh checkout\(rq) و ساخت نرم‌افزار از صفر نیست. هر تعداد تکرار در به‌روزرسانی‌ها، همواره همان خروجی‌ای را تولید می‌کند که گویی همه‌چیز از نو ساخته شده است. چنانچه وضعیتی خلاف این مشاهده کردید، احتمالاً باگی در tup پیدا کرده‌اید (نه در Tupfileهای خود)، که در این صورت باید به فهرست پستی اطلاع دهید (بخش تماس (CONTACT) را ببینید). .P برای کسب اطلاعات بیشتر در رابطه با مبانی نظری پشت tup، به http://gittup.org/tup/build_system_rules_and_algorithms.pdf مراجعه کنید. .SH "همچنین ببینید (SEE ALSO)" http://gittup.org/tup .SH "تماس (CONTACT)" tup\-users@googlegroups.com