Yapılandırılabilir Sorgu (cquery)

Sorun bildir Kaynağı görüntüle Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

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

Bu işlem, Bazel'in bu etkileri entegre eden analiz aşamasının sonuçları üzerinde çalıştırılarak gerçekleştirilir. query ise seçenekler değerlendirilmeden önce Bazel'in yükleme aşamasının sonuçları üzerinde çalışır.

Ö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 (9f87702) benzersiz tanımlayıcısını içerir.

cquery, yapılandırılmış hedef grafiği üzerinden çalıştığı için derleme işlemleri gibi yapılar hakkında bilgi sahibi değildir ve yapılandırılmış hedefler olmadıkları için test_suite kurallarına erişemez. İlki için aquery başlıklı makaleyi inceleyin.

Temel söz dizimi

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

bazel cquery "function(//target)"

"function(//target)" sorgu ifadesi şunlardan oluşur:

  • function(...), hedefte çalıştırılacak işlevdir. cquery, query'in işlevlerinin çoğunu ve birkaç yeni işlevi destekler.
  • //target, işleve aktarılan 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 kılavuzu'na bakın.

cquery, yükleme ve analiz aşamalarından geçmek için bir hedef gerektirir. Aksi belirtilmediği sürece cquery, sorgu ifadesinde listelenen hedefleri ayrıştırır. Üst düzey derleme hedeflerinin bağımlılıklarını sorgulama hakkında bilgi edinmek 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ğu anlamına gelir. Çoğu hedef için bu, yapılandırmayı tanımlayan derleme seçeneği değerlerinin opak karma sürümüdür.

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

$ bazel config 9f87702

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 değerlerine benzer şekilde, tam bir kimliğin geçerli herhangi bir önekini anlar. Tam kimlikleri görmek için $ bazel config komutunu çalıştırın.

Hedef kalıp değerlendirmesi

//foo, cquery için query'den farklı bir anlama sahiptir. Bunun nedeni, cquery yapılandırılmış hedefleri değerlendirir ve derleme grafiğinde //foo'nin 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ış hedef için değerlendirilir. Çıkış deterministiktir ancak cquery, çekirdek sorgu sıralama sözleşmesinin ötesinde sıralama garantisi vermez.

Bu, sorgu ifadeleri için query ile karşılaştırıldığında daha ince sonuçlar üretir. Örneğin, aşağıdakiler birden fazla sonuç üretebilir:

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

Hangi örneğin sorgulanacağını tam olarak belirtmek istiyorsanız config işlevini kullanın.

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

İşlevler

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

cquery ayrıca aşağıdaki yeni işlevleri de sunar:

yapılandırma

expr ::= config(expr, word)

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

İkinci bağımsız değişken için geçerli değerler null veya özel yapılandırma karmasıdır. Karma değerler, $ bazel config veya önceki bir cquery çıkışından alınabilir.

Örnekler:

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

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

İlk bağımsız değişkenin tüm sonuçları belirtilen yapılandırmada bulunamazsa yalnızca bulunanlar 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çenekler kümesini devralır.

cquery seçeneklerini kullanma

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

Yapılandırılan hedeflerin bağımlılıkları genellikle geçişler yaşar. Bu durum, yapılandırmalarının bağımlı oldukları hedeflerden farklı olmasına neden olur. Bu işaret, bir hedefi başka bir hedefin bağımlılığı veya geçişli bağımlılığı olarak oluşturulmuş gibi sorgulamanıza olanak tanır. Örneğin:

# 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, araçlarını exec configuration içinde yapılandırır. Bu nedenle, aşağıdaki sorgular aşağıdaki çıkışları üretir:

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(execconfig)

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

