עבודה עם תלות חיצונית

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

הקובץ WORKSPACE (או קובץ ה-WORKSPACE.bazel) בספרייה של סביבת העבודה מורה ל-Bazel איך להשיג מקורות של פרויקטים אחרים. הפרויקטים האחרים יכולים לכלול קובץ אחד או יותר מסוג BUILD עם יעדים משלהם. BUILD קבצים בתוך הפרויקט הראשי יכולים להיות תלויים ביעדים החיצוניים האלו על ידי שימוש בשם שלהם מקובץ ה-WORKSPACE.

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

/
  home/
    user/
      project1/
        WORKSPACE
        BUILD
        srcs/
          ...
      project2/
        WORKSPACE
        BUILD
        my-libs/

אם project1 רוצה להיות תלוי ביעד, :foo, המוגדר ב-/home/user/project2/BUILD, הוא עשוי לציין שמאגר בשם project2 נמצא ב-/home/user/project2. היעדים ב/home/user/project1/BUILD עשויים להיות תלויים ב@project2//:foo.

הקובץ WORKSPACE מאפשר למשתמשים להסתמך על יעדים מהחלקים האחרים של מערכת הקבצים, או שהם מורידים מהאינטרנט. התחביר משתמש באותו תחביר של קובצי BUILD, אך מאפשר קבוצה שונה של כללים הנקראת כללי מאגר (הנקראים לפעמים גם כללי סביבת עבודה) הנתונים. Bazel מגיעה עם כמה כללים מובנים של מאגר נתונים וקבוצה של כללים מוטמעים עבור מאגר Starlark. משתמשים יכולים גם לכתוב כללים למאגר מותאם אישית כדי לקבל התנהגות מורכבת יותר.

סוגים נתמכים של יחסי תלות חיצוניים

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

בהתאם לפרויקטים אחרים בבזל

אם רוצים להשתמש ביעדים מפרויקט בזל נוסף, אפשר להשתמש ב-local_repository, git_repository או http_archive כדי לקשר אותו למערכת הקבצים המקומית, להפנות למאגר Git או להוריד אותו (בהתאמה).

לדוגמה, נניח שאתה עובד בפרויקט my-project/, וברצונך להיות תלוי ביעדים מפרויקט הקולגות שלך, coworkers-project/. שני הפרויקטים משתמשים ב-Bazel, כך שניתן להוסיף את הפרויקט של העמית כתלות חיצונית ולאחר מכן להשתמש ביעדים שהגדיר העמית מקובצי BUILD משלך. צריך להוסיף את הערכים הבאים ל-my_project/WORKSPACE:

local_repository(
    name = "coworkers_project",
    path = "/path/to/coworkers-project",
)

אם לעמית לעבודה יש יעד //foo:bar, הפרויקט יכול להתייחס אליו כ-@coworkers_project//foo:bar. שמות של פרויקטים חיצוניים חייבים להיות שמות חוקיים של סביבות עבודה.

בהתאם לפרויקטים שאינם ב-Bazel

כללים עם תחילית new_, כמו new_local_repository, מאפשרים לך ליצור יעדים מפרויקטים שאינם משתמשים ב-Bazel.

לדוגמה, נניח שאתה עובד על פרויקט, my-project/, וברצונך להיות תלוי בפרויקט העמית לעבודה, coworkers-project/. לצורך יצירתו, העמית שלך משתמש ב-make, אך ברצונך להסתמך על אחד מקובצי ה-so .שהוא יוצר. כדי לעשות זאת, יש להוסיף את הפרטים הבאים ל-my_project/WORKSPACE:

new_local_repository(
    name = "coworkers_project",
    path = "/path/to/coworkers-project",
    build_file = "coworker.BUILD",
)

build_file מציין קובץ BUILD עבור שכבת-על בפרויקט הקיים, לדוגמה:

cc_library(
    name = "some-lib",
    srcs = glob(["**"]),
    visibility = ["//visibility:public"],
)

לאחר מכן תהיה לך אפשרות להיות תלוי ב-@coworkers_project//:some-lib מקובצי הפרויקט של BUILD.

בהתאם לחבילות חיצוניות

פריטים ומאגרים של Maven

אפשר להשתמש בכללי הכללים rules_jvm_external כדי להוריד פריטי מידע שנוצרו בתהליך פיתוח (Artifact) ממאגרי Maven ולהפוך אותם לזמינים כתלויי Java.

תלוי תלות

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

יחסי תלות בצללית

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

הפרויקט שלי/WORKSPACE

workspace(name = "myproject")

local_repository(
    name = "A",
    path = "../A",
)
local_repository(
    name = "B",
    path = "../B",
)

A/WORKSPACE

workspace(name = "A")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "testrunner",
    urls = ["https://github.com/testrunner/v1.zip"],
    sha256 = "...",
)

B/WORKSPACE

workspace(name = "B")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "testrunner",
    urls = ["https://github.com/testrunner/v2.zip"],
    sha256 = "..."
)

התלות של A ו-B תלויות ב-testrunner, אבל הן תלויות בגרסאות שונות של testrunner. אין שום סיבה שרצות המבחן לא מקיימים דו-קיום בשקט עם myproject, אך הם יתנגשו זה עם זה מכיוון שיש להם אותו שם. כדי להצהיר על שני יחסי תלות, יש לעדכן את הפרויקט שלי/WORKSPACE:

workspace(name = "myproject")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "testrunner-v1",
    urls = ["https://github.com/testrunner/v1.zip"],
    sha256 = "..."
)
http_archive(
    name = "testrunner-v2",
    urls = ["https://github.com/testrunner/v2.zip"],
    sha256 = "..."
)
local_repository(
    name = "A",
    path = "../A",
    repo_mapping = {"@testrunner" : "@testrunner-v1"}
)
local_repository(
    name = "B",
    path = "../B",
    repo_mapping = {"@testrunner" : "@testrunner-v2"}
)

