Yapılandırılabilir Sorgu (cquery)

cquery, query varyantının select() ve derleme seçeneklerinin derleme grafiğindeki etkilerini doğru şekilde işleyen bir varyantıdır.

Bu işlemi, Bazel'in bu efektleri entegre eden analiz aşamasının sonuçlarını çalıştırarak gerçekleştirir. Buna karşılık query, seçenekler değerlendirilmeden önce Bazel'in yükleme aşamasının sonuçlarını işler.

Örneğin:

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

Her sonuç, hedefin oluşturulduğu yapılandırmanın benzersiz tanımlayıcısını (9f87702) içerir.

cquery, yapılandırılmış hedef grafiğin üzerinde çalıştığı için yapılandırılmış hedef olmadıkları için derleme işlemleri veya [test_suite](/versions/6.5.0/reference/be/general#test_suite) kurallarına erişim gibi yapılar hakkında analiz sağlamaz. İlki için [aquery](/versions/6.5.0/docs/aquery) başlıklı makaleyi inceleyin.

Temel söz dizimi

Basit bir cquery çağrısı şöyle görünür:

bazel cquery "function(//target)"

"function(//target)" sorgu ifadesi aşağıdakilerden oluşur:

  • function(...), hedefte çalıştırılacak işlevdir. cquery, query'un işlevlerinin çoğunu ve birkaç yeni işlevi destekler.
  • //target, işleve beslenen ifadedir. Bu örnekte, ifade basit bir hedeftir. Ancak sorgu dili, işlevlerin iç içe yerleştirilmesine de olanak tanır. Örnekler için Sorgu Kullanma bölümüne bakın.

cquery, bir hedefin yükleme ve analiz aşamalarından geçmesini gerektirir. Aksi belirtilmedikçe cquery, sorgu ifadesinde listelenen hedefleri ayrıştırır. Üst düzey derleme hedeflerinin bağımlılıklarını sorgulamak için --universe_scope bölümüne bakın.

Yapılandırmalar

Satır:

//tree:ash (9f87702)

//tree:ash, 9f87702 kimlikli bir yapılandırmada oluşturuldu demektir. Çoğu hedef için bu, yapılandırmayı tanımlayan derleme seçeneği değerlerinin opak karmasıdır.

Yapılandırmanın tüm içeriğini görmek için şu komutu çalıştırın:

$ bazel config 9f87702

Ana makine yapılandırmasında (HOST) özel kimliği kullanılır. Genellikle srcs içinde bulunanlar gibi oluşturulmamış kaynak dosyaları, yapılandırılmaları gerekmediği için özel kimlik (null)'ü kullanır.

9f87702, tam kimliğin ön ekidir. Bunun nedeni, tam kimliklerin uzun ve takip edilmesi zor olan SHA-256 karmaları olmasıdır. cquery, Git kısa karma oluşturma işlemine benzer şekilde, tam bir kimliğin geçerli ön eklerini anlar. Tam kimlikleri görmek için $ bazel config komutunu çalıştırın.

Hedef kalıp değerlendirmesi

//foo, cquery için query ile aynı anlama sahip değildir. Bunun nedeni, cquery'ün yapılandırılmış hedefleri değerlendirmesidir ve derleme grafiğinde //foo'ın birden fazla yapılandırılmış sürümü olabilir.

cquery için sorgu ifadesindeki bir hedef kalıbı, bu kalıpla eşleşen bir etikete sahip her yapılandırılmış hedefe göre değerlendirilir. Çıkış belirleyicidir ancak cquery, temel sorgu sipariş sözleşmesi dışında hiçbir sipariş garantisi vermez.

Bu, sorgu ifadeleri için query ile kıyaslandığında daha hassas sonuçlar verir. Örneğin, aşağıdaki arama terimi birden fazla sonuç verebilir:

# 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)

Hangi örneğin üzerinde sorgu yapılacağını kesin olarak belirtmek istiyorsanız config işlevini kullanın.

Hedef kalıplar hakkında daha fazla bilgi için query'nin hedef kalıp dokümanlarına bakın.

İşlevler

query tarafından desteklenen işlev grubundan cquery, allrdeps, buildfiles, rbuildfiles, siblings, tests ve visible dışındaki tüm işlevleri destekler.

cquery aşağıdaki yeni işlevleri de kullanıma sunuyor:

yapılandırma

expr ::= config(expr, word)

config operatörü, ilk bağımsız değişken ve ikinci bağımsız değişken tarafından belirtilen yapılandırma ile belirtilen etiket için yapılandırılmış hedefi bulmaya çalışır.

İkinci bağımsız değişken için geçerli değerler target, host, null veya özel yapılandırma karma değeri'dir. Karma oluşturma işlemleri $ bazel config veya önceki bir cquery'un çıkışından alınabilir.

Örnekler:

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

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

Belirtilen yapılandırmada ilk bağımsız değişkenin tüm sonuçları bulunamazsa yalnızca bulunabilenler döndürülür. Belirtilen yapılandırmada sonuç bulunamazsa sorgu başarısız olur.

Seçenekler

Derleme seçenekleri

cquery, normal bir Bazel derlemesi üzerinde çalışır ve bu nedenle derleme sırasında kullanılabilen seçenek kümesini devralır.

Sorgu seçeneklerini kullanma

--universe_scope (virgülle ayrılmış liste)

Yapılandırılmış hedeflerin bağımlılıkları genellikle geçişlerden geçer. Bu da yapılandırmalarının, bağımlılarından farklı olmasına neden olur. Bu işaret, bir hedefi başka bir hedefin bağımlılık veya geçişli bağımlılığı olarak oluşturulmuş gibi sorgulamanızı sağlar. Örneğin:

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

Genrules, araçlarını ana makine yapılandırmasında yapılandırır. Bu nedenle, aşağıdaki sorgular aşağıdaki çıkışları verir:

Sorgu Hedef Oluşturuldu Çıkış
bazel cquery "//x:tool" //x:tool //x:tool(targetconfig)
bazel cquery "//x:tool" --universe_scope="x:my_gen" //x:my_gen //x:tool(hostconfig)

Bu işaret ayarlanırsa içeriği oluşturulur. Ayarlanmazsa sorgu ifadesinde belirtilen tüm hedefler oluşturulur. Oluşturulan hedeflerin geçişli kapatması, sorgunun evreni olarak kullanılır. Her iki durumda da, oluşturulacak hedefler üst düzeyde derlenebilir olmalıdır (yani üst düzey seçeneklerle uyumlu olmalıdır). cquery, bu üst düzey hedeflerin geçişli kapatılmasıyla ilgili sonuçları döndürür.

Bir sorgu ifadesinde tüm hedefleri en üst düzeyde oluşturmak mümkün olsa bile bunu yapmamak faydalı olabilir. Örneğin, --universe_scope politikasını açık bir şekilde ayarlamak, önemsemediğiniz yapılandırmalarda hedefleri birden çok kez oluşturmayı engelleyebilir. Aradığınız hedefin yapılandırma sürümünü belirtmenize de yardımcı olabilir (çünkü şu anda bunu başka bir şekilde tam olarak belirtmek mümkün değildir). Sorgu ifadeniz deps(//foo)'ten daha karmaşıksa bu işareti ayarlamanız gerekir.

--implicit_deps (boolean, varsayılan=True)

Bu işaret false olarak ayarlandığında, BUILD dosyasında açıkça ayarlanmayan ve bunun yerine Bazel tarafından başka bir yerde ayarlanan tüm sonuçlar filtrelenir. Çözüme ulaştırılan araç zincirlerini filtreleme de buna dahildir.

--tool_deps (boolean, varsayılan=True)

Bu işaret yanlış olarak ayarlanırsa sorgulanan hedeften kendilerine giden yolun, hedef yapılandırması ile hedef olmayan yapılandırmalar arasındaki geçişten geçtiği tüm yapılandırılmış hedefler filtrelenir. Sorgulanan hedef hedef yapılandırmadaysa --notool_deps ayarı yalnızca hedef yapılandırmada da bulunan hedefleri döndürür. Sorgulanan hedef, hedef olmayan bir yapılandırmadaysa --notool_deps ayarlanması, yalnızca hedef olmayan yapılandırmalardaki hedefleri de döndürür. Bu ayar, genellikle çözülmüş araç zincirlerinin filtrelenmesini etkilemez.

--include_aspects (boolean, varsayılan=True)

Aspects, bir derlemeye ek bağımlılıklar ekleyebilir. Sorgulanabilir grafiği büyüterek daha fazla bellek kullandıkları için cquery varsayılan olarak yönleri takip etmez. Ancak bunları takip etmek daha doğru sonuçlar sağlar.

Büyük sorguların bellek üzerindeki etkisinden endişelenmiyorsanız bazelrc dosyanızda bu işareti varsayılan olarak etkinleştirin.

Yönleri devre dışı bırakarak sorgu yaparsanız hedef Y oluşturulurken hedef X'in başarısız olduğu ancak bağımlılık bir yön aracılığıyla gerçekleştiği için cquery somepath(Y, X) ve cquery deps(Y) | grep 'X''ün hiçbir sonuç döndürmediği bir sorunla karşılaşabilirsiniz.

Çıkış biçimleri

Varsayılan olarak cquery, sonuçları etiket ve yapılandırma çiftlerinin bağımlılık sırasına göre düzenlenmiş bir listesinde döndürür. Sonuçları göstermek için başka seçenekler de vardır.

Geçişler

--transitions=lite
--transitions=full

Yapılandırma geçişleri, üst düzey hedeflerin altında üst düzey hedeflerden farklı yapılandırmalarda hedefler oluşturmak için kullanılır.

Örneğin, bir hedef, tools özelliğindeki tüm bağımlılıklarda ana makine yapılandırmasına geçişi zorunlu kılabilir. Bunlara özellik geçişleri denir. Kurallar, kendi yapılandırmalarında geçişler de uygulayabilir. Bu geçişlere kural sınıfı geçişleri denir. Bu çıkış biçimi, bu geçişlerle ilgili bilgileri (ör. türleri ve derleme seçenekleri üzerindeki etkileri) gösterir.

Bu çıkış biçimi, varsayılan olarak NONE değerine ayarlanmış --transitions işareti tarafından tetiklenir. FULL veya LITE moduna ayarlanabilir. FULL modu, geçiş öncesi ve sonrası seçeneklerin ayrıntılı bir karşılaştırmasını da içeren kural sınıfı geçişleri ve özellik geçişleri hakkında bilgi verir. LITE modu, seçenekler farkı olmadan aynı bilgileri gösterir.

Protokol mesajı çıkışı

--output=proto

Bu seçenek, elde edilen hedeflerin ikili protokol arabelleği biçiminde yazdırılmasına neden olur. Protokol arabelleğinin tanımını src/main/protobuf/analysis.proto adresinde bulabilirsiniz.

CqueryResult, cquery'nin sonuçlarını içeren üst düzey iletidir. Bu dosyada ConfiguredTarget mesajlarının ve Configuration mesajlarının listesi bulunur. Her ConfiguredTarget, değeri ilgili Configuration mesajındaki id alanına eşit olan bir configuration_id içerir.

--[no]proto:include_configurations

Varsayılan olarak cquery sonuçları, yapılandırılmış her hedefin bir parçası olarak yapılandırma bilgilerini döndürür. Bu bilgiyi atlamak ve tam olarak sorgunun proto çıkışıyla aynı şekilde biçimlendirilmiş bir proto çıkışı almak istiyorsanız bu işareti false (yanlış) olarak ayarlayın.

Proto çıkışıyla ilgili daha fazla seçenek için sorgunun proto çıkışı belgelerine bakın.

Grafik çıkışı

--output=graph

Bu seçenek, çıktıyı Graphviz uyumlu bir .dot dosyası olarak oluşturur. Ayrıntılar için query'ın grafik çıkış dokümanlarına bakın. cquery, --graph:node_limit ve --graph:factored özelliklerini de destekler.

Dosya çıkışı

--output=files

Bu seçenek, bazel build çağrısının sonunda yazdırılan listeye benzer şekilde, sorguyla eşleşen her hedef tarafından üretilen çıkış dosyalarının bir listesini yazdırır. Çıkışta yalnızca --output_groups işaretçisine göre belirlenen istenen çıkış gruplarında reklamı yapılan dosyalar bulunur. Kaynak dosyalar bu kapsama girer.

Starlark'ı kullanarak çıkış biçimini tanımlama

--output=starlark

Bu çıkış biçimi, sorgu sonucundaki her yapılandırılmış hedef için Starlark işlevini çağırır ve çağrı tarafından döndürülen değeri yazdırır. --starlark:file işaretçisi, format adlı bir işlevi tek bir parametreyle (target) tanımlayan bir Starlark dosyasının konumunu belirtir. Bu işlev, sorgu sonucundaki her bir Hedef için çağrılır. Alternatif olarak, kolaylık sağlamak için --starlark:expr işaretini kullanarak def format(target): return expr olarak tanımlanan bir işlevin yalnızca gövdesini belirtebilirsiniz.

"cquery" Starlark lehçesi

cquery Starlark ortamı, BUILD veya .bzl dosyasından farklıdır. Tüm temel Starlark yerleşik sabitlerini ve işlevlerini, ayrıca aşağıda açıklanan birkaç cquery'ye özgü sabitleri içerir ancak glob, native veya rule'yi içermez ve load ifadelerini desteklemez.

build_options(hedef)

build_options(target), anahtarları derleme seçeneği tanımlayıcıları (Yapılandırmalar bölümüne bakın) ve değerleri Starlark değerleri olan bir harita döndürür. Değerleri geçerli Starlark değerleri olmayan derleme seçenekleri bu haritada atlanır.

Hedef bir giriş dosyasıysa giriş dosyası hedefleri null yapılandırmaya sahip olduğundan build_options(target) None değerini döndürür.

providers(hedef)

providers(target), anahtarları sağlayıcıların adları (örneğin, "DefaultInfo") ve değerleri Starlark değerleri olan bir harita döndürür. Değerleri geçerli Starlark değerleri olmayan sağlayıcılar bu haritada yer almaz.

Örnekler

//foo tarafından oluşturulan tüm dosyaların temel adlarının boşlukla ayrılmış bir listesini yazdırın:

  bazel cquery //foo --output=starlark \
    --starlark:expr="' '.join([f.basename for f in target.files.to_list()])"

//bar ve alt paketlerinde rule hedefleri tarafından oluşturulan tüm dosyaların yollarının boşlukla ayrılmış bir listesini yazdırın:

  bazel cquery 'kind(rule, //bar/...)' --output=starlark \
    --starlark:expr="' '.join([f.path for f in target.files.to_list()])"

//foo tarafından kaydedilen tüm işlemlerin anımsatıcılarının listesini yazdırın.

  bazel cquery //foo --output=starlark \
    --starlark:expr="[a.mnemonic for a in target.actions]"

cc_library //baz tarafından kaydedilen derleme çıktılarının listesini yazdırma

  bazel cquery //baz --output=starlark \
    --starlark:expr="[f.path for f in target.output_groups.compilation_outputs.to_list()]"

//foo oluştururken --javacopt komut satırı seçeneğinin değerini yazdırın.

  bazel cquery //foo --output=starlark \
    --starlark:expr="build_options(target)['//command_line_option:javacopt']"

Her hedefin etiketini tam olarak bir çıkışla yazdırın. Bu örnekte, bir dosyada tanımlanan Starlark işlevleri kullanılmaktadır.

  $ 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

Her hedefin etiketini yazdırın. Bu etiketler yalnızca Python 3'tür. Bu örnekte, bir dosyada tanımlanan Starlark işlevleri kullanılmaktadır.

  $ 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

Kullanıcı tanımlı bir sağlayıcıdan değer ayıklayın.

  $ 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 ve query

cquery ve query birbirini tamamlar ve farklı alanlarda başarılıdır. Sizin için en uygun seçeneği belirlemek üzere aşağıdakileri göz önünde bulundurun:

  • cquery, oluşturduğunuz grafiği tam olarak modellemek için belirli select() dallarını izler. query, derlemenin hangi dalı seçtiğini bilmediği için tüm dalları dahil ederek fazla tahminde bulunur.
  • cquery'ün hassasiyeti, grafiğin query'ten daha fazla oluşturulmasını gerektirir. Daha açık belirtmek gerekirse cquery, yapılandırılmış hedefleri değerlendirirken query yalnızca hedefleri değerlendirir. Bu işlem daha uzun sürer ve daha fazla bellek kullanır.
  • cquery tarafından sorgu dili yorumlanması, query tarafından kaçınılan belirsizliklere yol açmaktadır. Örneğin, "//foo" iki yapılandırmada mevcutsa cquery "deps(//foo)" hangi yapılandırmayı kullanmalıdır? [config](#config) işlevi bu konuda yardımcı olabilir.
  • Daha yeni bir araç olan cquery, belirli kullanım alanları için desteğe sahip değildir. Ayrıntılar için Bilinen sorunlar bölümüne bakın.

Bilinen sorunlar

cquery'ın "derlediği" tüm hedefler aynı yapılandırmaya sahip olmalıdır.

cquery, sorguları değerlendirmeden önce, derleme işlemlerinin yürütüleceği noktadan hemen önceki bir derlemeyi tetikler. "Oluşturduğu" hedefler varsayılan olarak sorgu ifadesinde görünen tüm etiketlerden seçilir (bu, --universe_scope ile geçersiz kılınabilir). Bu etiketler aynı yapılandırmaya sahip olmalıdır.

Bunlar genellikle üst düzey "hedef" yapılandırmasını paylaşsa da kurallar, gelen kenar geçişleriyle kendi yapılandırmalarını değiştirebilir. cquery bu noktada yetersiz kalıyor.

Geçici çözüm: Mümkünse --universe_scope öğesini daha sıkı bir kapsama ayarlayın. Örneğin:

# 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 için destek sunulmaz.

Deterministik olmayan çıkış.

cquery, önceki komutlardaki derleme grafiğini otomatik olarak silmez ve bu nedenle geçmiş sorgulardaki sonuçları alma eğilimindedir. Örneğin, genquery, tools özelliğinde bir ana makine geçişi gerçekleştirir. Yani, araçlarını ana makine yapılandırmasında yapılandırır.

Bu geçişin kalıcı etkilerini aşağıda görebilirsiniz.

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

Geçici çözüm: Yapılandırılmış hedeflerin yeniden analiz edilmesini zorunlu kılmak için herhangi bir başlangıç seçeneğini değiştirin. Örneğin, derleme komutunuza --test_arg=&lt;whatever&gt; komutunu ekleyin.

Sorun giderme

Yinelenen hedef kalıpları (/...)

Aşağıdakilerle karşılaşırsanız:

$ 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.

Bu, --universe_scope=//foo:app paketi //foo paketini içermesine rağmen //foo paketinin kapsamda olmadığını yanlış bir şekilde belirtir. Bunun nedeni cquery'teki tasarım sınırlamalarıdır. Geçici bir çözüm olarak //foo/... değerini evren kapsamına açıkça dahil edin:

$ bazel cquery --universe_scope=//foo:app,//foo/... "somepath(//foo:app, //foo/...)"

Bu işe yaramazsa (örneğin, //foo/... içindeki bir hedef, seçilen derleme işaretleriyle derlenemediğinden) bir ön işleme sorgusu kullanarak kalıbın sarmalamasını manuel olarak açın:

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