۲۹ مهر ۱۴۰۴

Techboy

اخبار و اطلاعات روز تکنولوژی

پروژه‌های Rust را برای کامپایل سریع‌تر با فضای کاری Cargo سازماندهی کنید

از ابزار مدیریت پروژهٔ Rust استفاده کنید تا پروژه‌های خود را به زیرپروژه‌های قابل مدیریت تقسیم کنید و زمان کامپایل را سریع‌تر کنید.

از ابزار مدیریت پروژهٔ Rust استفاده کنید تا پروژه‌های خود را به زیرپروژه‌های قابل مدیریت تقسیم کنید و زمان کامپایل را سریع‌تر کنید.

راه‌اندازی workspaces در یک پروژه Rust

پروژه‌های ساده در زبان Rust معمولاً از یک crate واحد تشکیل می‌شوند. اما ابزار مدیریت پروژه cargo برای Rust به شما امکان می‌دهد یک پروژه را به workspaces تقسیم کنید، که بسته‌های کوچکتری درون بسته اصلی هستند.

تقسیم یک پروژه موجود به workspaces — که در اصل زیرپروژه‌ها هستند — نیاز به برنامه‌ریزی دارد، زیرا باید مشخص کنید که چه وظایفی توسط کد هر workspace انجام خواهد شد. اما این روش قدرتمندی برای تقسیم و تسلط بر یک پروژه Rust بر اساس خطوط منطقی است. همچنین به سرعت بخشیدن به زمان کامپایل کمک می‌کند، که یک مشکل رایج برای توسعه‌دهندگان Rust است.

راه‌اندازی workspaces در یک پروژه Rust

هنگامی که یک پروژه یا crate جدید را با cargo راه‌اندازی می‌کنید، رفتار پیش‌فرض این است که پروژه تازه ایجاد شده را به عنوان یک crate واحد در نظر بگیرد. اگر بخواهید یک پوشه workspace با چندین crate در آن تنظیم کنید، باید رویکردی کمی متفاوت اتخاذ کنید.

ایجاد پوشه اصلی

با ایجاد پوشه‌ای که می‌خواهید workspace در آن قرار گیرد، به همراه تمام subcrate‌ها آغاز کنید. در آن پوشه، یک فایل جدید Cargo.lock ایجاد کنید که فقط محتوای زیر را شامل می‌شود:

[workspace] resolver = "3"

این به cargo می‌گوید که پوشه سطح بالا یک workspace است و نه یک crate مستقل. «resolver» در این فایل به شماره نسخه الگوریتم resolver Cargo اشاره دارد که تعیین می‌کند چگونه وابستگی‌ها بین crate‌های Rust حل شوند. جدیدترین نسخهٔ الگوریتم ۳ است، بنابراین هر پروژهٔ جدیدی که در آخرین نگارش Rust شروع می‌شود باید از آن استفاده کند. (اگر در حال انتقال یک پروژهٔ قدیمی به workspaces با شماره resolver متفاوت هستید، آن را دست نخورده بگذارید.)

ایجاد crate اصلی

سپس، با خط فرمان به آن پوشه بروید و از cargo new برای ایجاد crate اصلی پروژه استفاده کنید:

cargo new the_project

اکنون یک پوشهٔ دیگر داخل پوشهٔ اصلی خواهید دید که به نام the_project است و دارای فایل Cargo.toml و پوشه src خود می‌باشد.

اگر به فایل Cargo.toml در پوشهٔ بیرونی نگاه کنید، باید خط جدیدی در بخش [workspace] مشاهده کنید:

members = ["the_project"]

هر crate در workspace به‌صورت خودکار در اینجا ثبت می‌شود وقتی از cargo new در سطح بالای workspace استفاده کنید.

اگر workspace شما برای یک کتابخانه است نه یک برنامه اجرایی، نیازی به تغییر زیاد ندارید. به سادگی crate اصلی پروژه خود را با cargo new <crate_name> –lib تنظیم کنید.

ایجاد crate‌های وابسته

سپس، می‌خواهید crate‌هایی را که به‌عنوان وابستگی برای crate اصلی هستند تنظیم کنید. برای این کار، همانند قبل در پوشهٔ سطح بالا از cargo new استفاده کنید، اما با پرچم –lib:

cargo new subcrate1 --lib cargo new subcrate2 --lib

این اطمینان می‌دهد که این crate‌ها به‌عنوان وابستگی برای crate اصلی کامپایل شوند، نه به‌عنوان برنامه‌های مستقل.

افزودن وابستگی‌ها در workspaces

هنگامی که یک پروژهٔ کار کرده با workspace با cargo ایجاد می‌کنید، باید به‌صورت دستی توصیف کنید که crate‌ها چگونه به یکدیگر وابسته‌اند. در مورد ما، یک crate اصلی داریم که تمام crateهای دیگر را به‌عنوان وابستگی فهرست می‌کند.

وقتی فایل Cargo.toml برای crate اصلی خود را ویرایش می‌کنید، می‌توانید سایر crate‌ها را به‌عنوان وابستگی اضافه کنید فقط با مشخص کردن نام آنها و مکان یافتن‌شان نسبت به crate اصلی:

