قوانین نوشتن در ویندوز

این صفحه بر روی نوشتن قوانین سازگار با ویندوز، مشکلات رایج نوشتن قوانین قابل حمل و برخی راه حل ها تمرکز دارد.

راه ها

چالش ها و مسائل:

  • محدودیت طول : حداکثر طول مسیر 259 کاراکتر است.

    اگرچه ویندوز از مسیرهای طولانی تر (تا 32767 کاراکتر) نیز پشتیبانی می کند، بسیاری از برنامه ها با محدودیت کمتر ساخته می شوند.

    در مورد برنامه هایی که در اکشن ها اجرا می کنید از این موضوع آگاه باشید.

  • دایرکتوری کاری : همچنین به 259 کاراکتر محدود شده است.

    فرآیندها نمی توانند به فهرستی با بیش از 259 کاراکتر cd وارد شوند.

  • حساسیت به حروف کوچک و بزرگ: مسیرهای ویندوز به حروف بزرگ و کوچک حساس هستند، مسیرهای یونیکس به حروف بزرگ و کوچک حساس هستند.

    هنگام ایجاد خطوط فرمان برای اقدامات، از این موضوع آگاه باشید.

  • جداکننده های مسیر : اسلش معکوس ( \`), not forward slash ( /`) هستند.

    Bazel مسیرهایی را به سبک یونیکس با جداکننده / ذخیره می کند. اگرچه برخی از برنامه‌های ویندوز از مسیرهای سبک یونیکس پشتیبانی می‌کنند، برخی دیگر اینطور نیستند. برخی از دستورات داخلی در cmd.exe از آنها پشتیبانی می کنند، برخی نه.

    بهترین کار این است که همیشه از \` separators on Windows: replace / with ` شوید.

  • مسیرهای مطلق : با اسلش ( / ) شروع نکنید.

    مسیرهای مطلق در ویندوز با یک حرف درایو شروع می شوند، مانند C:\foo\bar.txt . هیچ ریشه سیستم فایل واحدی وجود ندارد.

    اگر قانون شما بررسی می کند که آیا یک مسیر مطلق است، از این آگاه باشید. از مسیرهای مطلق باید اجتناب شود زیرا اغلب غیرقابل حمل هستند.

