מדריך Bazel: בניית פרויקט C++

מבוא

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

Bazel היא מערכת build שתומכת ב-build בשפות מרובות, אבל בשיעור ההדרכה הזה תוכלו להשתמש בפרויקט +++ לדוגמה, שבו מפורטות ההנחיות הכלליות ותהליך העבודה ברוב השפות.

זמן סיום משוער: 30 דקות.

דרישות מוקדמות

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

לאחר מכן, צריך לאחזר את הפרויקט לדוגמה ממאגר ה-GitHub של Bazel. לשם כך, הפעילו את הכלי הבא בשורת הפקודה:

git clone https://github.com/bazelbuild/examples

הפרויקט לדוגמה במדריך הזה נמצא בספרייה examples/cpp-tutorial.

בטבלה הבאה אפשר לראות את המבנה שלה:

examples
└── cpp-tutorial
    ├──stage1
    │  ├── main
    │  │   ├── BUILD
    │  │   └── hello-world.cc
    │  └── WORKSPACE
    ├──stage2
    │  ├── main
    │  │   ├── BUILD
    │  │   ├── hello-world.cc
    │  │   ├── hello-greet.cc
    │  │   └── hello-greet.h
    │  └── WORKSPACE
    └──stage3
       ├── main
       │   ├── BUILD
       │   ├── hello-world.cc
       │   ├── hello-greet.cc
       │   └── hello-greet.h
       ├── lib
       │   ├── BUILD
       │   ├── hello-time.cc
       │   └── hello-time.h
       └── WORKSPACE

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

סיכום: מבוא

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

תחילת העבודה

הגדרת סביבת העבודה

כדי ליצור פרויקט, צריך להגדיר את סביבת העבודה שלו. 'סביבת עבודה' היא ספרייה ששומרת את קובצי המקור של הפרויקט ואת תוצרי ה-build של Bazel&39. הוא גם מכיל את הקבצים החשובים הבאים:

  • הדומיין WORKSPACE file , שמזהה את הספרייה והתוכן שלה כסביבת עבודה ב-Bazel ושוכן בבסיס מבנה הספרייה של הפרויקט.
  • BUILD files או יותר, שמסבירים לבזל איך לבנות חלקים שונים של הפרויקט. ספרייה בסביבת העבודה שמכילה קובץ BUILD היא חבילה. (מידע נוסף על חבילות מופיע בהמשך המדריך).

בפרויקטים עתידיים, כדי להגדיר ספרייה כסביבת עבודה של Bazel, יוצרים קובץ ריק בשם WORKSPACE בספרייה הזו. למטרות המדריך הזה, כבר קיים קובץ WORKSPACE בכל שלב.

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

הבנת קובץ ה-BUILD

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

הצצה בקובץ BUILD שבספרייה cpp-tutorial/stage1/main:

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
)

בדוגמה שלנו, היעד hello-world משקף את המודעה המובנית של Bazel&#39 cc_binary rule. הכלל מורה ל-Bazel לבנות קובץ הפעלה בינארי עצמאי מקובץ המקור hello-world.cc ללא יחסי תלות.

סיכום: תחילת העבודה

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

שלב 1: יעד יחיד, חבילה בודדת

הגיע הזמן לבנות את החלק הראשון של הפרויקט. בתור דוגמה, המבנה של שלב 1 בפרויקט הוא:

examples
└── cpp-tutorial
    └──stage1
       ├── main
       │   ├── BUILD
       │   └── hello-world.cc
       └── WORKSPACE

על מנת לעבור אל הספרייה cpp-tutorial/stage1:

cd cpp-tutorial/stage1

השלב הבא:

bazel build //main:hello-world

בתווית היעד, החלק //main: הוא המיקום של הקובץ BUILD ביחס לשורש העבודה, וה-hello-world הוא שם היעד בקובץ BUILD.

Bazel מפיקה משהו שנראה כך:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 2.267s, Critical Path: 0.25s

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

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

bazel-bin/main/hello-world

התוצאה היא הודעת"Hello world"מודפסת.

תרשים התרשים הבא של שלב 1:

תרשים תלות של שלום עולם מציג יעד יחיד עם קובץ מקור יחיד.

סיכום: שלב 1

אחרי שסיימתם את הגרסה הראשונה, יש לכם מושג בסיסי לגבי המבנה של גרסת ה-build. בשלב הבא, תוסיפו מורכבות על ידי הוספת יעד נוסף.

שלב 2: ריבוי יעדי build

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

זו הספרייה שאיתה אתם עובדים בשלב 2:

    ├──stage2
    │  ├── main
    │  │   ├── BUILD
    │  │   ├── hello-world.cc
    │  │   ├── hello-greet.cc
    │  │   └── hello-greet.h
    │  └── WORKSPACE

