कॉन्फ़िगर करने लायक क्वेरी (cquery)

cquery query का एक वैरिएंट है. यह बिल्ड ग्राफ़ पर select() और बिल्ड विकल्पों के असर को सही तरीके से हैंडल करता है.

यह Bazel के analysis phase, नतीजों पर काम करके ऐसा करता है. इसमें इन इफ़ेक्ट को इंटिग्रेट किया जाता है. इसके उलट, 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, कॉन्फ़िगर किए गए टारगेट ग्राफ़ पर काम करता है. इसलिए, इसे बिल्ड ऐक्शन जैसे आर्टफ़ैक्ट के बारे में जानकारी नहीं होती. साथ ही, इसे [test_suite](/versions/6.2.0/reference/be/general#test_suite) नियमों का ऐक्सेस नहीं होता, क्योंकि ये कॉन्फ़िगर किए गए टारगेट नहीं होते. पहले वाले के लिए, [aquery](/versions/6.2.0/docs/aquery) देखें.

बेसिक सिंटैक्स

cquery को कॉल करने का एक आसान तरीका यहां दिया गया है:

bazel cquery "function(//target)"

क्वेरी एक्सप्रेशन "function(//target)" में ये चीज़ें शामिल होती हैं:

  • function(...) वह फ़ंक्शन है जिसे टारगेट पर चलाया जाता है. cquery query के ज़्यादातर फ़ंक्शन के साथ-साथ कुछ नए फ़ंक्शन भी इस्तेमाल करता है.
  • //target वह एक्सप्रेशन है जिसे फ़ंक्शन में फ़ीड किया जाता है. इस उदाहरण में, एक्सप्रेशन एक आसान टारगेट है. हालांकि, क्वेरी लैंग्वेज में फ़ंक्शन को नेस्ट भी किया जा सकता है. उदाहरण के लिए, क्वेरी के बारे में जानकारी देने वाला लेख देखें.

cquery को लोडिंग और विश्लेषण फ़ेज़ में चलाने के लिए, टारगेट की ज़रूरत होती है. जब तक अलग से न बताया जाए, cquery, क्वेरी एक्सप्रेशन में शामिल टारगेट को पार्स करता है. टॉप-लेवल के बिल्ड टारगेट की डिपेंडेंसी के बारे में क्वेरी करने के लिए, --universe_scope देखें.

कॉन्फ़िगरेशन

इस लाइन का मतलब है:

//tree:ash (9f87702)

इसका मतलब है कि //tree:ash को आईडी 9f87702 वाले कॉन्फ़िगरेशन में बनाया गया था. ज़्यादातर टारगेट के लिए, यह कॉन्फ़िगरेशन को तय करने वाले बिल्ड विकल्प की वैल्यू का अपारदर्शी हैश होता है.

कॉन्फ़िगरेशन का पूरा कॉन्टेंट देखने के लिए, यह कमांड चलाएं:

$ bazel config 9f87702

होस्ट कॉन्फ़िगरेशन, खास आईडी (HOST) का इस्तेमाल करता है. सोर्स की जनरेट न की गई फ़ाइलें, जैसे कि आम तौर पर srcs में मौजूद फ़ाइलें, खास आईडी (null) का इस्तेमाल करती हैं. ऐसा इसलिए, क्योंकि इन्हें कॉन्फ़िगर करने की ज़रूरत नहीं होती.

9f87702, पूरे आईडी का प्रीफ़िक्स है. ऐसा इसलिए, क्योंकि पूरे आईडी SHA-256 हैश होते हैं. ये लंबे होते हैं और इन्हें समझना मुश्किल होता है. cquery पूरे आईडी के किसी भी मान्य प्रीफ़िक्स को समझता है. यह Git के छोटे हैश की तरह काम करता है. पूरे आईडी देखने के लिए, $ 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's टारगेट पैटर्न दस्तावेज़ देखें.

फ़ंक्शन

फ़ंक्शन के सेट में से, जिसे query इस्तेमाल करता है, cquery allrdeps, buildfiles, rbuildfiles, siblings, tests, और visible को छोड़कर बाकी सभी फ़ंक्शन इस्तेमाल करता है.

cquery में ये नए फ़ंक्शन भी शामिल हैं:

config

expr ::= config(expr, word)

config ऑपरेटर, पहले आर्ग्युमेंट से दिखाए गए लेबल और दूसरे आर्ग्युमेंट से तय किए गए कॉन्फ़िगरेशन के लिए, कॉन्फ़िगर किया गया टारगेट ढूंढने की कोशिश करता है.

दूसरे आर्ग्युमेंट के लिए मान्य वैल्यू, target, host, null, या कस्टम कॉन्फ़िगरेशन हैश होती है. हैश, $ bazel config या पिछले cquery के आउटपुट से लिए जा सकते हैं.

उदाहरण:

$ bazel cquery "config(//bar, host)" --universe_scope=//foo
$ bazel cquery "deps(//foo)"
//bar (HOST)
//baz (3732cc8)

$ bazel cquery "config(//baz, 3732cc8)"

अगर पहले आर्ग्युमेंट के सभी नतीजे, तय किए गए कॉन्फ़िगरेशन में नहीं मिलते हैं, तो सिर्फ़ वे नतीजे दिखाए जाते हैं जो मिल सकते हैं. अगर तय किए गए कॉन्फ़िगरेशन में कोई नतीजा नहीं मिलता है, तो क्वेरी फ़ेल हो जाती है.

विकल्प

बिल्ड विकल्प

cquery Bazel के सामान्य बिल्ड पर काम करता है. इसलिए, यह बिल्ड के दौरान उपलब्ध विकल्पों के सेट को इनहेरिट करता है.

cquery के विकल्पों का इस्तेमाल करना

--universe_scope (कॉमा लगाकर अलग की गई लिस्ट)

अक्सर, कॉन्फ़िगर किए गए टारगेट की डिपेंडेंसी, ट्रांज़िशनसे गुज़रती हैं. इससे उनका कॉन्फ़िगरेशन, उन पर निर्भर टारगेट से अलग हो जाता है. इस फ़्लैग की मदद से, किसी टारगेट के बारे में क्वेरी की जा सकती है. ऐसा तब किया जा सकता है, जब उसे किसी दूसरे टारगेट की डिपेंडेंसी या ट्रांज़िटिव डिपेंडेंसी के तौर पर बनाया गया हो. उदाहरण के लिए:

# x/BUILD
genrule(
     name = "my_gen",
     srcs = ["x.in"],
     outs = ["x.cc"],
     cmd = "$(locations :tool) $< >$@",
     tools = [":tool"],
)
cc_library(
    name = "tool",
)

Genrules, अपने टूल को होस्ट कॉन्फ़िगरेशन में कॉन्फ़िगर करते हैं. इसलिए, इन क्वेरी से ये आउटपुट मिलेंगे:

क्वेरी बनाया गया टारगेट आउटपुट
bazel cquery "//x:tool" //x:tool //x:tool(targetconfig)
bazel cquery "//x:tool" --universe_scope="//x:my_gen" //x:my_gen //x:tool(hostconfig)

अगर यह फ़्लैग सेट किया जाता है, तो इसका कॉन्टेंट बनाया जाता है. अगर इसे सेट नहीं किया जाता है, तो क्वेरी एक्सप्रेशन में बताए गए सभी टारगेट बनाए जाते हैं. बनाए गए टारगेट के ट्रांज़िटिव क्लोज़र को, क्वेरी के यूनिवर्स के तौर पर इस्तेमाल किया जाता है. दोनों ही मामलों में, बनाए जाने वाले टारगेट को टॉप लेवल पर बनाया जाना चाहिए. इसका मतलब है कि वे टॉप-लेवल के विकल्पों के साथ काम करने वाले होने चाहिए. cquery , इन टॉप-लेवल के टारगेट के ट्रांज़िटिव क्लोज़र में नतीजे दिखाता है.

भले ही, क्वेरी एक्सप्रेशन में मौजूद सभी टारगेट को टॉप लेवल पर बनाया जा सकता हो, लेकिन ऐसा न करना फ़ायदेमंद हो सकता है. उदाहरण के लिए, --universe_scope को साफ़ तौर पर सेट करने से, उन कॉन्फ़िगरेशन में टारगेट को कई बार बनाने से रोका जा सकता है जिनकी आपको परवाह नहीं है. इससे यह भी तय किया जा सकता है कि आपको किसी टारगेट का कौनसा कॉन्फ़िगरेशन वर्शन चाहिए. ऐसा इसलिए, क्योंकि फ़िलहाल किसी दूसरे तरीके से इसे पूरी तरह से तय नहीं किया जा सकता. अगर आपका क्वेरी एक्सप्रेशन, deps(//foo) से ज़्यादा जटिल है, तो आपको यह फ़्लैग सेट करना चाहिए.

--implicit_deps (बूलियन, डिफ़ॉल्ट=True)

इस फ़्लैग को 'गलत' पर सेट करने से, उन सभी नतीजों को फ़िल्टर कर दिया जाता है जिन्हें BUILD फ़ाइल में साफ़ तौर पर सेट नहीं किया गया है. इसके बजाय, Bazel ने उन्हें कहीं और सेट किया है. इसमें, हल की गई टूलचेन को फ़िल्टर करना शामिल है.

--tool_deps (बूलियन, डिफ़ॉल्ट=True)

इस फ़्लैग को 'गलत' पर सेट करने से, उन सभी कॉन्फ़िगर किए गए टारगेट को फ़िल्टर कर दिया जाता है जिनके लिए, क्वेरी किए गए टारगेट से उन तक का पाथ, टारगेट कॉन्फ़िगरेशन और नॉन-टारगेट कॉन्फ़िगरेशनके बीच ट्रांज़िशन को पार करता है. अगर क्वेरी किया गया टारगेट, टारगेट कॉन्फ़िगरेशन में है, तो --notool_deps को सेट करने पर, सिर्फ़ वे टारगेट दिखेंगे जो टारगेट कॉन्फ़िगरेशन में भी हैं. अगर क्वेरी किया गया टारगेट, नॉन-टारगेट कॉन्फ़िगरेशन में है, तो --notool_deps को सेट करने पर, सिर्फ़ वे टारगेट दिखेंगे जो नॉन-टारगेट कॉन्फ़िगरेशन में भी हैं. आम तौर पर, इस सेटिंग से हल की गई टूलचेन को फ़िल्टर करने पर कोई असर नहीं पड़ता.

--include_aspects (बूलियन, डिफ़ॉल्ट=True)

आसपेक्ट, बिल्ड में अतिरिक्त डिपेंडेंसी जोड़ सकते हैं. डिफ़ॉल्ट रूप से, cquery, आसपेक्ट को फ़ॉलो नहीं करता, क्योंकि इससे क्वेरी किया जा सकने वाला ग्राफ़ बड़ा हो जाता है. इससे ज़्यादा मेमोरी का इस्तेमाल होता है. हालांकि, उन्हें फ़ॉलो करने से ज़्यादा सटीक नतीजे मिलते हैं.

अगर आपको बड़ी क्वेरी की वजह से मेमोरी पर पड़ने वाले असर की चिंता नहीं है, तो अपने bazelrc में इस फ़्लैग को डिफ़ॉल्ट रूप से चालू करें.

अगर आसपेक्ट को बंद करके क्वेरी की जाती है, तो आपको ऐसी समस्या आ सकती है जहां टारगेट Y बनाते समय टारगेट X फ़ेल हो जाता है. हालांकि, cquery somepath(Y, X) और cquery deps(Y) | grep 'X' कोई नतीजा नहीं दिखाते, क्योंकि डिपेंडेंसी किसी आसपेक्ट के ज़रिए होती है.

आउटपुट फ़ॉर्मैट

डिफ़ॉल्ट रूप से, cquery, लेबल और कॉन्फ़िगरेशन के पेयर की डिपेंडेंसी के क्रम वाली सूची में नतीजे दिखाता है. नतीजों को दिखाने के लिए, अन्य विकल्प भी मौजूद हैं.

ट्रांज़िशन

--transitions=lite
--transitions=full

कॉन्फ़िगरेशन ट्रांज़िशन का इस्तेमाल, टॉप लेवल के टारगेट के नीचे मौजूद टारगेट को, टॉप लेवल के टारगेट से अलग कॉन्फ़िगरेशन में बनाने के लिए किया जाता है.

उदाहरण के लिए, कोई टारगेट, अपने tools एट्रिब्यूट में मौजूद सभी डिपेंडेंसी पर, होस्ट कॉन्फ़िगरेशन में ट्रांज़िशन लागू कर सकता है. इन्हें एट्रिब्यूट ट्रांज़िशन कहा जाता है. नियम, अपने कॉन्फ़िगरेशन पर भी ट्रांज़िशन लागू कर सकते हैं. इन्हें नियम क्लास ट्रांज़िशन कहा जाता है. इस आउटपुट फ़ॉर्मैट में, इन ट्रांज़िशन के बारे में जानकारी दी जाती है. जैसे, वे किस तरह के हैं और बिल्ड विकल्पों पर उनका क्या असर पड़ता है.

यह आउटपुट फ़ॉर्मैट, --transitions फ़्लैग से ट्रिगर होता है. यह डिफ़ॉल्ट रूप से NONE पर सेट होता है. इसे FULL या LITE मोड पर सेट किया जा सकता है. FULL मोड में, नियम क्लास ट्रांज़िशन और एट्रिब्यूट ट्रांज़िशन के बारे में जानकारी दी जाती है. इसमें ट्रांज़िशन से पहले और बाद में, विकल्पों का विस्तृत अंतर शामिल होता है. LITE मोड में, विकल्पों के अंतर के बिना वही जानकारी दी जाती है.

प्रोटोकॉल मैसेज आउटपुट

--output=proto

इस विकल्प से, नतीजे के तौर पर मिलने वाले टारगेट, बाइनरी प्रोटोकॉल बफ़र फ़ॉर्म में प्रिंट होते हैं. प्रोटोकॉल बफ़र की जानकारी, src/main/protobuf/analysis.proto पर देखी जा सकती है.

CqueryResult, टॉप लेवल का मैसेज है. इसमें cquery के नतीजे शामिल होते हैं. इसमें ConfiguredTarget मैसेज की सूची और Configuration मैसेज की सूची होती है. हर ConfiguredTarget में configuration_id होता है. इसकी वैल्यू, उससे जुड़े Configuration मैसेज के id फ़ील्ड की वैल्यू के बराबर होती है.

--[no]proto:include_configurations

डिफ़ॉल्ट रूप से, cquery के नतीजों में, हर कॉन्फ़िगर किए गए टारगेट के हिस्से के तौर पर, कॉन्फ़िगरेशन की जानकारी दिखती है. अगर आपको यह जानकारी नहीं चाहिए और proto आउटपुट चाहिए, जिसे ठीक उसी तरह फ़ॉर्मैट किया गया हो जैसा कि क्वेरी का proto आउटपुट होता है, तो इस फ़्लैग को 'गलत' पर सेट करें.

proto आउटपुट से जुड़े अन्य विकल्पों के लिए, क्वेरी के proto आउटपुट से जुड़े दस्तावेज़ देखें.

ग्राफ़ आउटपुट

--output=graph

इस विकल्प से, Graphviz के साथ काम करने वाली .dot फ़ाइल के तौर पर आउटपुट जनरेट होता है. ज़्यादा जानकारी के लिए, query's ग्राफ़ आउटपुट से जुड़े दस्तावेज़ देखें. cquery भी इस्तेमाल करता है --graph:node_limit और --graph:factored.

फ़ाइलें आउटपुट

--output=files

यह विकल्प, क्वेरी से मेल खाने वाले हर टारगेट से जनरेट होने वाली आउटपुट फ़ाइलों की सूची प्रिंट करता है. यह सूची, bazel build को कॉल करने के बाद प्रिंट की गई सूची की तरह होती है. आउटपुट में सिर्फ़ वे फ़ाइलें शामिल होती हैं जिन्हें अनुरोध किए गए आउटपुट ग्रुप में दिखाया गया है. यह जानकारी, --output_groups फ़्लैग से तय होती है. इसमें सोर्स फ़ाइलें शामिल होती हैं.

Starlark का इस्तेमाल करके आउटपुट फ़ॉर्मैट तय करना

--output=starlark

इस आउटपुट फ़ॉर्मैट में, क्वेरी के नतीजे में मौजूद हर कॉन्फ़िगर किए गए टारगेट के लिए, Starlark फ़ंक्शन को कॉल किया जाता है. साथ ही, कॉल से मिली वैल्यू को प्रिंट किया जाता है. --starlark:file फ़्लैग, Starlark फ़ाइल की जगह तय करता है. इस फ़ाइल में format नाम का फ़ंक्शन तय किया जाता है. इसमें एक पैरामीटर, target होता है. क्वेरी के नतीजे में मौजूद हर टारगेट के लिए, इस फ़ंक्शन को कॉल किया जाता है. इसके अलावा, सुविधा के लिए, --starlark:expr फ़्लैग का इस्तेमाल करके, def format(target): return expr के तौर पर तय किए गए फ़ंक्शन का सिर्फ़ बॉडी तय किया जा सकता है.

'cquery' Starlark की भाषा

cquery का Starlark एनवायरमेंट, BUILD या .bzl फ़ाइल से अलग होता है. इसमें Starlark के सभी मुख्य बिल्ट-इन कॉन्स्टैंट और फ़ंक्शन शामिल होते हैं. साथ ही, cquery के लिए खास तौर पर बनाए गए कुछ फ़ंक्शन भी शामिल होते हैं. इनके बारे में नीचे बताया गया है. हालांकि, इसमें glob, native या rule शामिल नहीं होते. साथ ही, इसमें लोड स्टेटमेंट इस्तेमाल नहीं किए जा सकते.

build_options(target)

build_options(target) एक मैप दिखाता है. इसकी कुंजियां, बिल्ड विकल्प के आइडेंटिफ़ायर होती हैं. कॉन्फ़िगरेशन देखें) साथ ही, इसकी वैल्यू, Starlark की वैल्यू होती हैं. जिन बिल्ड विकल्पों की वैल्यू, Starlark की मान्य वैल्यू नहीं होती हैं उन्हें इस मैप से हटा दिया जाता है.

अगर टारगेट, इनपुट फ़ाइल है, तो build_options(target) कोई वैल्यू नहीं दिखाता, क्योंकि इनपुट फ़ाइल टारगेट का कॉन्फ़िगरेशन शून्य होता है.

providers(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()]"

//foo बनाते समय, कमांड लाइन विकल्प --javacopt की वैल्यू प्रिंट करें.

  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 और query एक-दूसरे के पूरक हैं. साथ ही, ये अलग-अलग कामों में बेहतर हैं. यह तय करने के लिए कि आपके लिए कौनसा टूल सही है, इन बातों पर ध्यान दें:

  • cquery , select() की खास ब्रांच को फ़ॉलो करता है, ताकि आपके बनाए गए ग्राफ़ का सटीक मॉडल तैयार किया जा सके. query को यह नहीं पता होता कि बिल्ड कौनसी ब्रांच चुनता है. इसलिए, यह सभी ब्रांच को शामिल करके, ज़्यादा सटीक नतीजे दिखाता है.
  • cquery' को सटीक नतीजे पाने के लिए, query के मुकाबले ज़्यादा ग्राफ़ बनाने की ज़रूरत होती है. खास तौर पर, cquery कॉन्फ़िगर किए गए टारगेट का आकलन करता है. वहीं, query सिर्फ़ टारगेट का आकलन करता है. इसमें ज़्यादा समय लगता है और ज़्यादा मेमोरी का इस्तेमाल होता है.
  • cquery की व्याख्या से, ऐसी अस्पष्टता पैदा होती है जिसे query से टाला जा सकता है. उदाहरण के लिए, अगर "//foo" दो कॉन्फ़िगरेशन में मौजूद है, तो कौनसा इस्तेमाल करना चाहिए?cquery "deps(//foo)" [config](#config) फ़ंक्शन, इसमें आपकी मदद कर सकता है.
  • cquery एक नया टूल है. इसलिए, इसमें कुछ इस्तेमाल के मामलों के लिए सहायता उपलब्ध नहीं है. ज़्यादा जानकारी के लिए, ऐसी समस्याएं जिनके बारे में जानकारी है देखें.

ऐसी समस्याएं जिनके बारे में जानकारी है

`cquery` से "बनाए गए" सभी टारगेट का कॉन्फ़िगरेशन एक जैसा होना चाहिए.cquery

क्वेरी का आकलन करने से पहले, cquery, बिल्ड को उस पॉइंट से ठीक पहले ट्रिगर करता है जहां बिल्ड ऐक्शन लागू होंगे. यह जिन टारगेट को "बनाता है" उन्हें डिफ़ॉल्ट रूप से, क्वेरी एक्सप्रेशन में दिखने वाले सभी लेबल से चुना जाता है. इसे --universe_scopeसे बदला जा सकता है. इनका कॉन्फ़िगरेशन एक जैसा होना चाहिए.

आम तौर पर, ये टॉप-लेवल के "टारगेट" कॉन्फ़िगरेशन को शेयर करते हैं. हालांकि, नियम, आने वाले एज ट्रांज़िशन के साथ अपना कॉन्फ़िगरेशन बदल सकते हैं. यहां 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 , पिछली कमांड से बिल्ड ग्राफ़ को अपने-आप नहीं मिटाता. इसलिए, इसमें पिछली क्वेरी के नतीजे दिखने की संभावना होती है. उदाहरण के लिए, 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=&lt;whatever&gt; जोड़ें.

समस्या का हल

रिकर्सिव टारगेट पैटर्न (/...)

अगर आपको यह गड़बड़ी दिखती है:

$ 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 "+" -))"