כללי כתיבה ב-Windows

כאן אנחנו מנסחים כללים שתואמים ל-Windows, בעיות נפוצות בכתיבת כללים לניידים ופתרונות מסוימים.

נתיבים

בעיות:

  • מגבלת אורך: האורך המרבי של הנתיב הוא 259 תווים.

    Windows תומך גם בנתיבים ארוכים יותר (עד 32,767 תווים), אבל תוכנות רבות מובנות עם המגבלה התחתונה.

    חשוב לשים לב לנקודות האלה לגבי תוכניות שמופעלות בפעולות.

  • ספריית העבודה מוגבלת גם היא ל-259 תווים.

    תהליכים לא יכולים לכלול cd כאשר הוא מכיל יותר מ-259 תווים.

  • תלוי אותיות רישיות: נתיבי Windows הם תלויי אותיות רישיות, ונתיבי Unix הם תלויי אותיות רישיות.

    חשוב לשים לב לכך כשיוצרים שורות של פעולות לביצוע.

  • מפרידי נתיבים: הם לוכסן הפוך (\`), not forward slash (/`).

    בזל מאחסנת נתיבים בסגנון יוניקס עם מפרידים של /. חלק מהתוכניות של Windows תומכות בנתיבים בסגנון Unix, אבל אחרות לא. חלק מהפקודות המובנות ב-cmd.exe תומכות בהן, ובחלקן אין.

    עדיף להשתמש תמיד ב-\` separators on Windows: replace/with` כשיוצרים שורות פקודה ומשתני סביבה לפעולות.

  • נתיבים מוחלטים: אין להתחיל בקו נטוי (/).

    מסלולים מוחלטים ב-Windows מתחילים באות כונן, כמו C:\foo\bar.txt. אין שורש יחיד של מערכת קבצים.

    חשוב לדעת אם הכלל בודק אם נתיב הוא מוחלט. יש להימנע מנתיבים מוחלטים, מפני שלעיתים קרובות הם לא ניידים.

פתרונות:

  • נסחו נתיבים קצרים.

    מומלץ להימנע משמות ארוכים של ספריות, מבני ספריות עם עומק ארוך, שמות של קבצים ארוכים, שמות של סביבות עבודה ארוכות ושמות ארוכי יעד.

    כל אלה עשויים להפוך לרכיבי נתיב של פעולות' לגרום לקלט של קבצים, ועשויים למצות את מגבלת הנתיב.

  • השתמשו בשורש קצר של פלט.

    מומלץ להשתמש בסימון --output_user_root=<path> כדי לציין נתיב קצר לתוצאות של Bazel. כדאי להתקין כונן (או כונן וירטואלי) רק עבור פלטי Bazel (כגון קובץ D:\`), and adding this line to your.bazelrc).

    build --output_user_root=D:/
    

    או

    build --output_user_root=C:/_bzl
    
  • שימוש בצמתים.

    הצמתים מדברים בחופשיות[1], קישורים סימבוליים בספרייה. קל ליצור צמתים והם יכולים להפנות לספריות (באותו מחשב) עם מסלולים ארוכים. אם פעולת build יוצרת צומת שהנתיב שלו קצר אבל היעד שלו ארוך, כלים עם מגבלת נתיב קצרה יוכלו לגשת לקבצים בספריית הצמתים.

    בקובצי .bat או ב-cmd.exe אפשר ליצור צמתים כמו בדוגמה הבאה:

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

    [1]: באופן קפדני צמתים אינם קישורים סימבוליים, אבל לצורכי פעולות בנייה, אפשר להתייחס לצמתים כקישורים לספרייה.

  • יש להחליף את / ב-'` בנתיבים בפעולות / בסביבות.

    כשיוצרים את שורת הפקודה או את משתני הסביבה של פעולה, יוצרים את הנתיבים בסגנון Windows. דוגמה:

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

משתני סביבה

בעיות:

  • תלויי אותיות רישיות: שמות של משתני סביבה ב-Windows הם לא תלויי-רישיות.

    לדוגמה, ב-Java System.getenv("SystemRoot") וב-System.getenv("SYSTEMROOT") מניב את אותה תוצאה. (הפרט הזה חל גם על שפות אחרות.)

  • רגישות: הפעולות צריכות להשתמש בכמה שפחות משתני סביבה מותאמים אישית.

    משתני הסביבה הם חלק ממפתח המטמון של הפעולה. אם פעולה מסוימת משתמשת במשתני סביבה שמשתנים לעתים קרובות, או שהם מותאמים אישית למשתמשים, כלל זה עלול להקל על השמירה שלו.

פתרונות:

  • אפשר להשתמש רק בשמות של משתני סביבה באותיות גדולות.

    הפעולה הזו פועלת ב-Windows, ב-macOS וב-Linux.

  • מזעור סביבות פעולה.

    בעת שימוש ב-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) ב-Windows. לא ניתן לציין אותם בפורמט executable של ctx.actions.run. אין גם הרשאת +x לקבצים, ולכן אפשר לבצע קבצים שרירותיים כמו ב-Linux.

  • פקודות גיבוב (Bash): כדי לשמור על ניידות, לא מומלץ להפעיל פקודות באש ישירות בפעולות.

    Ash נרחבת בשימוש במערכות דמויי Unix, אבל לעיתים קרובות היא לא זמינה ב-Windows. מאחר ש-Bazel אינה תלויה פחות ופחות ב-Bash (MSYS2), סביר להניח שהמשתמשים לא יתקינו את MSYS2 ביחד עם Bazel. כדי שיהיה קל יותר להשתמש בכללים ב-Windows, מומלץ להימנע מהפעלת פקודות באש בפעולות.

  • סיומות שורות: ב-Windows נעשה שימוש ב-CRLF (\r\n), ובמערכות דמויי Unix נעשה שימוש ב-LF (\n).

    חשוב לדעת בעת השוואת קובצי טקסט. כדאי לשים לב להגדרות של Git, במיוחד לסיומות כשמשלמים או מבצעים. (יש לעיין בהגדרה של Git&core.autocrlf3).

