מדריך בסגנון .bzl

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

Starlark היא שפה שמגדירה את אופן היצירה של תוכנה, ולכן היא תואמת לשפת תכנות.

ניתן להשתמש ב-Starlark כדי לכתוב BUILD קבצים, פקודות מאקרו ובניית כללים. למעשה, מאקרו וכללים הם מטא-שפות – הם מגדירים את אופן הכתיבה של קובצי BUILD. BUILD קבצים צריכים להיות פשוטים וחוזרים על עצמם.

המערכת קוראת כל תוכנה בתדירות גבוהה יותר ממה שכתוב בה. זה נכון במיוחד לגבי Starlark, מכיוון שמהנדסים קוראים קובצי BUILD כדי להבין את התלות שלהם ביעדים ובפרטים של ה-build שלהם. קריאה זו מתרחשת בדרך כלל מהר, במהירות, או במקביל לביצוע משימה אחרת כלשהי. לכן חשוב מאוד להשתמש בפשטות ובקריאות, כדי שמשתמשים יוכלו לנתח ולהבין BUILD קבצים במהירות.

כשמשתמש פותח קובץ BUILD, הוא רוצה להכיר במהירות את רשימת היעדים שבקובץ, או לבדוק את רשימת המקורות שמשויכים לאותה ספריית C++ או להסיר תלות בבינארי של Java. בכל פעם שמוסיפים שכבה של הפשטה, קשה למשתמש לבצע את המשימות האלה.

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

ייעוץ כללי

סגנון

סגנון Python

אם יש לכם ספק, תוכלו להיעזר במדריך הסגנון PEP 8, באופן ספציפי, יש להשתמש בארבעה רווחים במקום בשני רווחים כדי לפעול בהתאם למוסכמות של Python.

מכיוון ש-Starlark אינה Python, חלק מההיבטים בסגנון Python לא חלים. לדוגמה, ב-PEP 8 מומלץ לבצע השוואה בין סינגלטון לבין is, שהוא לא אופרטור ב-Starlark.

יצירת מסמכים

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

כללים והיבטים של מסמכים

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

מוסכמה למתן שמות

  • משתנים ושמות של פונקציות כוללים אותיות קטנות המופרדות באמצעות קו תחתון ([a-z][a-z0-9_]*), למשל cc_library.
  • ערכים פרטיים ברמה העליונה מתחילים בקו תחתון אחד. מאחר ש-Bazel מבצעת אכיפה, לא ניתן להשתמש בערכים פרטיים מקבצים אחרים. משתנים מקומיים לא צריכים להשתמש בקידומת הקו התחתון.

אורך קו

