פלטפורמות

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

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

Bazel מזהה שלושה תפקידים שפלטפורמה יכולה למלא:

  • מארח – הפלטפורמה שבה פועל Bazel עצמה.
  • ביצוע – פלטפורמה שבה כלי ה-build מבצעים פעולות build כדי ליצור פלט ביניים ופלט סופי.
  • Target – פלטפורמה שבה ממוקם הפלט הסופי ומבצע אותו.

Bazel תומכת בתרחישי build הבאים בנוגע לפלטפורמות:

  • גרסאות build של פלטפורמה יחידה (ברירת מחדל) – פלטפורמות מארח, ביצוע ויעד זהות. לדוגמה, בניית הפעלה של Linux ב-Ubuntu פועלת במעבד Intel x64.

  • יצירת אוספים בהרכבות שונות – פלטפורמת האירוח והפלטפורמה זהות, אבל פלטפורמת היעד שונה. לדוגמה, בניית אפליקציה ל-iOS ב-macOS Pro ב-MacBook Pro.

  • פלטפורמות ליצירת פלטפורמות מרובות – המארחות, הביצוע ופלטפורמות היעד שונות זו מזו.

הגדרת אילוצים ופלטפורמות

המרחב המשותף של אפשרויות אפשריות לפלטפורמות מוגדר באמצעות הכללים constraint_setting ו-constraint_value בתוך קובצי BUILD. המאפיין constraint_setting יוצר מאפיין חדש, ואילו constraint_value יוצר ערך חדש למאפיין נתון. יחד, הם מגדירים בפועל 'enum' (ערכים) ואת הערכים האפשריים שלהם. לדוגמה, קטע הקוד הבא של קובץ BUILD מציין מגבלה לגרסת ה-glibc של המערכת עם שני ערכים אפשריים.

constraint_setting(name = "glibc_version")

constraint_value(
    name = "glibc_2_25",
    constraint_setting = ":glibc_version",
)

constraint_value(
    name = "glibc_2_26",
    constraint_setting = ":glibc_version",
)

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

הכלל platform משיק פלטפורמה חדשה עם אפשרויות מסוימות לקביעת ערכי אילוץ. בהמשך מופיעה פלטפורמה בשם linux_x86 שאומרת שהיא מתארת סביבה שמריצה מערכת הפעלה של Linux עם ארכיטקטורת x86_64 עם גרסה 2.25 של Glibc. (ראו מידע נוסף על אילוצים מובנים של Bazel&#39).

platform(
    name = "linux_x86",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        ":glibc_2_25",
    ],
)

אילוצים ופלטפורמות שימושיים באופן כללי

כדי לשמור על עקביות בסביבה העסקית, צוות Bazel מנהל מאגר עם הגדרות מוגבלות לארכיטקטורות ה-CPU ומערכות ההפעלה הפופולריות ביותר. כל אלה נמצאים בכתובת https://github.com/bazelbuild/platforms.

Bazship ships עם ההגדרה המיוחדת הבאה של הפלטפורמה: @local_config_platform//:host. זהו הערך של פלטפורמת המארח שזוהה באופן אוטומטי – מייצג את הפלטפורמה שזוהתה באופן אוטומטי עבור המערכת ש-Bazel פועל בה.

ציון פלטפורמה עבור build

אפשר לציין את פלטפורמת המארח ואת פלטפורמת היעד לגרסת ה-build באמצעות הסימונים הבאים בשורת הפקודה:

  • --host_platform – ברירת מחדל היא @bazel_tools//platforms:host_platform
  • --platforms – ברירת מחדל היא @bazel_tools//platforms:target_platform

מדלג על יעדים לא תואמים

כשמפתחים פלטפורמת פלטפורמה ספציפית, לעיתים קרובות עדיף לדלג על יעדים אף פעם לא יפעלו בפלטפורמה הזו. לדוגמה, סביר להניח שהנהג של מכשיר Windows יפיק הרבה שגיאות מהדר במהלך יצירה במחשב Linux עם //.... משתמשים במאפיין target_compatible_with כדי לספר ל-Bazel אילו מגבלות יש לקוד של פלטפורמת היעד.

השימוש הפשוט ביותר במאפיין הזה מגביל יעד לפלטפורמה יחידה. היעד לא יהיה מבוסס על פלטפורמה שלא עומדת בכל המגבלות. בדוגמה הבאה, win_driver_lib.cc מוגבל ל-64 ביט של Windows.

cc_library(
    name = "win_driver_lib",
    srcs = ["win_driver_lib.cc"],
    target_compatible_with = [
        "@platforms//cpu:x86_64",
        "@platforms//os:windows",
    ],
)

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

מתי מדלגים על יעדים?

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

$ bazel build --platforms=//:myplatform //...
$ bazel build --platforms=//:myplatform //:all

המערכת תדלג באופן דומה על בדיקות לא תואמות ב-test_suite גם אם ה-test_suite מצוין בשורת הפקודה עם --expand_test_suites. כלומר, test_suite יעדים בשורת הפקודה מתנהגים כמו :all ו-.... השימוש ב---noexpand_test_suites מונע הרחבה וגורם גם לחוסר התאמה בtest_suite יעדים עם בדיקות לא תואמות.

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

$ bazel build --platforms=//:myplatform //:target_incompatible_with_myplatform
...
ERROR: Target //:target_incompatible_with_myplatform is incompatible and cannot be built, but was explicitly requested.
...
FAILED: Build did NOT complete successfully

אילוצים מבטאים יותר

אם אתם לא רוצים לבטא אילוצים, אפשר להשתמש @platforms//:incompatible constraint_value בפלטפורמה שלא עומדת בדרישות שלנו.

השתמשו ב-select() בשילוב עם @platforms//:incompatible כדי לבטא הגבלות מורכבות יותר. לדוגמה, השתמשו בו כדי ליישם לוגיקת OR בסיסית. ברשימה שבהמשך מצוין ספרייה שתואמת ל-macOS ול-Linux, אבל לא קיימות פלטפורמות אחרות.

cc_library(
    name = "unixish_lib",
    srcs = ["unixish_lib.cc"],
    target_compatible_with = select({
        "@platforms//os:osx": [],
        "@platforms//os:linux": [],
        "//conditions:default": ["@platforms//:incompatible"],
    }),
)

אפשר לפרש את המידע הזה באופן הבא:

  1. כשמטרגטים ל-macOS, אין הגבלות.
  2. כשמטרגטים ל-Linux, אין הגבלות.
  3. אם לא, היעד כולל את המגבלה @platforms//:incompatible. היעד @platforms//:incompatible לא שייך לפלטפורמה כלשהי, ולכן הוא לא תואם.

כדי שהאילוצים יהיו קריאים יותר, השתמשו ב-skylib'sselects.with_or().

אתם יכולים לבטא תאימות הפוכה באופן דומה. הדוגמה הבאה מתארת ספרייה שתואמת לכל דבר למעט ARM.

cc_library(
    name = "non_arm_lib",
    srcs = ["non_arm_lib.cc"],
    target_compatible_with = select({
        "@platforms//cpu:arm": ["@platforms//:incompatible"],
        "//conditions:default": [],
    ],
)

זיהוי יעדים לא תואמים באמצעות bazel cquery

אתם יכולים להשתמש IncompatiblePlatformProvider בפורמט סטארליק bazel cqueryכדי להבחין בין יעדים לא תואמים ליעדים תואמים.

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

$ cat example.cquery

def format(target):
  if "IncompatiblePlatformProvider" not in providers(target):
    return target.label
  return ""


$ bazel cquery //... --output=starlark --starlark:file=example.cquery

בעיות ידועות

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