פתרונות:

  • משתמשים בכלל שמבוסס על המטרה, בלי תוספות.

    native.genrule() הוא wrapper לפקודות באש, והוא משמש לעיתים קרובות לפתרון בעיות פשוטות, כמו העתקת קובץ או כתיבה של קובץ טקסט. תוכלו להימנע מהסתמכות על באס (ולהמציא את הגלגל מחדש): לראות אם לבזלת הבזלת יש כלל מיוחד למטרה שלכם. אף אחת מהן לא תלויה ב-Bash בבנייה/בדיקה ב-Windows.

    דוגמאות ליצירת כללים:

    • copy_file() (מקור, תיעוד): להעתיק קובץ במקום אחר, עם אפשרות להפוך אותו לקובץ הפעלה

    • write_file() (מקור, מסמכי תיעוד): כותב קובץ טקסט עם סיומות השורות הרצויות (auto, unix או windows), וזמין באופן אופציונלי לקובץ הפעלה (אם זה סקריפט)

    • run_binary() (מקור, מסמכי תיעוד): פועלים נתונים בינאריים (או כלל *_binary) עם קלט נתון ופלט צפוי כפעולה של build (זהו wrapper של כלל Build עבור ctx.actions.run)

    • native_binary() (מקור, מסמכי תיעוד): מכילה נתונים בינאריים מקומיים בכלל *_binary, שאפשר bazel run או להשתמש בו במאפיין run_binary()'s tool או במאפיין native.genrule()'s tools

    דוגמאות לכלל בדיקה:

    • diff_test() (מקור, תיעוד): בדיקה שמשווים בין תוכן של שני קבצים

    • native_test() (מקור, תיעוד): קובץ בינארי מקורי בכלל *_test, שאפשר bazel test

  • ב-Windows, מומלץ להשתמש ב-.bat סקריפטים לדברים טריוויים.

    במקום .sh סקריפטים, אפשר לפתור משימות טריוויאליות בעזרת .bat סקריפטים.

    לדוגמה, אם אתם צריכים סקריפט שלא עושה דבר, מדפיס הודעה או יוצא עם קוד שגיאה קבוע, מספיק קובץ .bat פשוט. אם הכלל שלכם מחזיר ספק DefaultInfo(), ייתכן שהשדה executable מתייחס לקובץ .bat הזה ב-Windows.

    ומאחר שסיומות הקבצים לא חשובות ב-macOS וב-Linux, תמיד אפשר להשתמש ב-.bat כתוסף, גם בסקריפטים של מעטפת.

    לידיעתך, לא ניתן להפעיל קובצי .bat ריקים. אם אתם צריכים סקריפט ריק, תוכלו לכתוב בו רווח.

  • השתמשו ב-Bash באופן עיקרי.

    ב-Sarlark Build ובדיקות כללים, השתמשו ב-ctx.actions.run_shell כדי להריץ סקריפטים של באש ופקודות בוש כפעולות.

    בפקודות מאקרו של Starlark, צריך להקיף סקריפטים ופקודות של Bash ב-native.sh_binary() או native.genrule(). Bazel יכולה לבדוק אם Bah זמין ולהריץ את הסקריפט או את הפקודה דרך Bash.

    בכללים של מאגר הסטארלארק צריך להימנע לגמרי מ-Bash. בשלב הזה בבזל לא מאפשרת להריץ פקודות ב-Bash באופן עיקרי בכללי מאגר.

מחיקת קבצים

בעיות:

  • לא ניתן למחוק קבצים כשהם פתוחים.

    לא ניתן למחוק קבצים פתוחים (כברירת מחדל), ניסיונות עלולים לגרום לשגיאות "גישה נדחתה" אם אי אפשר למחוק קובץ, יכול להיות שהתהליך עדיין פתוח.

  • לא ניתן למחוק ספריית עבודה של תהליך ריצה.

    לתהליכים יש ידית פתוחה לספריית העבודה שלהם, ולא ניתן למחוק את הספרייה עד לסיום התהליך.

פתרונות:

  • בקוד, נסו לסגור קבצים באופן יסודי.

    ב-Java, משתמשים ב-try-with-resources. ב-Python, יש להשתמש ב-with open(...) as f:. כעיקרון, נסו לסגור את נקודות האחיזה בהקדם האפשרי.