המדריך הזה משתמש בתרחיש לדוגמה כדי לתאר את אופן ההגדרה של כלי C++
לפרויקט. הוא מבוסס על
פרויקט לדוגמה C++
שיוצר מבנים ללא שגיאות באמצעות clang
.
מה תלמדו
במדריך הזה לומדים איך:
- הגדרה של סביבת ה-build
- הגדרת מחזיק הכלים C++
- יצירת כלל של Starlark שמספק תצורה נוספת עבור
cc_toolchain
כדי ש-Bazel תוכל לבנות את האפליקציה עםclang
- כדי לאשר את התוצאה הצפויה, יש להפעיל את
bazel build --config=clang_config //main:hello-world
במחשב Linux - בניית האפליקציה C++
לפני שמתחילים
הגדרה של סביבת ה-build
המדריך הזה מבוסס על ההנחה שאתם משתמשים ב-Linux ובנו בהצלחה
C++ אפליקציות והתקנתם את הכלים והספריות המתאימים.
המדריך משתמש ב-clang version 9.0.1
, שאותו אפשר להתקין במערכת.
מגדירים את סביבת ה-build באופן הבא:
אם עדיין לא עשית זאת, יש להוריד ולהתקין את Bazel 0.23 ואילך.
הורידו את הפרויקט לדוגמה C++ מ-GitHub והציבו אותו בספרייה ריקה במחשב המקומי שלכם.
מוסיפים את היעד
cc_binary
הבא לקובץmain/BUILD
:cc_binary( name = "hello-world", srcs = ["hello-world.cc"], )
כדי לאפשר שימוש בסימון
--config
, יש ליצור קובץ.bazelrc
בשורש הספרייה של סביבת העבודה עם התוכן הבא:# Use our custom-configured c++ toolchain. build:clang_config --crosstool_top=//toolchain:clang_suite # Use --cpu as a differentiator. build:clang_config --cpu=k8 # Use the default Bazel C++ toolchain to build the tools used during the # build. build:clang_config --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
עבור רשומה build:{config_name} --flag=value
, סימון שורת הפקודה --config={config_name}
משויך לדגל המסוים הזה. אפשר לעיין במסמכי התיעוד של הסימונים שהיו בשימוש:
crosstool_top
,
cpu
ו-
host_crosstool_top
.
כשמגדירים את target
עם bazel build --config=clang_config //main:hello-world
, Bazel משתמשת ב-chail Tool שלך בהתאמה אישית מ-
cc_toolchain_Suite
//toolchain:clang_suite
. בסוויטה עשויים להיות רשומים
כלים שונים עבור מעבדים שונים, ולכן היא שונה מהדגל --cpu=k8
.
מכיוון ש-Bazel משתמשת בכלים פנימיים רבים הכתובים ב-C++ במהלך ה-build, כגון תהליך-wrapper, כלי ברירת המחדל הקיים מראש של C++ מצוין עבור הפלטפורמה המארחת, כך שכלים אלו בנויים באמצעות 'כלי כלים' זה במקום זה שנוצר במדריך זה.
הגדרת מחזיק הכלים C++
כדי להגדיר את ארגז הכלים של C++ , בונים שוב ושוב את האפליקציה ומבטלים כל שגיאה בנפרד, כמתואר בהמשך.
הרץ את ה-build עם הפקודה הבאה:
bazel build --config=clang_config //main:hello-world
מכיוון שציינת את
--crosstool_top=//toolchain:clang_suite
בקובץ.bazelrc
, Bazel מציג את השגיאה הבאה:No such package `toolchain`: BUILD file not found on package path.
בספרייה של סביבת העבודה, יש ליצור את הספרייה של
toolchain
עבור החבילה וקובץBUILD
ריק בתוך הספרייה שלtoolchain
.הרץ שוב את ה-build. מכיוון שהחבילה
toolchain
עדיין לא מגדירה את היעדclang_suite
, Bazel מציג את השגיאה הבאה:No such target '//toolchain:clang_suite': target 'clang_suite' not declared in package 'toolchain' defined by .../toolchain/BUILD
בקובץ ה-
toolchain/BUILD
, יש להגדיר קבוצת קבצים ריקה:package(default_visibility = ["//visibility:public"]) filegroup(name = "clang_suite")
הרץ שוב את ה-build. Bazel מציג את השגיאה הבאה:
'//toolchain:clang_suite' does not have mandatory providers: 'ToolchainInfo'
בזל גילתה שהסימון של
--crosstool_top
מפנה לכלל שלא מספק את הספק הנדרשToolchainInfo
. במקרה כזה עליך להפנות את--crosstool_top
לכלל שמספקToolchainInfo
– זהו הכללcc_toolchain_suite
. בקובץtoolchain/BUILD
, מחליפים את קבוצת הקבצים הריקה בפריטים הבאים:cc_toolchain_suite( name = "clang_suite", toolchains = { "k8": ":k8_toolchain", }, )
המאפיין
toolchains
ממפה באופן אוטומטי את הערכים--cpu
(ובנוסף--compiler
כאשר הם מצוינים) ל-cc_toolchain
. עדיין לא הגדרת יעדים שלcc_toolchain
ובזל יתלונן על כך בקרוב.הרץ שוב את ה-build. Bazel מציג את השגיאה הבאה:
Rule '//toolchain:k8_toolchain' does not exist
עכשיו צריך להגדיר
cc_toolchain
יעדים לכל ערך במאפייןcc_toolchain_suite.toolchains
. יש להוסיף את הערכים הבאים לקובץtoolchain/BUILD
:filegroup(name = "empty") cc_toolchain( name = "k8_toolchain", toolchain_identifier = "k8-toolchain", toolchain_config = ":k8_toolchain_config", all_files = ":empty", compiler_files = ":empty", dwp_files = ":empty", linker_files = ":empty", objcopy_files = ":empty", strip_files = ":empty", supports_param_files = 0, )
הרץ שוב את ה-build. Bazel מציג את השגיאה הבאה:
Rule '//toolchain:k8_toolchain_config' does not exist
בשלב הבא, יש להוסיף יעד ":k8_toolchain_config" לקובץ
toolchain/BUILD
:filegroup(name = "k8_toolchain_config")
הרץ שוב את ה-build. Bazel מציג את השגיאה הבאה:
'//toolchain:k8_toolchain_config' does not have mandatory providers: 'CcToolchainConfigInfo'
CcToolchainConfigInfo
הוא ספק שבו אתם משתמשים כדי להגדיר את מחזיקי הכלים מסוג C++. כדי לתקן את השגיאה הזו, יש ליצור כלל של Starlark שמספקCcToolchainConfigInfo
ל-Bazel על ידי יצירת קובץtoolchain/cc_toolchain_config.bzl
עם התוכן הבא:def _impl(ctx): return cc_common.create_cc_toolchain_config_info( ctx = ctx, toolchain_identifier = "k8-toolchain", host_system_name = "local", target_system_name = "local", target_cpu = "k8", target_libc = "unknown", compiler = "clang", abi_version = "unknown", abi_libc_version = "unknown", ) cc_toolchain_config = rule( implementation = _impl, attrs = {}, provides = [CcToolchainConfigInfo], )
cc_common.create_cc_toolchain_config_info()
הוא הספק הנדרשCcToolchainConfigInfo
. כדי להשתמש בכללcc_toolchain_config
, יש להוסיף הצהרת עומס אלtoolchains/BUILD
:load(":cc_toolchain_config.bzl", "cc_toolchain_config")
ומחליפים את קבוצת הקבצים "k8_toolchain_config" בהצהרה של
cc_toolchain_config
:cc_toolchain_config(name = "k8_toolchain_config")
הרץ שוב את ה-build. Bazel מציג את השגיאה הבאה:
.../BUILD:1:1: C++ compilation of rule '//:hello-world' failed (Exit 1) src/main/tools/linux-sandbox-pid1.cc:421: "execvp(toolchain/DUMMY_GCC_TOOL, 0x11f20e0)": No such file or directory Target //:hello-world failed to build`
בשלב זה יש לבזל מספיק מידע כדי לנסות לבנות את הקוד, אבל היא עדיין לא יודעת באילו כלים להשתמש כדי להשלים את פעולות ה-build הנדרשות. עליך לשנות את יישום הכלל של Starlark כדי להורות ל-Bazel באילו כלים להשתמש. לשם כך, צריך להשתמש בבנאי Tool_path() מ-
@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl
:# toolchain/cc_toolchain_config.bzl: # NEW load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "tool_path") def _impl(ctx): tool_paths = [ # NEW tool_path( name = "gcc", path = "/usr/bin/clang", ), tool_path( name = "ld", path = "/usr/bin/ld", ), tool_path( name = "ar", path = "/usr/bin/ar", ), tool_path( name = "cpp", path = "/bin/false", ), tool_path( name = "gcov", path = "/bin/false", ), tool_path( name = "nm", path = "/bin/false", ), tool_path( name = "objdump", path = "/bin/false", ), tool_path( name = "strip", path = "/bin/false", ), ] return cc_common.create_cc_toolchain_config_info( ctx = ctx, toolchain_identifier = "local", host_system_name = "local", target_system_name = "local", target_cpu = "k8", target_libc = "unknown", compiler = "clang", abi_version = "unknown", abi_libc_version = "unknown", tool_paths = tool_paths, # NEW )
חשוב לוודא שנתיבי הנסיעה
/usr/bin/clang
ו-/usr/bin/ld
הם הנתיבים הנכונים במערכת שלך.הרץ שוב את ה-build. Bazel מציג את השגיאה הבאה:
..../BUILD:3:1: undeclared inclusion(s) in rule '//main:hello-world': this rule is missing dependency declarations for the following files included by 'main/hello-world.cc': '/usr/include/c++/9/ctime' '/usr/include/x86_64-linux-gnu/c++/9/bits/c++config.h' '/usr/include/x86_64-linux-gnu/c++/9/bits/os_defines.h' ....
Bazel צריכה לדעת היכן לחפש כותרות נכללות. יש כמה דרכים לפתור את הבעיה, למשל שימוש במאפיין
includes
שלcc_binary
, אבל כאן פותרים את הבעיה ברמת ה-keychain עםcxx_builtin_include_directories
הפרמטרcc_common.create_cc_toolchain_config_info
. יש לשים לב שאם אתה משתמש בגרסה אחרת שלclang
, נתיב ההכללה יהיה שונה. ייתכן שהנתיבים האלו יהיו שונים, בהתאם להתפלגות.יש לשנות את ערך ההחזרה ב-
toolchain/cc_toolchain_config.bzl
כך שייראה כך:return cc_common.create_cc_toolchain_config_info( ctx = ctx, cxx_builtin_include_directories = [ # NEW "/usr/lib/llvm-9/lib/clang/9.0.1/include", "/usr/include", ], toolchain_identifier = "local", host_system_name = "local", target_system_name = "local", target_cpu = "k8", target_libc = "unknown", compiler = "clang", abi_version = "unknown", abi_libc_version = "unknown", tool_paths = tool_paths, )
מריצים שוב את פקודת ה-build. תוצג לכם שגיאה כמו:
/usr/bin/ld: bazel-out/k8-fastbuild/bin/main/_objs/hello-world/hello-world.o: in function `print_localtime()': hello-world.cc:(.text+0x68): undefined reference to `std::cout'
הסיבה לכך היא שבקישור חסר הספרייה C++ הרגילה, והוא אינו יכול למצוא את הסמלים שלו. אפשר לפתור את הבעיה בדרכים רבות, למשל באמצעות המאפיין
linkopts
שלcc_binary
. כדי לפתור את הבעיה, חשוב לוודא שכל יעד שמשתמש ב-chachain לא חייב לציין את הסימון הזה.מעתיקים את הקוד הבא אל
cc_toolchain_config.bzl
:# NEW load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") # NEW load( "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "feature", "flag_group", "flag_set", "tool_path", ) all_link_actions = [ # NEW ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, ] def _impl(ctx): tool_paths = [ tool_path( name = "gcc", path = "/usr/bin/clang", ), tool_path( name = "ld", path = "/usr/bin/ld", ), tool_path( name = "ar", path = "/bin/false", ), tool_path( name = "cpp", path = "/bin/false", ), tool_path( name = "gcov", path = "/bin/false", ), tool_path( name = "nm", path = "/bin/false", ), tool_path( name = "objdump", path = "/bin/false", ), tool_path( name = "strip", path = "/bin/false", ), ] features = [ # NEW feature( name = "default_linker_flags", enabled = True, flag_sets = [ flag_set( actions = all_link_actions, flag_groups = ([ flag_group( flags = [ "-lstdc++", ], ), ]), ), ], ), ] return cc_common.create_cc_toolchain_config_info( ctx = ctx, features = features, # NEW cxx_builtin_include_directories = [ "/usr/lib/llvm-9/lib/clang/9.0.1/include", "/usr/include", ], toolchain_identifier = "local", host_system_name = "local", target_system_name = "local", target_cpu = "k8", target_libc = "unknown", compiler = "clang", abi_version = "unknown", abi_libc_version = "unknown", tool_paths = tool_paths, ) cc_toolchain_config = rule( implementation = _impl, attrs = {}, provides = [CcToolchainConfigInfo], )
אם מפעילים את
bazel build --config=clang_config //main:hello-world
, הוא אמור להגיע לבנייה סופית.
בדיקת העבודות שלך
בסרטון הדרכה זה למדתם כיצד להגדיר כלי עבודה בסיסיים מסוג ++C, אך כלי כלים חזקים יותר מדוגמה פשוטה זו.
המסקנות העיקריות הן:
- עליך לציין בשורת הפקודה --crosstool_top
סימון שאמור להפנות
לcc_toolchain_suite
- ניתן ליצור קיצור דרך לתצורה מסוימת שימוש בקובץ .bazelrc
- cc_toolchain_Suite עשוי לכלול cc_toolchains
מעבדים ומהדרים שונים. אפשר להשתמש בסימונים של שורת פקודה כמו --cpu
כדי להבדיל בין התכונות.
- עליכם ליידע את מחזיק הכלים כדי לדעת היכן נמצאים הכלים. במדריך הזה יש גרסה פשוטה, שבה אפשר לגשת לכלים מהמערכת. אם
חשוב לך יותר גישה עצמאית, אפשר לקרוא כאן על סביבות עבודה. ייתכן שהכלים שלך יגיעו מסביבת עבודה אחרת, ויהיה עליך להפוך את הקבצים לזמינים
ב-cc_toolchain
עם יעדי יעד במאפיינים, כגון
compiler_files
. יש לשנות גם את ה-tool_paths
.
- ניתן ליצור תכונות כדי להתאים אישית את הסימונים שיש להעביר
לפעולות שונות, בין אם מדובר בקישור או בכל סוג אחר של פעולה.
קריאה נוספת
לקבלת פרטים נוספים, ראה הגדרת כלי C++