Tüm hedefleri en üst düzeydeki bir sorgu ifadesinde oluşturmak mümkün olsa bile bunu yapmamak faydalı olabilir. Örneğin, --universe_scope değerini açıkça ayarlamak, önemsemediğiniz yapılandırmalarda hedeflerin birden fazla kez oluşturulmasını önleyebilir. Ayrıca, aradığınız hedef yapılandırma sürümünü belirtmenize de yardımcı olabilir. Sorgu ifadeniz deps(//foo) değerinden daha karmaşıksa bu işareti ayarlamanız gerekir.

--implicit_deps (boolean, default=True)

Bu işareti false olarak ayarlamak, BUILD dosyasında açıkça ayarlanmamış ve bunun yerine Bazel tarafından başka bir yerde ayarlanmış tüm sonuçları filtreler. Çözülmüş araç zincirlerini filtreleme de buna dahildir.

--tool_deps (boolean, default=True)

Bu işareti false olarak ayarlamak, sorgulanan hedeften kendilerine giden yolun hedef yapılandırması ile hedef olmayan yapılandırmalar arasında bir geçişi geçtiği tüm yapılandırılmış hedefleri filtreler. Sorgulanan hedef, hedef yapılandırmasında yer alıyorsa --notool_deps ayarı yalnızca hedef yapılandırmasında da yer alan hedefleri döndürür. Sorgulanan hedef bir hedef dışı yapılandırmadaysa --notool_deps ayarı yalnızca hedef dışı yapılandırmalardaki hedefleri döndürür. Bu ayar genellikle çözümlenmiş araç zincirlerinin filtrelenmesini etkilemez.

--include_aspects (boolean, default=True)

Aspects tarafından eklenen bağımlılıkları dahil edin.

Bu işaret devre dışı bırakılırsa cquery somepath(X, Y) ve cquery deps(X) | grep 'Y', X yalnızca bir yön aracılığıyla Y'ye bağlıysa Y'yi atlar.

Çı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 listede verir. 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ındaki hedefleri üst düzey hedeflerden farklı yapılandırmalarda oluşturmak için kullanılır.

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

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

Protokol mesajı çıkışı

--output=proto

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

CqueryResult, cquery sonuçlarını içeren en üst düzeydeki mesajdır. ConfiguredTarget mesajlarının ve Configuration mesajlarının listesini içerir. Her ConfiguredTarget, değeri ilgili Configuration mesajındaki id alanının değerine eşit olan bir configuration_id içerir.

--[no]proto:include_configurations

Varsayılan olarak, cquery sonuçları yapılandırma bilgilerini her bir yapılandırılmış hedef kapsamında döndürür. Bu bilgileri atlamak ve sorgunun proto çıkışıyla aynı şekilde biçimlendirilmiş bir proto çıkışı almak istiyorsanız bu işareti false olarak ayarlayın.

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

Grafik çıkışı

--output=graph

Bu seçenek, Graphviz ile uyumlu bir .dot dosyası olarak çıktı oluşturur. Ayrıntılar için query'nın grafik çıkışı belgelerine bakın. cquery, --graph:node_limit ve --graph:factored'ı da destekler.

Çıkış dosyaları

--output=files

Bu seçenek, sorguyla eşleşen her hedef tarafından üretilen çıkış dosyalarının listesini, bazel build çağrısının sonunda yazdırılan listeye benzer şekilde yazdırır. Çıkış, --output_groups işaretiyle belirlenen, istenen çıkış gruplarında reklamı yapılan dosyaları içerir. Kaynak dosyalar dahil edilir.

Bu çıkış biçimi tarafından verilen tüm yollar, bazel info execution_root aracılığıyla elde edilebilen execroot'a göre belirlenir. bazel-out kolaylık sembolik bağlantısı varsa ana depodaki dosya yolları da çalışma alanı dizinine göre çözümlenir.

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

--output=starlark

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

"cquery" Starlark lehçesi

cquery Starlark ortamı, BUILD veya .bzl dosyasından farklıdır. Bu, tüm temel Starlark yerleşik sabitlerini ve işlevlerini, ayrıca aşağıda açıklanan birkaç cquery'ye özgü olanı içerir ancak (örneğin) glob, native veya rule'i içermez ve yükleme ifadelerini desteklemez.

build_options(target)

build_options(target), anahtarları derleme seçeneği tanımlayıcıları olan (bkz. Yapılandırmalar) ve değerleri Starlark değerleri olan bir harita döndürür. Değerleri yasal Starlark değerleri olmayan derleme seçenekleri bu haritadan çıkarılır.

Hedef bir giriş dosyasıysa build_options(target), giriş dosyası hedeflerinin yapılandırması boş olduğundan None değerini döndürür.

providers(target)

providers(target), anahtarları sağlayıcıların adları (örneğin, "DefaultInfo"), değerleri ise Starlark değerleri olan bir harita döndürür. Değerleri yasal Starlark değerleri olmayan sağlayıcılar bu haritaya dahil edilmez.

Ö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 providers(target)['DefaultInfo'].files.to_list()])"

//bar ve alt paketlerinde kural 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 providers(target)['DefaultInfo'].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]"

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

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

--javacopt oluşturulurken //foo 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(providers(target)["DefaultInfo"].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

Kesinlikle Python 3 olan her hedefin etiketini yazdırın. 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 karşılaştırması

cquery ve query birbirini tamamlar ve farklı alanlarda öne çıkar. Hangisinin sizin için doğru olduğuna karar vermek için aşağıdakileri göz önünde bulundurun:

  • cquery, oluşturduğunuz grafiği tam olarak modellemek için belirli select() dalları izler. query, derlemenin hangi dalı seçeceğini bilmediği için tüm dalları dahil ederek fazla tahmin yapar.
  • cquery'nın hassasiyeti, query'ye kıyasla grafiğin daha fazla bölümünün 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 fazla zaman alır ve daha fazla bellek kullanır.
  • cquery'nın sorgu dilini yorumlaması, query'ın kaçındığı belirsizliğe yol açıyor. Örneğin, "//foo" iki yapılandırmada varsa cquery "deps(//foo)" hangisini kullanmalıdır? Bu konuda config işlevinden yararlanabilirsiniz.

Belirlenimci olmayan çıkış

cquery, önceki komutlardan oluşturma grafiğini otomatik olarak silmez. Bu nedenle, geçmiş sorgulardan sonuç alma olasılığı yüksektir.

Örneğin, genrule, tools özelliğinde bir yürütme geçişi uygular. Yani araçlarını yürütme yapılandırmasında yapılandırır.

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

$ cat > foo/BUILD <<

Bu, değerlendirmeye çalıştığınız şeye bağlı olarak istenen bir davranış olabilir veya olmayabilir.

Bunu devre dışı bırakmak için yeni bir analiz grafiği elde etmek üzere cquery komutunuzdan önce blaze clean komutunu çalıştırın.

Sorun giderme

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

Aşağıdaki sorunlarla 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, //foo paketinin kapsamda olmadığını yanlış bir şekilde öneriyor ancak --universe_scope=//foo:app paketi kapsamda. Bu durum, cquery'daki tasarım sınırlamalarından kaynaklanmaktadır. Geçici çözüm olarak, //foo/... öğesini 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 bazı hedefler seçilen derleme işaretleriyle derlenemediği için) ön işleme sorgusuyla kalıbı manuel olarak bileşen paketlerine 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 "+" -))"