cquery
היא וריאציה של query
שמטפלת כראוי
select()
בבניית אפשרויות' השפעות על ה-build
כדי לעשות זאת, אפשר להריץ את התוצאות על-ידי ניתוח ב-Bazel' שמשלב את ההשפעות האלה. לעומת זאת, query
פועל מעל התוצאות של
שלב הטעינה של Bazel לפני הערכת האפשרויות.
למשל:
$ cat > tree/BUILD <<EOF sh_library( name = "ash", deps = select({ ":excelsior": [":manna-ash"], ":americana": [":white-ash"], "//conditions:default": [":common-ash"], }), ) sh_library(name = "manna-ash") sh_library(name = "white-ash") sh_library(name = "common-ash") config_setting( name = "excelsior", values = {"define": "species=excelsior"}, ) config_setting( name = "americana", values = {"define": "species=americana"}, ) EOF
# Traditional query: query doesn't know which select() branch you will choose, # so it conservatively lists all of possible choices, including all used config_settings. $ bazel query "deps(//tree:ash)" --noimplicit_deps //tree:americana //tree:ash //tree:common-ash //tree:excelsior //tree:manna-ash //tree:white-ash # cquery: cquery lets you set build options at the command line and chooses # the exact dependencies that implies (and also the config_setting targets). $ bazel cquery "deps(//tree:ash)" --define species=excelsior --noimplicit_deps //tree:ash (9f87702) //tree:manna-ash (9f87702) //tree:americana (9f87702) //tree:excelsior (9f87702)
כל תוצאה כוללת מזהה ייחודי (9f87702)
של התצורה שהיעד מיועד לה.
מכיוון ש-cquery
פועל מעל תרשים היעד שהוגדר. אין לו תובנה
בנוגע לחפצים כמו פעולות build או גישה לכללים [test_suite](/reference/be/general#test_suite)
מכיוון שהם לא יעדים מוגדרים. לאירוע הקודם, יש לעיין ב-[aquery](/docs/aquery)
.
תחביר בסיסי
קריאה פשוטה אל cquery
נראית כך:
bazel cquery "function(//target)"
ביטוי השאילתה "function(//target)"
מורכב מהביטויים הבאים:
- הפונקציה
function(...)
היא הפונקציה שרוצים להריץ ביעד.cquery
יש תמיכה ברוב הפונקציות שלquery
, וגם כמה פונקציות חדשות. //target
הוא הביטוי שמוזן לפונקציה. בדוגמה הזו, הביטוי הוא יעד פשוט. אבל שפת השאילתה גם מאפשרת קינון של פונקציות. דוגמאות מפורטות במדריך לשאילתה.
cquery
דורש יעד לפעול דרך השלבים של טעינה וניתוח. אלא אם צוין אחרת, cquery
מנתח את היעדים המפורטים
בביטוי השאילתה. ראו --universe_scope
למידע על שאילתות התלויות ביעדי build ברמה העליונה.
הגדרות אישיות
הקו:
//tree:ash (9f87702)
פירוש הדבר ש//tree:ash
נבנה בתצורה עם המזהה 9f87702
. ברוב
היעדים, מדובר בגיבוב (hash) אטום של ערכי אפשרות ה-build שמגדירים את ההגדרה.
כדי לראות את התוכן המלא של התצורה, יש להריץ:
$ bazel config 9f87702
בהגדרת המארח נעשה שימוש במזהה המיוחד (HOST)
. קובצי מקור שלא נוצרו, כמו אלו
שנמצאים לעיתים קרובות ב-srcs
, משתמשים במזהה המיוחד (null)
(כי אין
צורך להגדיר אותם).
9f87702
הוא קידומת של המזהה המלא. הסיבה לכך היא שמזהים מלאים הם גיבובים מסוג SHA-256, שהם ארוכים וקשה לעקוב אחריהם. cquery
מבין כל קידומת
חוקית של מזהה מלא, בדומה ל
Git גיבובים קצרים (hash).
כדי להציג את כל המזהים, יש להריץ את $ bazel config
.
הערכה של דפוסי יעד
ל-//foo
יש משמעות שונה מבחינת cquery
מאשר query
. הסיבה לכך היא
שב-cquery
מתבצעת הערכה של יעדים שהוגדרו ותרשים היצירה עשוי לכלול מספר
גרסאות מוגדרות של //foo
.
עבור cquery
, דפוס יעד בביטוי השאילתה מוערך
לכל יעד מוגדר עם תווית שתואמת לדפוס הזה. הפלט הוא עיקרי, אך cquery
אינו מבטיח התחייבות מעבר לחוזה הזמנת השאילתות המרכזיות.
כך מתקבלות תוצאות עדינות יותר עבור ביטויים של שאילתות מאשר עם query
.
לדוגמה, התוצאות הבאות יכולות להניב מספר תוצאות:
# Analyzes //foo in the target configuration, but also analyzes # //genrule_with_foo_as_tool which depends on a host-configured # //foo. So there are two configured target instances of //foo in # the build graph. $ bazel cquery //foo --universe_scope=//foo,//genrule_with_foo_as_tool //foo (9f87702) //foo (HOST)
אם רוצים להצהיר במדויק על המכונה שעליה רוצים להריץ שאילתה, משתמשים
בפונקציה config
.
אפשר למצוא מידע נוסף על תבניות יעד בתיעוד של
דפוסי יעד של query
.
פונקציות
מתוך מערך הפונקציות
הנתמך על ידי query
, cquery
תומך בכולם מלבד visible
,
siblings
, buildfiles
ו-tests
.
הוספנו גם את הפונקציות החדשות הבאות ב-cquery
:
תצורה
expr ::= config(expr, word)
האופרטור של config
מנסה למצוא את היעד שהוגדר עבור התווית שצוינה בארגומנט הראשון ואת ההגדרה שצוינה בארגומנט השני.
הערכים החוקיים לארגומנט השני הם target
, host
, null
או
גיבוב תצורה מותאמת אישית. ניתן לאחזר גיבוב (hash) מ-$
bazel config
או מפלט קודם של cquery
&33.
למשל:
$ bazel cquery "config(//bar, host)" --universe_scope=//foo
$ bazel cquery "deps(//foo)" //bar (HOST) //baz (3732cc8) $ bazel cquery "config(//baz, 3732cc8)"
אם לא כל התוצאות של הארגומנט הראשון נמצאות בתצורה שצוינה, יוחזרו רק התוצאות שנמצאות. אם לא נמצאו תוצאות בהגדרה שצוינה, השאילתה תיכשל.
אפשרויות
אפשרויות build
cquery
פועל מעל build רגיל של Bazel, וכך יורש את קבוצת
האפשרויות הזמינות במהלך build.
שימוש באפשרויות של שאילתה
--universe_scope
(רשימה מופרדת בפסיקים)
לעיתים קרובות, התלות של היעדים שהוגדרו עוברת מעברים, שבגללם התצורה שונה מתלויה. סימון זה מאפשר להריץ שאילתות על יעד כאילו הוא נוצר כתלות או תלות תלות ביעד אחר. למשל:
# x/BUILD genrule( name = "my_gen", srcs = ["x.in"], outs = ["x.cc"], cmd = "$(locations :tool) $< >$@", tools = [":tool"], ) cc_library( name = "tool", )
כללים מגדירים את הכלים שלהם בתצורת המארח כך שהשאילתות הבאות יפיקו פלט:
שאילתה | היעד נוצר | פלט |
---|---|---|
bazel cquery "//x:tools" | //x:tool | //x:tool(targetconfig) |
bazel cquery "//x:tools" --universe_scope="//x:my_gen" | //x:my_gen | //x:tool(hostconfig) |
אם הדגל הזה הוגדר, התוכן שלו נוצר. אם היא אינה מוגדרת, כל היעדים המוזכרים בביטוי השאילתה נוצרים במקום זאת. הסגירה העקיפה של היעדים
המובְנים משמשת כיקום של השאילתה. בכל מקרה, יש לבנות את היעדים ברמה העליונה (כלומר, תואמים לאפשרויות ברמה העליונה). cquery
מחזיר תוצאות בסגירת
היעדים המטורגטים האלה.
גם אם אפשר ליצור את כל היעדים בביטוי שאילתה ברמה העליונה, לא כדאי לעשות זאת. לדוגמה, הגדרה מפורשת של
--universe_scope
יכולה למנוע בניית יעדים מספר רב של פעמים
בהגדרות שאינן חשובות לך. זה יכול גם לעזור לציין איזו גרסת הגדרה של
יעד שאתם מחפשים (כי בשלב זה לא ניתן לציין את זה בצורה אחרת). עליכם להגדיר את הסימון הזה
אם ביטוי השאילתה מורכב יותר מ-deps(//foo)
.
--implicit_deps
(ערך בוליאני, ברירת מחדל=True)
הגדרת הסימון הזה כ-false מסננת את כל התוצאות שאינן מוגדרות במפורש בקובץ BUILD ומוגדרות במקום אחר ב-Bazel. זה כולל סינון של שרשרת כלים.
--tool_deps
(ערך בוליאני, ברירת מחדל=True)
הגדרת הסימון הזה כ-false מסננת את כל היעדים המוגדרים שעבורם
הנתיב מהיעד שבוצעה אליו שאילתה חוצה מעבר בין הגדרת היעד
להגדרות שאינן יעד.
אם היעד המבוקש מופיע בתצורת היעד, הגדרת --notool_deps
תחזיר רק יעדים שנכללים גם בהגדרת היעד. אם היעד שנשאלה
נמצא בתצורה שאינה יעד, ההגדרה --notool_deps
תחזיר רק יעדים גם בתצורות שאינן לפי היעד. בדרך כלל ההגדרה הזו לא משפיעה על סינון
של ערכות כלים שטופלו.
--include_aspects
(ערך בוליאני, ברירת מחדל=True)
היבטים יכולים להוסיף
תלויות נוספות למודל. כברירת מחדל, cquery
לא עוקב אחר היבטים כי הוא מגדיל את התרשים שניתן להריץ שאילתות, ולכן נעשה שימוש ביותר זיכרון. אבל אם תעקבו אחריהם, תקבלו תוצאות מדויקות יותר.
אם אתם לא חוששים מההשפעה של שאילתות גדולות על הזיכרון, הפעילו את התכונה הזו כברירת מחדל בבזאר.
אם תבצעו שאילתה כשהיבטים מושבתים, ייתכן שתיתקלו בבעיה שבה היעד X ייכשל בעת יצירת היעד Y, אבל cquery somepath(Y, X)
ו-cquery deps(Y) | grep 'X'
לא יחזירו תוצאות כי התלות תלויה בהיבט כלשהו.
פלט פורמטים
כברירת מחדל, פלטי שאילתות הופכים לרשימה של צמדי תוויות וסדר תלויים. קיימות אפשרויות נוספות לחשיפת התוצאות.
מעברים
--transitions=lite --transitions=full
מעברים של תצורה משמשים ליצירת יעדים מתחת ליעדים ברמה העליונה בהגדרות שונות מאלה של היעדים ברמה העליונה.
לדוגמה, יעד יכול לאלץ מעבר לתצורת המארח בכל
התלות במאפיינים של tools
. האפשרויות האלה נקראות מעברים בין מאפיינים. כללים יכולים גם לקבוע מעברים בתצורות שלהם, הידועים גם כמעברים של כללי כלל. פורמט הפלט הזה מפיק מידע על המעברים האלה, למשל מה סוגם ומה ההשפעה שלהם על אפשרויות ה-build.
פורמט הפלט הזה מופעל על ידי הדגל --transitions
, שמוגדר כברירת מחדל
ל-NONE
. ניתן להגדיר אותה למצב FULL
או למצב LITE
. מצב FULL
פלט
מידע על מעברים בין מחלקות של כללים ומעברים בין מאפיינים, כולל
פירוט של האפשרויות לפני ואחרי המעבר. מצב LITE
מציג את אותו מידע ללא האפשרויות השונות.
פלט ההודעה של הפרוטוקול
--output=proto
אפשרות זו גורמת להדפסת היעדים המתקבלים בטופס אגירת פרוטוקול בינארי. אפשר למצוא את ההגדרה של מאגר הנתונים הזמני בפרוטוקול src/main/protobuf/analysis.proto.
CqueryResult
היא ההודעה ברמה העליונה שמכילה את תוצאות השאילתה. יש בו רשימה של ConfiguredTarget
הודעות ורשימה של Configuration
הודעות. לכל ConfiguredTarget
יש configuration_id
שהערך שלו שווה לערך של השדה id
מההודעה Configuration
המתאימה.
--[no]proto:include_Configurations
כברירת מחדל, תוצאות השאילתה מחזירות פרטי תצורה כחלק מכל יעד שהוגדר. אם ברצונך להשמיט את המידע הזה ולקבל פלט אב הפורמט בדיוק כמו פלט השאילתה
אפשר לעיין בתיעוד של פלט הפרוטו של השאילתה כדי לראות אפשרויות נוספות הקשורות לפרוטוקול.
פלט התרשים
--output=graph
בחירה באפשרות הזאת תייצר פלט כקובץ .dot תואם ל-Graphviz. לפרטים, יש לעיין בquery
'sתיעוד של פלט. cquery
תומכת גם ב---graph:node_limit
וב-
--graph:factored
.
פלט קבצים
--output=files
באפשרות זו מודפסת רשימה של קובצי פלט שהופקו על ידי כל יעד, שתואם
לשאילתה שדומה לרשימה המודפסת בסוף הפעלת bazel build
. הפלט מכיל רק את הקבצים שפורסמו
בקבוצות הפלט המבוקשות, על פי הסימון של
--output_groups
לעולם לא מכיל קובצי מקור.
הגדרת פורמט הפלט באמצעות Starlark
--output=starlark
פורמט הפלט הזה מפעיל פונקציה ב-Starlark
לכל יעד מוגדר בתוצאת השאילתה, ומדפיס את הערך
שמוחזר על ידי השיחה. הדגל --starlark:file
מציין את המיקום של קובץ Starlark שמגדיר פונקציה בשם format
עם פרמטר יחיד,
target
. הפונקציה הזו נקראת עבור כל יעד בתוצאת השאילתה. לחלופין, אפשר לציין רק גוף
של פונקציה שהוכרז כ-def format(target): return expr
באמצעות
הסימון --starlark:expr
.
'cquery' Starlark ניב
סביבת ה-Querylark של השאילתה שונה מקובץ BUILD או bzl. הוא כולל את כל הפונקציות
קבועות והפונקציות המובנות, וגם כמה פונקציות ספציפיות לשאילתה שמפורטות בהמשך, אבל לא את הנתונים (למשל) glob
,
native
או rule
, והוא לא תומך בהצהרות טעינה.
build_option(target)
build_options(target)
מחזירה מפה שהמפתחות שלה הם מזהי אפשרויות build (ראו
תצורות)
והערכים שלהם הם ערכי Starlark. יצירת אפשרויות שהערכים שלהן אינם חוקיים של ערכי Starlark
מושמטים מהמפה הזו.
אם היעד הוא קובץ קלט, הפונקציה build_options(target)
מחזירה 'ללא', מפני שביעדי קובצי הקלט יש הגדרה ריקה.
ספקים(יעד)
providers(target)
מחזירה מפה שהמפתחות שלה הם שמות של
ספקים
(לדוגמה, "DefaultInfo"
) והערכים שלהם הם ערכי Starlark. ספקים
שהערכים שלהם אינם ערכים משפטיים של Starlark מושמטים מהמפה הזו.
דוגמאות
אפשר להדפיס רשימה מופרדת ברווחים של שמות הבסיס של כל הקבצים שנוצרו על ידי //foo
:
bazel cquery //foo --output=starlark \ --starlark:expr="' '.join([f.basename for f in target.files.to_list()])"
אפשר להדפיס רשימה מופרדת ברווחים של כל הקבצים שהופקו על ידי יעדים של כללים ב-//bar
ובחבילות המשנה שלו:
bazel cquery 'kind(rule, //bar/...)' --output=starlark \ --starlark:expr="' '.join([f.path for f in target.files.to_list()])"
יש להדפיס רשימה של שאר הפעולות של //foo
.
bazel cquery //foo --output=starlark \ --starlark:expr="[a.mnemonic for a in target.actions]"
אפשר להדפיס רשימה של פלטי הידור שרשומים על ידי cc_library
//baz
.
bazel cquery //baz --output=starlark \ --starlark:expr="[f.path for f in target.output_groups.compilation_outputs.to_list()]"
יש להדפיס את הערך של אפשרות שורת הפקודה --javacopt
בעת יצירת //foo
.
bazel cquery //foo --output=starlark \ --starlark:expr="build_options(target)['//command_line_option:javacopt']"
הדפסת התווית של כל יעד בפלט אחד בדיוק. בדוגמה הזו נעשה שימוש בפונקציות Starlark המוגדרות בקובץ.
$ cat example.cquery def has_one_output(target): return len(target.files.to_list()) == 1 def format(target): if has_one_output(target): return target.label else: return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
הדפסת התווית של כל יעד שהוא בדיוק Python 3. בדוגמה הזו נעשה שימוש בפונקציות Starlark המוגדרות בקובץ.
$ cat example.cquery def format(target): p = providers(target) py_info = p.get("PyInfo") if py_info and py_info.has_py3_only_sources: return target.label else: return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
חילוץ ערך מספק שמוגדר על ידי המשתמש.
$ cat some_package/my_rule.bzl MyRuleInfo = provider(fields={"color": "the name of a color"}) def _my_rule_impl(ctx): ... return [MyRuleInfo(color="red")] my_rule = rule( implementation = _my_rule_impl, attrs = {...}, ) $ cat example.cquery def format(target): p = providers(target) my_rule_info = p.get("//some_package:my_rule.bzl%MyRuleInfo'") if my_rule_info: return my_rule_info.color return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
שאילתה לעומת שאילתה
cquery
ו-query
משלימים זה את זה
ומצטיינים בנישות שונות. כדי להחליט מה מתאים לך:
cquery
עוקב אחרי ענפים ספציפיים ב-select()
כדי ליצור מודל מדויק של התרשים.query
לא יודע/ת איזו ענף בוחר, כך שההערכה היא לכלול את כל הסניפים.cquery
כדי לשמור על דיוק, נדרש יותר מידע מהתרשים מאשרquery
. באופן ספציפי, מערכתcquery
מעריכה יעדים מוגדרים בלבד, אבל מערכתquery
מעריכה רק יעדים. התהליך הזה לוקח יותר זמן והוא צורך יותר זיכרון.cquery
ההבנה של שפת השאילתה גורמת לאי בהירות שquery
מונעת. לדוגמה, אם יש"//foo"
בשתי תצורות, באיזו תצורה צריך להשתמש ב-cquery "deps(//foo)"
? הפונקציה[config](#config)
יכולה לעזור בכך.- ככלי חדש יותר, אין ל-
cquery
תמיכה עבור תרחישי שימוש מסוימים. כדי לקבל פרטים נוספים, אפשר לעיין בקטע בעיות מוכרות.
בעיות ידועות
לכל היעדים ש-cquery
"builds" יש בהם את אותה הגדרה.
לפני ביצוע הערכה של שאילתות, cquery
מפעיל גרסת build עד ממש לפני הנקודה שבה פעולות ה-build יבוצעו. היעדים שהם
"builds" נבחרים כברירת מחדל מכל התוויות שמופיעות בביטוי לשאילתה (ניתן לבטל זאת
עם --universe_scope
). לתצורה הזו
חייבת להיות אותה הגדרה.
בדרך כלל ההגדרה הזו משתפת את ההגדרה ברמה העליונה;"target" ,
כללים יכולים לשנות את ההגדרה האישית שלהם באמצעות
מעברי קצה נכנסים.
כאן כותבים cquery
.
פתרון עקיף: אם ניתן, כדאי להגדיר את --universe_scope
להיקף מחמיר יותר. למשל:
# This command attempts to build the transitive closures of both //foo and # //bar. //bar uses an incoming edge transition to change its --cpu flag. $ bazel cquery 'somepath(//foo, //bar)' ERROR: Error doing post analysis query: Top-level targets //foo and //bar have different configurations (top-level targets with different configurations is not supported) # This command only builds the transitive closure of //foo, under which # //bar should exist in the correct configuration. $ bazel cquery 'somepath(//foo, //bar)' --universe_scope=//foo
אין תמיכה בדומיין --output=xml
.
פלט לא חד-משמעי.
הפונקציה cquery
לא מוחקת באופן אוטומטי את תרשים ה-build מפקודות קודמות, ולכן היא נוטה לאסוף תוצאות משאילתות קודמות. לדוגמה, ב-genquery
פועל מעבר של המארח במאפיין tools
שלו, כלומר הוא מגדיר את הכלים שלו בהגדרת המארח.
בהמשך ניתן לראות את ההשפעות של המעבר.
$ cat > foo/BUILD <<<EOF genrule( name = "my_gen", srcs = ["x.in"], outs = ["x.cc"], cmd = "$(locations :tool) $< >$@", tools = [":tool"], ) cc_library( name = "tool", ) EOF $ bazel cquery "//foo:tool" tool(target_config) $ bazel cquery "deps(//foo:my_gen)" my_gen (target_config) tool (host_config) ... $ bazel cquery "//foo:tool" tool(host_config)
פתרון עקיף: ניתן לשנות את כל אפשרויות ההפעלה כדי לאלץ ניתוח מחדש של יעדים שהוגדרו.
לדוגמה, אפשר להוסיף את --test_arg=<whatever>
לפקודת ה-build.
פתרון בעיות
דפוסי יעד חוזרים (/...
)
אם תיתקלו ב:
$ bazel cquery --universe_scope=//foo:app "somepath(//foo:app, //foo/...)" ERROR: Error doing post analysis query: Evaluation failed: Unable to load package '[foo]' because package is not in scope. Check that all target patterns in query expression are within the --universe_scope of this query.
פעולה זו מציינת שהחבילה //foo
לא נכללת בהיקף למרות ש---universe_scope=//foo:app
כוללת אותה. ההגבלה הזו נובעת ממגבלות עיצוב ב-cquery
. כפתרון עקיף, ניתן לכלול את //foo/...
באופן מפורש בהיקף היקום:
$ bazel cquery --universe_scope=//foo:app,//foo/... "somepath(//foo:app, //foo/...)"
אם זה לא עובד (למשל, כי בחלק מהיעדים ב-//foo/...
אין אפשרות ליצור עם הסימונים שנבחרו), יש לבטל באופן ידני את הדפוס בחבילות הנמצאות בו, בעזרת שאילתה בעיבוד מראש:
# Replace "//foo/..." with a subshell query call (not cquery!) outputting each package, piped into # a sed call converting "<pkg>" to "//<pkg>:*", piped into a "+"-delimited line merge. # Output looks like "//foo:*+//foo/bar:*+//foo/baz". # $ bazel cquery --universe_scope=//foo:app "somepath(//foo:app, $(bazel query //foo/... --output=package | sed -e 's/^/\/\//' -e 's/$/:*/' | paste -sd "+" -))"