ניתן להשתמש במנגנון הזה גם כדי להצטרף ליהלומים. לדוגמה, אם ל-A ול-B הייתה תלות זהה, אבל יש לקרוא לה בשמות שונים, אפשר לצרף את התלות הזו בפרויקט שלי/WORKSPACE.

עקיפת מאגרים משורת הפקודה

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

לדוגמה, כדי לעקוף את @foo לספרייה המקומית /path/to/local/foo, יש להעביר את הסימון --override_repository=foo=/path/to/local/foo.

דוגמאות לתרחישים לדוגמה:

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

שימוש בשרתי proxy

Bazel תאסוף כתובות proxy ממשתני הסביבה HTTPS_PROXY ו-HTTP_PROXY ותשתמש בהן כדי להוריד קובצי HTTP/HTTPS (אם צוינו).

תמיכה ב-IPv6

במחשבים עם IPv6 בלבד, Bazel תוכל להוריד יחסי תלות ללא שינויים. עם זאת, מכונות IPv4 ו-IPv6 עם ערימות כפולות עושות שימוש באותה מוסכמה כמו Java: אם IPv4 מופעל, מומלץ להשתמש ב-IPv4. במצבים מסוימים, לדוגמה כשרשת IPv4 לא מצליחה לפענח/להגיע לכתובות חיצוניות, ייתכנו בעיות חריגות ב-Network unreachable ובעיות בנייה. במקרים כאלה, אפשר לעקוף את ההתנהגות של Bazel ולהעדיף את IPv6 על ידי שימוש במאפיין המערכת של java.net.preferIPv6Addresses=true. פרטים נוספים:

  • השתמשו ב--host_jvm_args=-Djava.net.preferIPv6Addresses=true אפשרות ההפעלה, למשל על ידי הוספת השורה הבאה בקובץ .bazelrc:

    startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true

  • אם בחרת להריץ יעדי build של Java שצריכים להתחבר גם לאינטרנט (לבדיקות ההטמעה לפעמים יש צורך בשיטה הזו), כדאי להשתמש גם ב---jvmopt=-Djava.net.preferIPv6Addresses=true דגל כלים, לדוגמה, על ידי הוספת השורה הבאה לקובץ .bazelrc:

    build --jvmopt=-Djava.net.preferIPv6Addresses

  • אם משתמשים rules_jvm_external , לדוגמה, לרזולוציה של גרסת תלות, יש להוסיף גם-Djava.net.preferIPv6Addresses=true אלCOURSIER_OPTS משתנה סביבה עבורהזנת אפשרויות JVM לקורס

יחסי תלות טרנזיטיביים

Bazel קוראת יחסי תלות בלבד המפורטים בקובץ WORKSPACE שלך. אם הפרויקט שלך (A) תלוי בפרויקט אחר (B) שרשמת תלות בו בפרויקט שלישי (C) בקובץ WORKSPACE, צריך להוסיף את B ואת C לקובץ WORKSPACE של הפרויקט. דרישה זו יכולה להוסיף בועות לגודל הקובץ WORKSPACE, אבל קיימת הגבלה על הסיכויים שספרייה אחת תכלול את C בגרסה 1.0 ואחרת תכלול את C בגרסה 2.0.

מתבצעת שמירה של יחסי תלות חיצוניים

כברירת מחדל, Bazel תוריד מחדש יחסי תלות חיצוניים רק אם ההגדרה שלהם משתנה. בנוסף, שינויים בקבצים שהוזכרו בהגדרה (כגון תיקונים או קובצי BUILD) נלקחים בחשבון גם הם.

כדי לאלץ הורדה חוזרת, השתמש ב-bazel sync.

פריסה

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

ls $(bazel info output_base)/external

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

גרסאות אופליין

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

עבור גרסאות build לא מקוונות אמיתיות, שבהן אספקת הקבצים הנדרשים היא ישות על ידי ישות השונה מ-Bazel, Bazel תומך באפשרות הזו. --distdir בכל פעם שכלל של מאגר מבקש מ-Bazel לאחזר קובץ דרך ctx.download או ctx.download_and_extract והוא מספק סכום גיבוב (hash) הקובץ דרוש, בזל תבחן תחילה את הספריות שצוינו באפשרות זו עבור קובץ המתאים לשם הבסיס של כתובת האתר הראשונה שסופקה, ותשתמש בעותק מקומי זה אם הגיבוב תואם.

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

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

שיטות מומלצות

כללי המאגר

כלל של מאגר צריך להיות אחראי באופן כללי ל:

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

נמנעים משימוש בrepository_ctx.execute כאשר אפשר. לדוגמה, כשמשתמשים ב-C++ (ספרייה שאינה +Bazel) שיש לה build באמצעות Make, עדיף להשתמש ב-repository_ctx.download() ולאחר מכן לכתוב קובץ BUILD שיוצר אותו, במקום להריץ את ctx.execute(["make"]) הנתונים.

העדפה לhttp_archive git_repository ו new_git_repository. הסיבות לכך הן:

  • כללי מאגר הנתונים של Git תלויים במערכת git(1), בעוד שהורדה של HTTP מובנית ב-Bazel ואין לה יחסי תלות של המערכת.
  • http_archive תומך ברשימה של urls כמראות, ו-git_repository תומך רק ב-remote יחיד.
  • ניתן להשתמש בhttp_archive יחד עם המטמון של המאגר, אך לא git_repository. למידע נוסף, אפשר לעיין כאן: #5116.

אין להשתמש בקוד bind(). עיינו במאמר "כדאי להסיר את הכריכה