כמו ב-BUILD קבצים, אין הגבלה מחמירה על אורך השורה, מאחר שתוויות יכולות להיות ארוכות. כשהדבר אפשרי, נסו להשתמש ב-79 תווים לכל היותר בכל שורה (בהתאם למדריך הסגנון של Python&#39, PEP 8). אין לאכוף מדיניות זו במפורש: עורכים צריכים להציג יותר מ-80 עמודות, שינויים אוטומטיים יציגו לעתים קרובות שורות ארוכות יותר, ואנשים לא יצטרכו להקדיש זמן לפיצול שורות שכבר ניתן לקרוא אותן.

ארגומנטים למילת מפתח

בארגומנטים של מילות מפתח, מרחבים מסביב לסימן עדיף:

def fct(name, srcs):
    filtered_srcs = my_filter(source = srcs)
    native.cc_library(
        name = name,
        srcs = filtered_srcs,
        testonly = True,
    )

ערכים בוליאניים

עדיף להשתמש בערכים True ו-False (במקום 1 ו-0) כדי להזין ערכים בוליאניים (למשל, כשמשתמשים במאפיין בוליאני בכלל).

אין להשתמש בפונקציה print() בקוד הייצור. היא מיועדת רק לניפוי באגים והיא תשלח ספאם לכל המשתמשים הישירים והעקיפים בקובץ ה-.bzl. המקרה החריג היחיד הוא שניתן לשלוח קוד שמשתמש ב-print() אם הוא מושבת כברירת מחדל וניתן להפעיל אותו רק על ידי עריכת המקור. לדוגמה, אם כל השימושים ב-print() מוגנים על ידי if DEBUG:, שבהם קוד הגישה בתוך הקוד הוא DEBUG אל False. כדאי לשים לב אם ההצהרות האלה מועילות מספיק כדי להצדיק את ההשפעה שלהן על הקריאות.

פקודות מאקרו

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

לכן, כשמשהו משתבש, המשתמש צריך להבין את יישום המאקרו שלך כדי לפתור בעיות build. בנוסף, לפעמים קשה לפרש את התוצאות ב-bazel query כי היעדים המוצגים בתוצאות מגיעים מהרחבת מאקרו. לבסוף, היבטים לא מודעים לפונקציות המאקרו, ולכן כלים התלויים בהיבטים מסוימים (IDE או אחרים) עלולים להיכשל.

שימוש בטוח ברכיבי מאקרו הוא לצורך הגדרת יעדים נוספים שיופנו ישירות ל-Bazel CLI או בקובצי BUILD: במקרה כזה, רק משתמשי הקצה של היעדים האלה צריכים לדעת, וכל בעיה בבנייה שהוגדרה על ידי פקודות מאקרו אף פעם לא רחוקה מהשימוש בהם.

עבור פקודות מאקרו המגדירות יעדים שנוצרו (פרטי יישום של המאקרו שאינם אמורים להיות מוזכרים ב-CLI או שאינם תלויים ביעדים שמאקרו זה לא יוצר), יש לפעול לפי השיטות המומלצות הבאות:

  • רכיב מאקרו צריך לכלול ארגומנט name ולהגדיר יעד בשם זה. היעד הזה הופך למאקרו הראשי של המאקרו.
  • יעדים שנוצרים, כלומר כל היעדים האחרים שהוגדרו על ידי מאקרו, צריכים:
    • הקידומת של השמות שלהם היא <name> או _<name>. לדוגמה, אם משתמשים ב-name = '%s_bar' % (name).
    • הרשאות גישה מוגבלות (//visibility:private) ו-
    • להוסיף תג manual כדי למנוע הרחבה ביעדים עם תווים כלליים לחיפוש (:all, ..., :* וכו').
  • יש להשתמש ב-name כדי להסיק שמות של יעדים רק על ידי המאקרו, ולא בשום דבר אחר. לדוגמה, אין להשתמש בשם כדי לגבש תלות או קובץ קלט שלא נוצרו על ידי המאקרו עצמו.
  • יש להתאים את כל היעדים שנוצרו במאקרו בדרך מסוימת אל היעד הראשי.
  • בודקים שהשמות של הפרמטרים במאקרו עקביים. אם פרמטר מועבר בתור ערך מאפיין ליעד הראשי, יש להשאיר את השם שלו זהה. אם הפרמטר של המאקרו משמש לאותה מטרה כמו מאפיין של כלל נפוץ, כמו deps, השם שלו הוא זהה לשם של המאפיין (ראו בהמשך).
  • כשקוראים מאקרו, השתמשו בארגומנטים של מילות מפתח בלבד. הערכים האלה תואמים לכללים, ומשפרים משמעותית את הקריאות.

לעיתים קרובות מהנדסים כותבים פקודות מאקרו כאשר ה-Starlark API של כללים רלוונטיים אינו מתאים לתרחיש לדוגמה הספציפי שלהם, בין שהוא מוגדר ב-Bazel בקוד מקורי ובין שלא. אם אתם נתקלים בבעיה הזו, שאלו את מחבר הכללים אם הוא יכול להרחיב את ה-API כדי להשיג את היעדים.

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

ראו גם פקודות מאקרו.

כללים

  • בכללים, בהיבטים ובמאפיינים שלהם צריך להשתמש בשמות באותיות קטנות ("snake case").
  • שמות של כללים הם שמות עצם המתארים את סוג פריט המידע העיקרי שנוצר על ידי הכלל, מנקודת המבט של יחסי תלות שלו (או עבור כללי עלה, המשתמש). זו לא בהכרח סיומת של קובץ. לדוגמה, כלל שמייצר פריטי C++ שמשמשים כתוספים ב-Python עשוי להיקרא py_extension. ברוב השפות, הכללים האופייניים כוללים:
    • *_library - יחידת הידור או "module".
    • *_binary – יעד שמייצר יחידת הפעלה או יחידת פריסה.
    • *_test – יעד בדיקה. מספר הבדיקות יכול לכלול כמה בדיקות. סביר להניח שכל הבדיקות ביעד *_test יהיו וריאציות על אותו נושא, כמו בדיקת ספרייה אחת.
    • *_import: יעד שכולל פריט מידע שנוצר בתהליך הגדרה מראש, כמו .jar, או .dll שמשמש במהלך האוסף.
  • עקביות במאפיינים ובשמות. דוגמאות למאפיינים שרלוונטיים באופן כללי:
    • srcs: label_list, מתן גישה לקבצים: קובצי מקור, בדרך כלל על ידי אדם.
    • deps: label_list, לרוב לא מאפשרים קבצים: יחסי תלות של אוספים.
    • data: label_list, מתן אפשרות לקבצים: קובצי נתונים, כגון נתוני בדיקה וכו'.
    • runtime_deps: label_list: יחסי תלות בזמן ריצה שאינם נדרשים לאיסוף.
  • לגבי מאפיינים בעלי התנהגות לא ברורה (לדוגמה, תבניות מחרוזת עם תחליפים מיוחדים, או כלים שמופעלים בהתאם לדרישות ספציפיות), יש לספק תיעוד עם ארגומנט מילת המפתח doc עבור ההצהרה 'מאפיין' (attr.label_list() או מאפיינים דומים).
  • פונקציות ההטמעה של כללים צריכות להיות כמעט תמיד פונקציות פרטיות (שנקראות קו תחתון מוביל). סגנון נפוץ הוא לתת לפונקציית myrule את השם _myrule_impl.
  • להעביר מידע בין הכללים שלך באמצעות ממשק ספק מוגדר היטב. הצהרה על שדות של ספקי מסמכים ומסמכים.
  • מעצבים את הכלל לפי יכולת הרחבה. כדאי לשקול כללים אחרים שאולי תרצו לקיים אינטראקציה עם הכלל שלכם, לגשת לספקים ולעשות שימוש חוזר בפעולות שיצרתם.
  • מומלץ לפעול לפי הנחיות הביצועים בכללים.