[dependencies] subcrate1 = { path = "../subcrate1" } subcrate2 = { path = "../subcrate2" }

باید برای هر وابستگی یک خط مشابه این را به‌صورت دستی اضافه کنید، زیرا هیچ‌کدام به‌صورت خودکار تولید نمی‌شوند.

اگر یک subcrate وابسته به subcrate دیگری باشد، می‌توانید وابستگی‌هایشان را به همان روش توصیف کنید. به‌عنوان مثال، اگر subcrate1 به subcrate3 وابسته باشد، subcrate3 را در وابستگی‌های subcrate1 فهرست می‌کنید.

کار با کدها در workspaces

اگر پوشه src برای subcrate اصلی در workspace خود را باز کنید، خواهید دید که یک فایل main.rs و یک تابع main() به‌صورت خودکار ایجاد شده است. این به‌عنوان نقطهٔ ورود برنامه عمل می‌کند.

سایر پوشه‌های src شامل یک فایل lib.rs و توابع نمونه و تست‌ها خواهند بود. می‌توانید آن توابع را از داخل پروژهٔ خود فقط با استفاده از فضای نام مناسب فراخوانی کنید. برای مثال، اگر ما subcrate1 داشته باشیم و تابعی به نام fn1 در آن باشد، فقط با نوشتن subcrate1::fn1() می‌توانیم از هرجایی در پروژهٔ اصلی آن را صدا بزنیم. ویژگی پیشنهادی خودکار ویرایشگر شما باید به‌صورت خودکار این نکات را شناسایی کند.

فواید کامپایل subcrate‌ها

وقتی پروژه‌ای که به subcrate‌ها تقسیم شده است را با cargo build در پوشهٔ سطح بالا می‌سازید، یکی از اولین چیزهایی که ممکن است متوجه شوید این است که هنگام اعمال تغییرات، کامپایل سریع‌تر انجام می‌شود.

وقتی تغییری در هر یک از crate‌های یک پروژهٔ workspace ایجاد می‌کنید، به‌صورت پیش‌فرض فقط همان crate بازکامپایل می‌شود. اگر رابط‌های تمام crate‌های وابستهٔ آن یکسان باشند، نیازی به تغییر آن‌ها نیست؛ می‌توانید همان‌گونه که هستند دوباره لینک کنید.

تنها چیزی که همیشه باید بازکامپایل شود نقطهٔ ورود است. این دلیل دیگری برای این است که نقطهٔ ورود را نسبتاً کم حجم نگه دارید، زیرا این کار زمان ساخت را بیشتر کاهش می‌دهد.

این سرعت‌بخشی‌های کامپایل در طول جلسات مختلف حفظ می‌شوند، زیرا آثار کامپایل subcrate‌ها در حافظهٔ کش ذخیره می‌شود. اما توجه داشته باشید که اگر از cargo clean برای پاک‌سازی آن‌ها استفاده کنید، مجبور خواهید شد همه چیز را دوباره کامپایل کنید.

همچنین توجه داشته باشید که subcrate‌ها بر اساس پروفایل ساخت خود کش می‌شوند. اگر چندین بار با پروفایل debug بازسازی کرده باشید، در هر بار بازسازی مزایای کش را خواهید دید. اما اگر به پروفایل release سوئیچ کنید، همه چیز باید قبل از اینکه مزایای کش ظاهر شوند، بازکامپایل شود.

اگر می‌خواهید فقط یک crate را در پروژهٔ workspace خود کامپایل کنید، از cargo build -p <crate_name> استفاده کنید. به‌طور معمول نیازی به این کار نیست، زیرا rustc به‌قدری هوشمند است که می‌داند چه چیزی نیاز به بازکامپایل دارد.

برنامه‌ریزی یک پروژه برای workspace

سخت‌ترین بخش workspaces تنظیم نیست، بلکه یافتن راهی برای تقسیم پروژه به چندین crate بر اساس خطوط منطقی است.

اگر برنامهٔ شما قبلاً با جداسازی مناسبی از مسئولیت‌ها تنظیم شده باشد، این کار نباید خیلی سخت باشد. به‌عنوان مثال، یک برنامه با UI می‌تواند به سه بخش تقسیم شود: نقطهٔ ورود (که می‌تواند وظایفی مانند سوئیچ‌های خط فرمان را نیز بر عهده بگیرد)، UI، و منطق کنترل‌کننده.

برای یک پروژهٔ جدید، برنامه‌ریزی این نوع جداسازی از پیش راحت‌تر است. اما تقسیم یک پروژهٔ موجود به subcrate‌ها ممکن است پیچیده‌تر باشد، چراکه ممکن است قبل از شکستن توابع مختلف به crate‌های جداگانه، نیاز به بازنگری در جداسازی داخلی برنامه داشته باشید. سعی نکنید همه کار را یک‌بار انجام دهید. در عوض می‌توانید توابع را به‌تدریج و به‌صورت یک به‌یک به subcrate‌ها منتقل کنید. این‌گونه به‌تدریج تنظیمی را کشف می‌کنید که بیشترین هماهنگی را با اهداف پروژه‌تان دارد.