cquery
adalah varian dari query
yang menangani
select()
dan efek opsi build dengan benar pada grafik
build.
Hal ini dicapai dengan menjalankan hasil fase
analisis Bazel,
yang mengintegrasikan efek ini. Sebaliknya, query
berjalan melalui 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
mem-build target.
Karena cquery
berjalan di atas grafik target yang dikonfigurasi, grafik tersebut tidak memiliki insight tentang artefak seperti tindakan build atau akses ke aturan [test_suite](/versions/6.5.0/reference/be/general#test_suite)
karena target tersebut bukan target yang dikonfigurasi. Untuk yang pertama, lihat [aquery](/versions/6.5.0/docs/aquery)
.
Sintaksis dasar
Panggilan cquery
sederhana terlihat seperti:
bazel cquery "function(//target)"
Ekspresi kueri "function(//target)"
terdiri dari hal berikut:
function(...)
adalah fungsi yang akan dijalankan di target.cquery
mendukung sebagian besar fungsiquery
, ditambah beberapa fungsi baru.//target
adalah ekspresi yang dimasukkan ke fungsi. Dalam contoh ini, ekspresi adalah target sederhana. Namun, bahasa kueri juga memungkinkan fungsi bertingkat. Lihat Cara Membuat Kueri untuk mengetahui contohnya.
cquery
memerlukan target untuk dijalankan melalui 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 level 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 konfigurasi lengkap, jalankan:
$ bazel config 9f87702
Konfigurasi host menggunakan ID khusus (HOST)
. File sumber yang tidak dihasilkan, seperti
yang biasa ditemukan di srcs
, menggunakan ID khusus (null)
(karena
tidak perlu dikonfigurasi).
9f87702
adalah awalan dari ID lengkap. Hal ini karena ID lengkap adalah
hash SHA-256 yang panjang dan sulit diikuti. cquery
memahami setiap awalan
yang valid dari ID lengkap, mirip dengan
hash singkat Git.
Untuk melihat ID lengkap, jalankan $ bazel config
.
Evaluasi pola target
//foo
memiliki arti yang berbeda untuk cquery
dibandingkan dengan 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.
Tindakan ini memberikan hasil yang lebih halus untuk ekspresi kueri dibandingkan 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 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)
Jika Anda ingin mendeklarasikan instance mana yang akan dikueri secara akurat, gunakan fungsi config
.
Lihat dokumentasi pola target query
untuk mengetahui informasi selengkapnya tentang pola target.
Fungsi
Dari kumpulan fungsi
yang didukung oleh query
, cquery
mendukung semuanya 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 target
, host
, null
, atau
hash konfigurasi kustom. Hash dapat diambil dari $
bazel config
atau output cquery
sebelumnya.
Contoh:
$ bazel cquery "config(//bar, host)" --universe_scope=//foo
$ bazel cquery "deps(//foo)" //bar (HOST) //baz (3732cc8) $ 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 pada build Bazel biasa sehingga mewarisi set
opsi yang tersedia selama proses build.
Menggunakan opsi kueri
--universe_scope
(daftar yang dipisahkan koma)
Sering kali, dependensi target yang dikonfigurasi akan melalui transisi, yang menyebabkan konfigurasinya berbeda dengan dependensinya. Flag ini memungkinkan Anda membuat kueri target seolah-olah dibuat sebagai dependensi atau dependensi transisional dari target lain. Contoh:
# x/BUILD genrule( name = "my_gen", srcs = ["x.in"], outs = ["x.cc"], cmd = "$(locations :tool) $< >$@", tools = [":tool"], ) cc_library( name = "tool", )
Genrules mengonfigurasi alat mereka di konfigurasi host sehingga kueri berikut akan menghasilkan output berikut:
Kueri | Target 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(hostconfig) |
Jika flag ini disetel, kontennya akan dibangun. Jika tidak ditetapkan, semua target
yang disebutkan dalam ekspresi kueri akan di-build. Penutupan transitif dari
target yang dibuat digunakan sebagai semesta kueri. Apa pun yang terjadi, target yang
akan dibuat harus dapat dibuat di tingkat teratas (yaitu, kompatibel dengan opsi
level teratas). cquery
menampilkan hasil dalam penutupan transitif dari
target tingkat teratas ini.
Meskipun Anda dapat mem-build semua target dalam ekspresi kueri di level
teratas, sebaiknya jangan melakukannya. Misalnya, menetapkan
--universe_scope
secara eksplisit dapat mencegah pembuatan target beberapa kali dalam
konfigurasi yang tidak Anda minati. Hal ini juga dapat membantu menentukan versi konfigurasi target
yang Anda cari (karena saat ini tidak mungkin
untuk menentukannya sepenuhnya dengan cara lain). Anda harus menetapkan tanda ini jika ekspresi kueri Anda lebih kompleks daripada deps(//foo)
.
--implicit_deps
(boolean, default=True)
Menetapkan tanda ini ke salah akan memfilter semua hasil yang tidak ditetapkan secara eksplisit dalam file BUILD, dan sebagai gantinya ditetapkan di tempat lain oleh Bazel. Hal ini mencakup pemfilteran toolchain yang di-resolve.
--tool_deps
(boolean, default=True)
Menetapkan tanda ini ke salah 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 ada dalam konfigurasi target. Jika target yang dikueri berada dalam konfigurasi non-target, setelan --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)
Aspek dapat menambahkan
dependensi tambahan ke build. Secara default, cquery
tidak mengikuti aspek karena
aspek tersebut membuat grafik yang dapat dikueri menjadi lebih besar, sehingga menggunakan lebih banyak memori. Namun, mengikutinya akan menghasilkan hasil yang lebih
akurat.
Jika Anda tidak khawatir dengan dampak memori dari kueri besar, aktifkan flag ini secara default di bazelrc Anda.
Jika membuat kueri dengan aspek dinonaktifkan, Anda dapat mengalami masalah saat target X gagal saat membangun target Y, tetapi cquery somepath(Y, X)
dan cquery deps(Y) | grep 'X'
tidak menampilkan hasil karena dependensi terjadi melalui aspek.
Format keluaran
Secara default, cquery menghasilkan output dalam daftar pasangan label dan konfigurasi yang diurutkan berdasarkan dependensi. Ada juga opsi lain untuk mengekspos hasil.
Transisi
--transitions=lite --transitions=full
Transisi konfigurasi digunakan untuk mem-build target di bawah target tingkat teratas dalam konfigurasi yang berbeda dengan target tingkat teratas.
Misalnya, target dapat menerapkan transisi ke konfigurasi host pada semua
dependensi dalam atribut tools
-nya. Hal ini dikenal sebagai transisi
atribut. Aturan juga dapat menerapkan transisi pada konfigurasinya sendiri,
yang dikenal sebagai transisi class aturan. Format output ini menghasilkan informasi tentang
transisi ini seperti jenisnya dan pengaruhnya terhadap opsi
build.
Format output ini dipicu oleh flag --transitions
yang secara default
ditetapkan ke NONE
. Nilai ini dapat disetel ke mode FULL
atau LITE
. Mode FULL
menghasilkan
informasi tentang transisi class aturan dan transisi atribut, termasuk
perbedaan mendetail dari opsi sebelum dan sesudah transisi. Mode LITE
mengeluarkan informasi yang sama tanpa perbedaan opsi.
Output pesan protokol
--output=proto
Opsi ini menyebabkan target yang dihasilkan dicetak dalam bentuk buffering protokol biner. Definisi buffering protokol dapat ditemukan di src/main/protobuf/analysis.proto.
CqueryResult
adalah pesan tingkat teratas 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 menghilangkan informasi ini dan mendapatkan output proto yang diformat persis seperti output proto kueri, tetapkan tanda ini ke salah (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 dokumentasi output grafik query
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
tanda --output_groups
.
File ini menyertakan file sumber.
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 memudahkan, Anda dapat menentukan
isi fungsi yang dideklarasikan sebagai def format(target): return expr
menggunakan
tanda --starlark:expr
.
'cquery' Dialek Starlark
Lingkungan Starlark cquery berbeda dengan file BUILD atau .bzl. Versi ini mencakup semua konstanta dan fungsi bawaan Starlark inti, ditambah beberapa kueri khusus kueri 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 yang nilainya merupakan nilai Starlark. Opsi build yang nilainya bukan nilai Starlark
yang sah akan dihilangkan dari peta ini.
Jika target adalah file input, build_options(target)
akan menampilkan Tidak Ada, 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 dihilangkan dari peta ini.
Contoh
Cetak daftar nama dasar yang dipisahkan spasi dari semua file yang dihasilkan oleh //foo
:
bazel cquery //foo --output=starlark \ --starlark:expr="' '.join([f.basename for f in target.files.to_list()])"
Cetak daftar jalur yang dipisahkan spasi dan berisi semua file yang dihasilkan oleh target aturan di //bar
dan sub-paketnya:
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 terdaftar oleh //foo
.
bazel cquery //foo --output=starlark \ --starlark:expr="[a.mnemonic for a in target.actions]"
Mencetak daftar output kompilasi yang terdaftar oleh cc_library
//baz
.
bazel cquery //baz --output=starlark \ --starlark:expr="[f.path for f in target.output_groups.compilation_outputs.to_list()]"
Cetak nilai opsi command line --javacopt
saat mem-build //foo
.
bazel cquery //foo --output=starlark \ --starlark:expr="build_options(target)['//command_line_option:javacopt']"
Cetak label setiap target dengan satu output. Contoh ini menggunakan fungsi Starlark yang didefinisikan dalam sebuah 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
Cetak label setiap target yang benar-benar 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
kueri vs. kueri
cquery
dan query
saling melengkapi dan unggul dalam
niche yang berbeda. Pertimbangkan hal berikut untuk memutuskan mana yang tepat bagi Anda:
cquery
mengikuti cabangselect()
tertentu untuk membuat model grafik yang tepat yang Anda buat.query
tidak mengetahui cabang mana yang dipilih build, sehingga melakukan perkiraan berlebihan dengan menyertakan semua cabang.- Presisi
cquery
memerlukan pembuatan lebih banyak grafik daripadaquery
. Secara khusus,cquery
mengevaluasi target yang dikonfigurasi, sedangkanquery
hanya mengevaluasi target. Tindakan ini memerlukan lebih banyak waktu dan menggunakan lebih banyak memori. - Penafsiran
cquery
terhadap bahasa kueri menyebabkan ambiguitas yang dihindariquery
. Misalnya, jika"//foo"
ada dalam dua konfigurasi, manakah yang harus digunakancquery "deps(//foo)"
? Fungsi[config](#config)
dapat membantu menangani hal ini. - Sebagai alat yang lebih baru,
cquery
tidak memiliki dukungan untuk kasus penggunaan tertentu. Lihat Masalah umum untuk mengetahui detailnya.
Masalah umum
Semua target yang "di-build" cquery
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 (ini dapat diganti
dengan --universe_scope
). Target ini
harus memiliki konfigurasi yang sama.
Meskipun umumnya berbagi konfigurasi "target" tingkat teratas,
aturan dapat mengubah konfigurasinya sendiri dengan
transisi tepi masuk.
Di sinilah cquery
gagal.
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 sehingga rentan mengambil hasil dari kueri
sebelumnya. Misalnya, genquery
menerapkan transisi host pada
atribut tools
-nya, yaitu mengonfigurasi alat di
konfigurasi host.
Anda dapat melihat efek yang berlanjut dari transisi tersebut 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 (host_config) ... $ bazel cquery "//foo:tool" tool(host_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 mengalami:
$ 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 menunjukkan bahwa paket //foo
tidak berada dalam cakupan meskipun
--universe_scope=//foo:app
menyertakannya. Hal ini disebabkan oleh batasan desain di
cquery
. Sebagai solusinya, sertakan //foo/...
secara eksplisit dalam cakupan
alam semesta:
$ bazel cquery --universe_scope=//foo:app,//foo/... "somepath(//foo:app, //foo/...)"
Jika cara tersebut tidak berhasil (misalnya, karena beberapa target di //foo/...
tidak dapat
di-build dengan flag build yang dipilih), buka pola secara manual ke dalam
paket penyusunnya 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 "+" -))"