cquery
adalah varian dari query
yang menangani dengan benar
select()
dan opsi build' efek pada build
grafik.
Hal ini dicapai dengan menjalankan hasil analisis terhadap
fase,
yang mengintegrasikan efek-efek ini. Sebaliknya, query
ditampilkan 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 mencakup ID unik (9f87702)
dari
konfigurasi
target bawaannya.
Karena cquery
berjalan di atas grafik target yang dikonfigurasi. tidak memiliki wawasan
menjadi artefak seperti tindakan build atau akses ke test_suite
aturan karena bukan target yang dikonfigurasi. Untuk yang pertama, lihat aquery
.
Sintaksis dasar
Panggilan cquery
sederhana akan terlihat seperti ini:
bazel cquery "function(//target)"
Ekspresi kueri "function(//target)"
terdiri dari hal berikut:
function(...)
adalah fungsi yang akan dijalankan pada target.cquery
mendukung sebagian besar dari fungsiquery
, ditambah beberapa sinyal baru.//target
adalah ekspresi yang dimasukkan ke fungsi. Dalam contoh ini, ekspresi merupakan target sederhana. Tetapi bahasa kueri juga memungkinkan pembuatan fungsi bertingkat. Lihat Panduan kueri untuk mengetahui contohnya.
cquery
memerlukan target untuk dijalankan melalui pemuatan dan analisis
fase-fase ini. Kecuali jika ditentukan lain, cquery
akan mengurai target yang tercantum dalam
ekspresi kueri. Lihat --universe_scope
untuk mengkueri 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 Anda.
Untuk melihat konten konfigurasi lengkap, jalankan:
$ bazel config 9f87702
9f87702
adalah awalan dari ID lengkap. Hal ini karena ID yang lengkap
Hash SHA-256, yang panjang dan sulit diikuti. cquery
memahami semua permintaan
awalan ID lengkap, mirip dengan
Buat hash singkat.
Untuk melihat ID lengkap, jalankan $ bazel config
.
Evaluasi pola target
//foo
memiliki arti yang berbeda untuk cquery
dibandingkan untuk query
. Hal ini karena
cquery
mengevaluasi target yang dikonfigurasi dan grafik build dapat memiliki beberapa
versi //foo
yang dikonfigurasi.
Untuk cquery
, pola target dalam ekspresi kueri mengevaluasi
ke setiap target yang dikonfigurasi dengan label yang cocok dengan pola tersebut. Output adalah
determenistik, 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 memberikan 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 secara tepat mendeklarasikan instance mana yang harus dikueri, gunakan
fungsi config
.
Lihat pola target query
dokumentasi untuk mengetahui informasi selengkapnya tentang pola target.
Fungsi
Dari kumpulan fungsi
didukung oleh query
, cquery
mendukung semua 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 ditandai oleh argumen dan konfigurasi pertama yang ditentukan oleh atribut
argumen kedua.
Nilai yang valid untuk argumen kedua adalah null
atau
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 kolom yang ditentukan , hanya yang dapat ditemukan yang dikembalikan. Jika tidak ada hasil ditemukan di konfigurasi tertentu, maka kueri akan gagal.
Opsi
Opsi build
cquery
berjalan pada build Bazel reguler sehingga mewarisi set
opsi yang tersedia selama proses build.
Menggunakan opsi kueri
--universe_scope
(daftar yang dipisahkan koma)
Sering kali, dependensi target yang dikonfigurasi melewati transisi, yang menyebabkan konfigurasinya berbeda dari dependensinya. Tanda ini memungkinkan Anda untuk membuat kueri target seolah-olah itu dibuat sebagai dependensi atau dependensi 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 eksekutif sehingga kueri berikut akan menghasilkan output berikut:
Kueri | Target Dibangun | 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 disetel, kontennya akan dibangun. Jika tidak ditetapkan, semua target
yang disebutkan dalam ekspresi kueri akan dibuat. Penutupan transitif dari
target yang telah dibuat digunakan
sebagai kumpulan kueri. Bagaimanapun, target yang
dibangun harus dapat dibangun di tingkat atas (yaitu, kompatibel dengan tingkat atas
lainnya). cquery
menampilkan hasil dalam penutupan transitifnya
target tingkat teratas.
Meskipun memungkinkan untuk membangun semua target dalam ekspresi kueri di bagian atas
ada baiknya jika Anda tidak melakukannya. Misalnya, secara eksplisit menetapkan
--universe_scope
dapat mencegah pembuatan target beberapa kali dalam
konfigurasi yang tidak diperlukan. Ini juga bisa membantu menentukan
versi konfigurasi dari sebuah
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 dari deps(//foo)
.
--implicit_deps
(boolean, default=True)
Menyetel penanda ini ke salah akan memfilter semua hasil yang tidak ditetapkan secara eksplisit di file {i>BUILD<i} dan sebagai gantinya ditempatkan di tempat lain oleh Bazel. Hal ini termasuk filter yang telah diselesaikan toolchain.
--tool_deps
(boolean, default=True)
Menyetel penanda ini ke false akan memfilter semua target yang dikonfigurasi, yang
jalur dari target yang dikueri ke pengguna tersebut menyilangkan transisi antar-target
dan perintah
konfigurasi non-target.
Jika target yang dikueri berada dalam konfigurasi target, menyetel --notool_deps
akan
hanya mengembalikan target yang juga ada dalam konfigurasi target. Jika kueri
target berada dalam konfigurasi non-target, setelan --notool_deps
hanya akan menampilkan
target juga dalam konfigurasi non-target. Setelan ini umumnya tidak memengaruhi pemfilteran
toolchain telah ditetapkan.
--include_aspects
(boolean, default=True)
Menyertakan dependensi yang ditambahkan oleh aspects.
Jika flag ini dinonaktifkan, cquery somepath(X, Y)
dan
cquery deps(X) | grep 'Y'
menghilangkan Y jika X hanya bergantung padanya melalui aspek.
Format keluaran
Secara default, output cquery menghasilkan daftar pasangan label dan konfigurasi yang diurutkan berdasarkan dependensi. Ada juga opsi lain untuk menampilkan hasil.
Transisi
--transitions=lite --transitions=full
Transisi konfigurasi digunakan untuk membuat target di bawah target level atas di berbagai konfigurasi daripada target tingkat atas.
Misalnya, target mungkin menerapkan transisi
ke konfigurasi exec pada semua
dependensi dalam atribut tools
miliknya. Ini dikenal sebagai atribut
transisi. Aturan juga dapat menerapkan
transisi pada konfigurasinya sendiri,
yang dikenal sebagai transisi kelas aturan. Format {i>output<i} ini menghasilkan informasi tentang
transisi ini seperti jenisnya dan efeknya pada build
lainnya.
Format output ini dipicu oleh flag --transitions
yang secara default adalah
ditetapkan ke NONE
. Kunci ini dapat disetel ke mode FULL
atau LITE
. Output mode FULL
informasi tentang transisi kelas aturan dan transisi atribut termasuk
perbedaan terperinci dari opsi sebelum dan sesudah transisi. LITE
moda
menghasilkan informasi yang sama tanpa
perbedaan opsi.
Output pesan protokol
--output=proto
Opsi ini menyebabkan target yang dihasilkan dicetak dalam protokol biner dalam bentuk buffer. Definisi penyangga protokol dapat ditemukan di src/main/protobuf/analysis_v2.proto.
CqueryResult
adalah pesan tingkat atas yang berisi hasil kueri. Ini
memiliki daftar ConfiguredTarget
pesan dan daftar Configuration
membuat pesan teks. Setiap ConfiguredTarget
memiliki configuration_id
yang nilainya sama
dengan kolom id
dari pesan Configuration
yang sesuai.
--[no]proto:include_configurations
Secara default, hasil kueri menampilkan informasi konfigurasi sebagai bagian dari masing-masing hasil target yang dikonfigurasi. Jika Anda ingin menghapus informasi ini dan mendapatkan output proto yang diformat persis seperti {i>output proto<i} kueri, setel penanda ini ke {i>false<i}.
Lihat dokumentasi output proto kueri untuk opsi terkait output proto lainnya.
Output grafik
--output=graph
Opsi ini menghasilkan output sebagai file .dot yang kompatibel dengan Graphviz. Lihat query
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 yang mirip dengan daftar yang dicetak di akhir bazel build
pemanggilan. Output hanya berisi file yang diiklankan di permintaan
output seperti yang ditentukan oleh
Flag --output_groups
.
Termasuk di antaranya adalah {i>file<i} sumber.
Semua jalur yang dimunculkan oleh format output ini relatif terhadap
execroot, yang dapat diperoleh
melalui bazel info execution_root
. Jika ada symlink praktis bazel-out
,
jalur ke file di repositori utama juga diselesaikan relatif terhadap ruang kerja
saat ini.
Menentukan format output menggunakan Starlark
--output=starlark
Format output ini memanggil 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 hanya
isi fungsi yang dideklarasikan sebagai def format(target): return expr
dengan menggunakan
tanda --starlark:expr
.
'kueri' Dialek Starlark
Lingkungan Starlark kueri berbeda dengan file BUILD atau .bzl. Ini mencakup
Starlark inti
konstanta dan fungsi bawaan,
ditambah beberapa kueri khusus kueri yang dijelaskan di bawah ini, tetapi bukan (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 nilai-nilainya adalah
nilai Starlark. Opsi build yang nilainya tidak sah menurut Starlark
nilai dihilangkan dari peta ini.
Jika target adalah file input, build_options(target)
akan menampilkan Tidak Ada, sebagai file input
target memiliki konfigurasi null.
provider(target)
providers(target)
menampilkan peta yang kuncinya adalah nama
penyedia
(misalnya, "DefaultInfo"
) dan yang nilainya merupakan nilai Starlark. Penyedia
yang nilainya bukan merupakan nilai Starlark yang sah 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 dari 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()])"
Cetak 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()]"
Cetak nilai opsi command line --javacopt
saat membangun //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 ditentukan 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 sebuah 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
Ekstrak 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
keunikan yang berbeda. Pertimbangkan hal berikut untuk memutuskan mana yang tepat bagi Anda:
cquery
mengikuti cabangselect()
tertentu untuk membuat model grafik yang tepat.query
tidak tahu yang mana cabang yang dipilih build, jadi kurang lebih dengan menyertakan semua cabang.- Presisi
cquery
membutuhkan pembuatan lebih banyak grafik daripadaquery
melakukannya. Khususnya,cquery
mengevaluasi target yang dikonfigurasi, sedangkanquery
hanya mengevaluasi target. Cara ini membutuhkan lebih banyak waktu dan menggunakan lebih banyak memori. - Penafsiran
cquery
tentang bahasa kueri menimbulkan ambiguitas yang dihindariquery
. Misalnya, jika"//foo"
ada dalam dua konfigurasi, mana yang yang harus digunakancquery "deps(//foo)"
? Fungsiconfig
dapat membantu menangani hal ini. - Sebagai alat yang lebih baru,
cquery
tidak memiliki dukungan untuk penggunaan tertentu penggunaan. Lihat Masalah umum untuk mengetahui detailnya.
Masalah umum
Semua target yang "dibangun" oleh cquery
harus memiliki konfigurasi yang sama.
Sebelum mengevaluasi kueri, cquery
memicu build hingga hanya
sebelum titik tempat tindakan build akan dijalankan. Targetnya
"bangunan" dipilih secara default dari semua label yang muncul dalam kueri
(ini dapat diabaikan
dengan --universe_scope
). Ini
harus memiliki konfigurasi yang sama.
Meskipun keduanya umumnya berbagi
dengan "target" tingkat atas konfigurasi,
aturan dapat mengubah konfigurasinya sendiri dengan
transisi edge yang masuk.
Di sinilah cquery
gagal.
Solusi: Jika memungkinkan, tetapkan --universe_scope
ke lebih ketat
ruang lingkup proyek. 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 total grafik build dari
perintah sebelumnya dan karenanya
rentan mengambil hasil dari
terhadap kueri. Misalnya, genquery
memberikan transisi eksekutif pada
atribut tools
-nya, yaitu mengonfigurasi alatnya di
konfigurasi exec.
Anda dapat melihat efek yang masih ada 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 (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 menunjukkan bahwa paket //foo
tidak berada dalam cakupan meskipun
--universe_scope=//foo:app
menyertakannya. Hal ini karena keterbatasan desain dalam
cquery
. Sebagai solusi, sertakan //foo/...
secara eksplisit di alam semesta
ruang lingkup:
$ bazel cquery --universe_scope=//foo:app,//foo/... "somepath(//foo:app, //foo/...)"
Jika itu tidak berhasil (misalnya, karena beberapa target dalam //foo/...
tidak bisa
dengan flag build yang dipilih), secara manual buka pola ke dalam
paket konstituen 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 "+" -))"