cquery adalah varian query yang menangani efek
select() dan opsi build pada grafik build
dengan benar.
Hal ini dicapai dengan menjalankan hasil fase analisis
Bazel,
yang mengintegrasikan efek ini. Sebaliknya, query berjalan di atas hasil fase pemuatan Bazel, sebelum opsi dievaluasi.
Contoh:
$ 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)
Setiap hasil menyertakan ID unik (9f87702) dari
konfigurasi yang digunakan untuk membuat target.
Karena cquery berjalan di atas grafik target yang dikonfigurasi, tidak memiliki insight
tentang artefak seperti tindakan build maupun akses ke test_suite
aturan karena bukan target yang dikonfigurasi. Untuk yang pertama, lihat aquery.
Sintaksis dasar
Panggilan cquery sederhana terlihat seperti ini:
bazel cquery "function(//target)"
Ekspresi kueri "function(//target)" terdiri dari hal berikut:
function(...)adalah fungsi yang akan dijalankan pada target.cquerymendukung sebagian besar fungsiquery's , ditambah beberapa fungsi baru.//targetadalah ekspresi yang dimasukkan ke fungsi. Dalam contoh ini, ekspresinya adalah target sederhana. Namun, bahasa kueri juga memungkinkan fungsi bertingkat. Lihat panduan Kueri untuk contohnya.
cquery memerlukan target untuk menjalankan fase pemuatan dan analisis. Kecuali jika ditentukan lain, cquery mengurai target yang tercantum dalam ekspresi kueri. Lihat --universe_scope
untuk membuat kueri dependensi target build tingkat atas.
Konfigurasi
Baris berikut:
//tree:ash (9f87702)
berarti //tree:ash dibuat dalam konfigurasi dengan ID 9f87702. Untuk sebagian besar target, ini adalah hash buram dari nilai opsi build yang menentukan konfigurasi.
Untuk melihat konten lengkap konfigurasi, jalankan:
$ bazel config 9f87702
9f87702 adalah awalan dari ID lengkap. Hal ini karena ID lengkap adalah hash SHA-256, yang panjang dan sulit diikuti. cquery memahami awalan valid
dari ID lengkap, mirip dengan
hash pendek Git.
Untuk melihat ID lengkap, jalankan $ bazel config.
Evaluasi pola target
//foo memiliki arti yang berbeda untuk cquery dan query. Hal ini karena cquery mengevaluasi target yang dikonfigurasi dan grafik build mungkin memiliki beberapa versi //foo yang dikonfigurasi.
Untuk cquery, pola target dalam ekspresi kueri dievaluasi ke setiap target yang dikonfigurasi dengan label yang cocok dengan pola tersebut. Output bersifat
deterministik, tetapi cquery tidak memberikan jaminan pengurutan di luar
kontrak pengurutan kueri inti.
Hal ini menghasilkan hasil yang lebih halus untuk ekspresi kueri daripada dengan query.
Misalnya, hal berikut dapat menghasilkan beberapa hasil:
# Analyzes //foo in the target configuration, but also analyzes # //genrule_with_foo_as_tool which depends on an exec-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 (exec)
Jika Anda ingin mendeklarasikan instance yang akan dikueri secara tepat, gunakan
the config fungsi.
Lihat dokumentasi pola target query untuk mengetahui informasi selengkapnya tentang pola target.
Fungsi
Dari kumpulan fungsi
yang didukung oleh query, cquery mendukung semua fungsi kecuali
allrdeps,
buildfiles,
rbuildfiles,
siblings, tests, dan
visible.
cquery juga memperkenalkan fungsi baru berikut:
config
expr ::= config(expr, word)
Operator config mencoba menemukan target yang dikonfigurasi untuk label yang ditunjukkan oleh argumen pertama dan konfigurasi yang ditentukan oleh argumen kedua.
Nilai yang valid untuk argumen kedua adalah null atau a
hash konfigurasi kustom. Hash dapat diambil dari $
bazel config atau output cquery sebelumnya.
Contoh:
$ bazel cquery "config(//bar, 3732cc8)" --universe_scope=//foo
$ bazel cquery "deps(//foo)" //bar (exec) //baz (exec) $ bazel cquery "config(//baz, 3732cc8)"
Jika tidak semua hasil argumen pertama dapat ditemukan dalam konfigurasi yang ditentukan, hanya hasil yang dapat ditemukan yang akan ditampilkan. Jika tidak ada hasil yang dapat ditemukan dalam konfigurasi yang ditentukan, kueri akan gagal.
Opsi
Opsi build
cquery berjalan di atas build Bazel reguler dan dengan demikian mewarisi kumpulan
opsi yang tersedia selama build.
Menggunakan opsi cquery
--universe_scope (daftar yang dipisahkan koma)
Sering kali, dependensi target yang dikonfigurasi mengalami transisi, yang menyebabkan konfigurasinya berbeda dari dependensinya. Flag ini memungkinkan Anda membuat kueri target seolah-olah dibuat sebagai dependensi atau dependensi transitif dari target lain. Contoh:
# x/BUILD
genrule(
name = "my_gen",
srcs = ["x.in"],
outs = ["x.cc"],
cmd = "$(locations :tool) $< >$@",
tools = [":tool"],
)
cc_binary(
name = "tool",
srcs = ["tool.cpp"],
)
Genrules mengonfigurasi alatnya dalam konfigurasi exec sehingga kueri berikut akan menghasilkan output berikut:
| Kueri | Target yang Dibuat | Output |
|---|---|---|
| bazel cquery "//x:tool" | //x:tool | //x:tool(targetconfig) |
| bazel cquery "//x:tool" --universe_scope="//x:my_gen" | //x:my_gen | //x:tool(execconfig) |
Jika flag ini ditetapkan, kontennya akan dibuat. Jika tidak ditetapkan, semua target
yang disebutkan dalam ekspresi kueri akan dibuat. Penutupan transitif target yang dibuat digunakan sebagai universe kueri. Bagaimanapun, target yang akan dibuat harus dapat dibuat di tingkat atas (yaitu, kompatibel dengan opsi tingkat atas). cquery menampilkan hasil dalam penutupan transitif target tingkat atas ini.
Meskipun semua target dalam ekspresi kueri dapat dibuat di tingkat atas, sebaiknya jangan lakukan hal tersebut. Misalnya, menetapkan --universe_scope secara eksplisit dapat mencegah pembuatan target beberapa kali dalam konfigurasi yang tidak Anda perhatikan. Hal ini juga dapat membantu menentukan versi konfigurasi target yang Anda cari (karena saat ini tidak mungkin menentukan hal ini sepenuhnya dengan cara lain). Anda harus menetapkan flag ini jika ekspresi kueri Anda lebih kompleks daripada deps(//foo).
--implicit_deps (boolean, default=True)
Menetapkan flag ini ke false akan memfilter semua hasil yang tidak ditetapkan secara eksplisit dalam file BUILD dan ditetapkan di tempat lain oleh Bazel. Hal ini mencakup pemfilteran toolchain yang di-resolve.
--tool_deps (boolean, default=True)
Menetapkan flag ini ke false akan memfilter semua target yang dikonfigurasi yang
jalurnya dari target yang dikueri ke target tersebut melintasi transisi antara konfigurasi target
dan
konfigurasi non-target.
Jika target yang dikueri berada dalam konfigurasi target, menetapkan --notool_deps hanya akan menampilkan target yang juga berada dalam konfigurasi target. Jika target yang dikueri berada dalam konfigurasi non-target, menetapkan --notool_deps hanya akan menampilkan target yang juga berada dalam konfigurasi non-target. Setelan ini umumnya tidak memengaruhi pemfilteran toolchain yang di-resolve.
--include_aspects (boolean, default=True)
Menyertakan dependensi yang ditambahkan oleh aspek.
Jika flag ini dinonaktifkan, cquery somepath(X, Y) dan
cquery deps(X) | grep 'Y' akan menghapus Y jika X hanya bergantung pada Y melalui aspek.
Format output
Secara default, cquery menampilkan hasil dalam daftar pasangan label dan konfigurasi yang diurutkan berdasarkan dependensi. Ada opsi lain untuk mengekspos hasilnya juga.
Transisi
--transitions=lite --transitions=full
Misalnya, target dapat menerapkan transisi ke konfigurasi exec pada semua dependensi dalam atribut tools. Hal ini dikenal sebagai transisi atribut. Aturan juga dapat menerapkan transisi pada konfigurasinya sendiri, yang dikenal sebagai transisi class aturan. Format output ini menampilkan informasi tentang transisi ini seperti jenisnya dan efeknya pada opsi build.
Format output ini dipicu oleh flag --transitions yang secara default ditetapkan ke NONE. Format ini dapat ditetapkan ke mode FULL atau LITE. Mode FULL menampilkan informasi tentang transisi class aturan dan transisi atribut, termasuk perbedaan opsi yang mendetail sebelum dan setelah transisi. Mode LITE menampilkan informasi yang sama tanpa perbedaan opsi.
Output pesan protokol
--output=proto
Opsi ini menyebabkan target yang dihasilkan dicetak dalam bentuk buffer protokol biner. Definisi buffer protokol dapat ditemukan di src/main/protobuf/analysis_v2.proto.
CqueryResult adalah pesan tingkat atas yang berisi hasil cquery. Pesan ini memiliki daftar pesan ConfiguredTarget dan daftar pesan Configuration. Setiap ConfiguredTarget memiliki configuration_id yang nilainya sama
dengan nilai kolom id dari pesan Configuration yang sesuai.
--[no]proto:include_configurations
Secara default, hasil cquery menampilkan informasi konfigurasi sebagai bagian dari setiap target yang dikonfigurasi. Jika Anda ingin menghapus informasi ini dan mendapatkan output proto yang diformat persis seperti output proto kueri, tetapkan flag ini ke false.
Lihat dokumentasi output proto kueri untuk mengetahui opsi terkait output proto lainnya.
Output grafik
--output=graph
Opsi ini menghasilkan output sebagai file .dot yang kompatibel dengan Graphviz. Lihat query's
dokumentasi output grafik untuk mengetahui detailnya. cquery
juga mendukung --graph:node_limit dan
--graph:factored.
Output file
--output=files
Opsi ini mencetak daftar file output yang dihasilkan oleh setiap target yang cocok dengan kueri, mirip dengan daftar yang dicetak di akhir pemanggilan bazel build. Output hanya berisi file yang diiklankan dalam grup output yang diminta seperti yang ditentukan oleh
--output_groups flag.
Output ini menyertakan file sumber.
Semua jalur yang dikeluarkan oleh format output ini bersifat relatif terhadap
execroot, yang dapat diperoleh
melalui bazel info execution_root. Jika symlink praktis bazel-out ada, jalur ke file di repositori utama juga akan di-resolve relatif terhadap direktori ruang kerja.
Menentukan format output menggunakan Starlark
--output=starlark
Format output ini memanggil fungsi Starlark
untuk setiap target yang dikonfigurasi dalam hasil kueri, dan mencetak nilai
yang ditampilkan oleh panggilan. Flag --starlark:file menentukan lokasi file Starlark yang menentukan fungsi bernama format dengan satu parameter, target. Fungsi ini dipanggil untuk setiap Target
dalam hasil kueri. Atau, untuk kemudahan, Anda dapat menentukan isi fungsi yang dideklarasikan sebagai def format(target): return expr menggunakan flag --starlark:expr.
Dialek Starlark 'cquery'
Lingkungan Starlark cquery berbeda dengan file BUILD atau .bzl. Lingkungan ini mencakup
semua konstanta dan fungsi bawaan Starlark
inti,
ditambah beberapa konstanta dan fungsi khusus cquery yang dijelaskan di bawah, tetapi tidak (misalnya) glob,
native, atau rule, dan tidak mendukung pernyataan pemuatan.
build_options(target)
build_options(target) menampilkan peta yang kuncinya adalah ID opsi build (lihat
Konfigurasi)
dan nilainya adalah nilai Starlark. Opsi build yang nilainya bukan nilai Starlark yang sah akan dihapus dari peta ini.
Jika target adalah file input, build_options(target) akan menampilkan None, karena target file input memiliki konfigurasi null.
providers(target)
providers(target) menampilkan peta yang kuncinya adalah nama
penyedia
(misalnya, "DefaultInfo") dan nilainya adalah nilai Starlark. Penyedia yang nilainya bukan nilai Starlark yang sah akan dihapus dari peta ini.
Contoh
Mencetak daftar nama dasar semua file yang dihasilkan oleh //foo yang dipisahkan spasi:
bazel cquery //foo --output=starlark \
--starlark:expr="' '.join([f.basename for f in target.files.to_list()])"
Mencetak daftar jalur semua file yang dihasilkan oleh target aturan di //bar dan subpaketnya yang dipisahkan spasi:
bazel cquery 'kind(rule, //bar/...)' --output=starlark \
--starlark:expr="' '.join([f.path for f in target.files.to_list()])"
Mencetak daftar mnemonik semua tindakan yang didaftarkan oleh //foo.
bazel cquery //foo --output=starlark \
--starlark:expr="[a.mnemonic for a in target.actions]"
Mencetak daftar output kompilasi yang didaftarkan oleh cc_library //baz.
bazel cquery //baz --output=starlark \
--starlark:expr="[f.path for f in target.output_groups.compilation_outputs.to_list()]"
Mencetak nilai opsi command line --javacopt saat membuat //foo.
bazel cquery //foo --output=starlark \
--starlark:expr="build_options(target)['//command_line_option:javacopt']"
Mencetak label setiap target dengan tepat satu output. Contoh ini menggunakan fungsi Starlark yang ditentukan dalam file.
$ 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
Mencetak label setiap target yang sepenuhnya Python 3. Contoh ini menggunakan fungsi Starlark yang ditentukan dalam file.
$ 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
Mengekstrak nilai dari Penyedia yang ditentukan pengguna.
$ 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 vs. query
cquery dan query saling melengkapi dan unggul dalam
ceruk yang berbeda. Pertimbangkan hal berikut untuk memutuskan mana yang tepat untuk Anda:
cquerymengikuti cabangselect()tertentu untuk memodelkan grafik persis yang Anda buat.querytidak mengetahui cabang yang dipilih build, sehingga melakukan overestimasi dengan menyertakan semua cabang.- Presisi
cquerymemerlukan pembuatan lebih banyak grafik daripadaquerySecara khusus,cquerymengevaluasi target yang dikonfigurasi , sedangkanqueryhanya mengevaluasi target. Hal ini memerlukan lebih banyak waktu dan menggunakan lebih banyak memori. - Interpretasi
cquery's terhadap bahasa kueri menimbulkan ambiguitas yang dihindariquery. Misalnya, jika"//foo"ada dalam dua konfigurasi, mana yang haruscquery "deps(//foo)"gunakan? Fungsiconfigdapat membantu hal ini. - Sebagai alat yang lebih baru,
cquerytidak memiliki dukungan untuk kasus penggunaan tertentu. Lihat Masalah umum untuk mengetahui detailnya.
Masalah umum
Semua target yang cquery "dibuat" harus memiliki konfigurasi yang sama.
Sebelum mengevaluasi kueri, cquery memicu build hingga tepat sebelum titik tempat tindakan build akan dieksekusi. Target yang
"dibuat" secara default dipilih dari semua label yang muncul dalam ekspresi
kueri (hal ini dapat diganti
dengan --universe_scope). Target ini
harus memiliki konfigurasi yang sama.
Meskipun umumnya berbagi konfigurasi "target" tingkat atas,
aturan dapat mengubah konfigurasinya sendiri dengan
transisi edge yang masuk.
Di sinilah cquery tidak berfungsi.
Solusi: Jika memungkinkan, tetapkan --universe_scope ke cakupan yang lebih ketat. Contoh:
# 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
Tidak ada dukungan untuk --output=xml.
Output non-deterministik.
cquery tidak otomatis menghapus grafik build dari perintah sebelumnya dan oleh karena itu rentan mengambil hasil dari kueri sebelumnya. Misalnya, genrule menerapkan transisi exec pada
atribut tools-nya, yaitu mengonfigurasi alatnya dalam
konfigurasi exec.
Anda dapat melihat efek transisi yang tersisa di bawah.
$ 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 (exec_config)
...
$ bazel cquery "//foo:tool"
tool(exec_config)
Solusi: ubah opsi startup apa pun untuk memaksa analisis ulang target yang dikonfigurasi.
Misalnya, tambahkan --test_arg=<whatever> ke perintah build Anda.
Pemecahan masalah
Pola target rekursif (/...)
Jika Anda menemukan:
$ 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.
hal ini salah menyarankan paket //foo tidak dalam cakupan meskipun
--universe_scope=//foo:app menyertakannya. Hal ini disebabkan oleh batasan desain di cquery. Sebagai solusinya, sertakan //foo/... secara eksplisit dalam cakupan universe:
$ bazel cquery --universe_scope=//foo:app,//foo/... "somepath(//foo:app, //foo/...)"
Jika hal tersebut tidak berhasil (misalnya, karena beberapa target di //foo/... tidak dapat dibuat dengan flag build yang dipilih), hapus pola secara manual ke dalam paket konstituennya dengan kueri pra-pemrosesan:
# 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 "+" -))"