راه حل ها:

  • مسیرها را کوتاه نگه دارید

    از نام‌های دایرکتوری طولانی، ساختارهای دایرکتوری عمیق تو در تو، نام فایل‌های طولانی، نام‌های فضای کاری طولانی، نام‌های هدف طولانی اجتناب کنید.

    همه اینها ممکن است به اجزای مسیر فایل های ورودی اقدامات تبدیل شوند و ممکن است محدودیت طول مسیر را تمام کنند.

  • از یک ریشه خروجی کوتاه استفاده کنید.

    از پرچم --output_user_root=<path> برای تعیین یک مسیر کوتاه برای خروجی های Bazel استفاده کنید. یک ایده خوب این است که یک درایو (یا درایو مجازی) فقط برای خروجی های Bazel (مانند D:\`), and adding this line to your اضافه کنید:

    build --output_user_root=D:/
    

    یا

    build --output_user_root=C:/_bzl
    
  • از اتصالات استفاده کنید.

    پیوندها، به زبان ساده [1] ، پیوندهای علامت دایرکتوری هستند. اتصالات به راحتی ایجاد می شوند و می توانند به دایرکتوری ها (در همان رایانه) با مسیرهای طولانی اشاره کنند. اگر یک اقدام ساخت اتصالی ایجاد کند که مسیر آن کوتاه است اما هدف آن طولانی است، ابزارهایی با محدودیت مسیر کوتاه می‌توانند به فایل‌های دایرکتوری junction'ed دسترسی داشته باشند.

    در فایل های .bat یا در cmd.exe می توانید پیوندهایی مانند این ایجاد کنید:

    mklink /J c:\path\to\junction c:\path\to\very\long\target\path
    

    [1] : به طور دقیق، Junction ها پیوندهای نمادین نیستند ، اما به خاطر اقدامات ساخت، می توانید Junction ها را به عنوان پیوندهای دایرکتوری در نظر بگیرید.

  • جایگزین / با `` در مسیرها در اقدامات / envvars.

    هنگامی که خط فرمان یا متغیرهای محیطی را برای یک اقدام ایجاد می کنید، مسیرها را به سبک ویندوز بسازید. مثال:

    def as_path(p, is_windows):
        if is_windows:
            return p.replace("/", "\\")
        else:
            return p
    

متغیرهای محیطی

چالش ها و مسائل:

  • حساسیت به حروف کوچک و بزرگ: نام متغیرهای محیط ویندوز به حروف بزرگ و کوچک حساس نیست.

    به عنوان مثال، در جاوا System.getenv("SystemRoot") و System.getenv("SYSTEMROOT") نتیجه یکسانی را به همراه دارد. (این برای سایر زبان ها نیز صدق می کند.)

  • هرمتیک : اقدامات باید تا حد امکان از متغیرهای محیطی سفارشی استفاده کنند.

    متغیرهای محیطی بخشی از کلید حافظه پنهان عمل هستند. اگر یک کنش از متغیرهای محیطی استفاده کند که اغلب تغییر می‌کنند، یا برای کاربران سفارشی هستند، این قانون باعث می‌شود کمتر قابلیت ذخیره‌سازی در حافظه پنهان را داشته باشد.

راه حل ها:

  • فقط از نام متغیرهای محیطی با حروف بزرگ استفاده کنید.

    این روی ویندوز، macOS و لینوکس کار می کند.

  • محیط های اکشن را به حداقل برسانید.

    هنگام استفاده از ctx.actions.run ، محیط را روی ctx.configuration.default_shell_env کنید. اگر عمل به متغیرهای محیطی بیشتری نیاز دارد، همه آنها را در یک دیکشنری قرار دهید و آن را به اکشن منتقل کنید. مثال:

    load("@bazel_skylib//lib:dicts.bzl", "dicts")
    
    def _make_env(ctx, output_file, is_windows):
        out_path = output_file.path
        if is_windows:
            out_path = out_path.replace("/", "\\")
        return dicts.add(ctx.configuration.default_shell_env, {"MY_OUTPUT": out_path})
    

اقدامات

چالش ها و مسائل:

  • خروجی های اجرایی : هر فایل اجرایی باید پسوند اجرایی داشته باشد.

    رایج‌ترین پسوندها .exe . (فایل‌های باینری) و .bat . (اسکریپت‌های دسته‌ای) هستند.

    توجه داشته باشید که اسکریپت های پوسته ( .sh ) در ویندوز قابل اجرا نیستند. شما نمی توانید آنها را به عنوان executable ctx.actions.run مشخص کنید. همچنین هیچ مجوز +x که فایل ها می توانند داشته باشند وجود ندارد، بنابراین نمی توانید مانند لینوکس فایل های دلخواه را اجرا کنید.

  • دستورات Bash : برای حمل و نقل، از اجرای مستقیم دستورات Bash در عملیات خودداری کنید.

    Bash در سیستم‌های مشابه یونیکس گسترده است، اما اغلب در ویندوز در دسترس نیست. خود Bazel کمتر و کمتر به Bash (MSYS2) متکی است، بنابراین در آینده کاربران کمتر احتمال دارد که MSYS2 را همراه با Bazel نصب کنند. برای سهولت استفاده از قوانین در ویندوز، از اجرای دستورات Bash در عملیات خودداری کنید.

  • انتهای خطوط : ویندوز از CRLF ( \r\n ) استفاده می کند، سیستم های شبه یونیکس از LF ( \n ) استفاده می کنند.

    هنگام مقایسه فایل های متنی به این نکته توجه داشته باشید. حواستان به تنظیمات Git خود باشد، به‌ویژه پایان‌های خط هنگام چک کردن یا تعهد کردن. (به تنظیمات core.autocrlf Git مراجعه کنید.)

راه حل ها:

  • از قانون هدفمند بدون Bash استفاده کنید.

    native.genrule() یک پوشش برای دستورات Bash است و اغلب برای حل مشکلات ساده مانند کپی کردن یک فایل یا نوشتن یک فایل متنی استفاده می شود. می‌توانید از تکیه بر Bash (و اختراع مجدد چرخ) اجتناب کنید: ببینید آیا bazel-skylib یک قانون هدفمند برای نیازهای شما دارد یا خیر. هیچکدام از آنها در هنگام ساخت/تست بر روی ویندوز به Bash وابسته نیستند.

    نمونه های قوانین ساخت:

    • copy_file() ( source , documentation ): فایل را در جای دیگری کپی می کند و به صورت اختیاری آن را قابل اجرا می کند

    • write_file() ( منبع ، مستندات ): یک فایل متنی با انتهای خط مورد نظر ( auto ، unix ، یا windows ) می نویسد، به صورت اختیاری آن را قابل اجرا می کند (اگر اسکریپت باشد)

    • run_binary() ( منبع ، مستندات ): یک باینری (یا *_binary ) را با ورودی‌های داده شده و خروجی‌های مورد انتظار به عنوان اکشن ساخت اجرا می‌کند (این یک پوشش قوانین ساخت برای ctx.actions.run )

    • native_binary() ( source , documentation ): یک باینری بومی را در یک قانون *_binary می پیچد، که می توانید آن را bazel run کنید یا در ویژگی tool run_binary run_binary() ) یا ویژگی tools native.genrule() استفاده کنید.

    نمونه قوانین تست:

    • diff_test() ( source , documentation ): تستی که محتویات دو فایل را با هم مقایسه می کند

    • native_test() ( source , documentation ): یک باینری بومی را در یک قانون *_test می پیچد که می توانید آن را bazel test کنید

  • در ویندوز، استفاده از اسکریپت های .bat را برای چیزهای بی اهمیت در نظر بگیرید.

    به جای اسکریپت های .sh ، می توانید کارهای بی اهمیت را با اسکریپت های .bat حل کنید.

    به عنوان مثال، اگر به اسکریپتی نیاز دارید که هیچ کاری انجام نمی دهد، یا پیامی را چاپ می کند، یا با کد خطای ثابت خارج می شود، یک فایل .bat ساده کافی است. اگر قانون شما یک ارائه‌دهنده DefaultInfo() برمی‌گرداند، فیلد executable ممکن است به آن فایل .bat . در ویندوز اشاره داشته باشد.

    و از آنجایی که پسوند فایل در macOS و Linux مهم نیست، همیشه می‌توانید از .bat . به عنوان پسوند استفاده کنید، حتی برای اسکریپت‌های پوسته.

    توجه داشته باشید که فایل های خالی .bat قابل اجرا نیستند. اگر به یک اسکریپت خالی نیاز دارید، یک فاصله در آن بنویسید.

  • از Bash به صورت اصولی استفاده کنید.

    در قوانین ساخت و تست Starlark، از ctx.actions.run_shell برای اجرای اسکریپت های Bash و دستورات Bash به عنوان اکشن استفاده کنید.

    در ماکروهای Starlark، اسکریپت ها و دستورات Bash را در یک native.sh_binary() native.genrule() ) native.genrule قرار دهید. Bazel بررسی می کند که آیا Bash در دسترس است و اسکریپت یا دستور را از طریق Bash اجرا می کند.

    در قوانین مخزن Starlark، سعی کنید از Bash به طور کلی اجتناب کنید. Bazel در حال حاضر هیچ راهی برای اجرای دستورات Bash به صورت اصولی در قوانین مخزن ارائه نمی دهد.

حذف فایل ها

چالش ها و مسائل:

  • فایل ها را نمی توان در حالت باز حذف کرد.

    فایل‌های باز را نمی‌توان حذف کرد (به‌طور پیش‌فرض)، تلاش‌ها منجر به خطاهای «دسترسی رد شد». اگر نمی توانید فایلی را حذف کنید، شاید یک فرآیند در حال اجرا همچنان آن را باز نگه می دارد.

  • فهرست کاری یک فرآیند در حال اجرا قابل حذف نیست.

    فرآیندها دارای یک دسته باز در پوشه کاری خود هستند و تا زمانی که فرآیند خاتمه نیابد نمی توان دایرکتوری را حذف کرد.

راه حل ها:

  • در کد خود سعی کنید فایل ها را مشتاقانه ببندید.

    در جاوا، از try-with-resources استفاده کنید. در پایتون، از with open(...) as f: استفاده کنید. در اصل سعی کنید دستگیره ها را در اسرع وقت ببندید.