יש לבדוק את הקובץ BUILD שבספרייה cpp-tutorial/stage2/main:

cc_library(
    name = "hello-greet",
    srcs = ["hello-greet.cc"],
    hdrs = ["hello-greet.h"],
)

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
    deps = [
        ":hello-greet",
    ],
)

עם קובץ BUILD זה, בזל בונה תחילה את ספריית hello-greet (באמצעות Bazel's cc_library rule), ולאחר מכן הקובץ הבינארי של hello-world. המאפיין deps ביעד hello-world מורה ל-Bazel שהספרייה hello-greet נדרשת כדי ליצור את הקובץ הבינארי של hello-world.

לפני שניתן יהיה לבנות את הגרסה החדשה הזו של הפרויקט, צריך לשנות את הספריות. לשם כך, צריך לעבור לספרייה cpp-tutorial/stage2:

cd ../stage2

עכשיו אפשר לבנות את הקובץ הבינארי החדש באמצעות הפקודה המוכרת הבאה:

bazel build //main:hello-world

שוב, בזל מפיקה משהו שנראה כך:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 2.399s, Critical Path: 0.30s

עכשיו אפשר לבדוק את הקובץ הבינארי החדש שמחזיר"Hello world":

bazel-bin/main/hello-world

אם תשנו עכשיו את hello-greet.cc ובנוי מחדש את הפרויקט, Bazel מהדר מחדש את הקובץ הזה.

אם תבחנו את תרשים התלות אפשר לראות שעולם השלום תלוי באותם הנתונים שהוזנו, אבל המבנה של ה-build שונה:

תרשים תלות של 'hello-world' מציג שינויים במבנה לאחר השינוי בקובץ.

סיכום: שלב 2

סיימת ליצור את הפרויקט עם שני יעדים. היעד hello-world יוצר קובץ מקור אחד ותלוי ביעד אחד נוסף (//main:hello-greet), שיוצר שני קובצי מקור נוספים. בקטע הבא, מתקדמים לשלב הבא ומוסיפים חבילה נוספת.

שלב 3: חבילות מרובות

השלב הבא מוסיף עוד שלב לסיבוך ויוצר פרויקט עם מספר חבילות. הנה הסבר על המבנה והתוכן של ספריית cpp-tutorial/stage3:

└──stage3
   ├── main
   │   ├── BUILD
   │   ├── hello-world.cc
   │   ├── hello-greet.cc
   │   └── hello-greet.h
   ├── lib
   │   ├── BUILD
   │   ├── hello-time.cc
   │   └── hello-time.h
   └── WORKSPACE

ניתן לראות שעכשיו יש שתי ספריות משנה, וכל אחת מהן מכילה קובץ BUILD. לכן, ב-Bazel סביבת העבודה מכילה עכשיו שתי חבילות: lib ו-main.

מומלץ לעיין בקובץ lib/BUILD:

cc_library(
    name = "hello-time",
    srcs = ["hello-time.cc"],
    hdrs = ["hello-time.h"],
    visibility = ["//main:__pkg__"],
)

ובקובץ main/BUILD:

cc_library(
    name = "hello-greet",
    srcs = ["hello-greet.cc"],
    hdrs = ["hello-greet.h"],
)

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
    deps = [
        ":hello-greet",
        "//lib:hello-time",
    ],
)

היעד hello-world בחבילה הראשית תלוי ביעד hello-time בחבילה lib (ולכן תווית היעד //lib:hello-time) – הבזל יודע זאת באמצעות המאפיין deps. ניתן לראות זאת בתרשים התלות:

תרשים תלות של 'hello-world' מראה כיצד היעד בחבילה הראשית תלוי ביעד בחבילה 'lib'.

כדי שהפרויקט יצליח, צריך להגדיר את היעד //lib:hello-time בlib/BUILD באופן מפורש ליעדים ב-main/BUILD, באמצעות מאפיין החשיפה. הסיבה לכך היא שיעדי ברירת מחדל גלויים רק ליעדים אחרים באותו קובץ BUILD. Bazel משתמשת בניראות של יעדים כדי למנוע בעיות, כמו ספריות שמכילות פרטי דליפה לממשקי API ציבוריים.

עכשיו צריך לבנות את הגרסה הסופית של הפרויקט. אפשר לעבור לספרייה cpp-tutorial/stage3 על ידי הרצת:

cd  ../stage3

ושוב, מריצים את הפקודה הבאה:

bazel build //main:hello-world

Bazel מפיקה משהו שנראה כך:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 0.167s, Critical Path: 0.00s

עכשיו יש לבדוק את הקובץ הבינארי האחרון של המדריך הזה כדי לקבל את הודעת Hello world הסופית:

bazel-bin/main/hello-world

סיכום: שלב 3

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

השלבים הבאים

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

בניין שמח!