Yapılandırılabilir Sorgu (cquery)

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

Bunu, Bazel'in bu efektleri entegre eden analiz aşamasının sonuçlarını izleyerek yapar. Buna karşın query, seçenekler değerlendirilmeden önce Bazel'ın yükleme aşamasının sonuçlarını gözden geçirir.

Ö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 bir 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ığı için derleme işlemleri veya [test_suite](/versions/6.2.0/reference/be/general#test_suite) kurallarına erişim gibi yapılar hakkında analize sahip değildir. Politika için bkz. [aquery](/versions/6.2.0/docs/aquery).

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(...), hedef üzerinde çalıştırılacak işlevdir. cquery, query işlevlerinin çoğunu ve birkaç yenisini 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 Nasıl Yapılır? 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 adresine bakın.

Yapılandırmalar

Satır:

//tree:ash (9f87702)

//tree:ash ürününün 9f87702 kimliğine sahip 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 bir 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ı (HOST) özel kimliğini kullanır. Genellikle srcs içinde bulunanlar gibi, oluşturulmayan kaynak dosyalar (null) özel kimliğini kullanır (çünkü bu dosyaların yapılandırılması gerekmez).

9f87702, tam kimliğin önekidir. Bunun nedeni, tam kimliklerin uzun ve takip edilmesi zor olan SHA-256 karmaları olmasıdır. cquery, Git kısa karmalarına benzer şekilde tam kimliğin tüm geçerli ön eklerini anlar. Kimliklerin tamamını görmek için $ bazel config komutunu çalıştırın.

Hedef kalıp değerlendirmesi

//foo, cquery için query ile farklı bir anlama geliyor. Bunun nedeni, cquery ürününün yapılandırılmış hedefleri değerlendirmesi ve derleme grafiğinde //foo için birden fazla yapılandırılmış sürüm olabilmesidir.

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

Bu, sorgu ifadeleri için query ile olduğundan daha ince sonuçlar verir. Örneğin, aşağıdakiler 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 sorgulanacağını kesin olarak tanımlamak istiyorsanız config işlevini kullanın.

Hedef kalıpları hakkında daha fazla bilgi için query ürününün hedef kalıbı belgelerine bakın.

İşlevler

query tarafından desteklenen işlev grubundan cquery, visible, siblings, buildfiles ve tests hariç tümünü destekler.

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

config

expr ::= config(expr, word)

config operatörü, ikinci bağımsız değişkenin belirttiği ilk bağımsız değişken ve yapılandırmayla gösterilen 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 karması şeklindedir. Karmalar, $ bazel config veya önceki cquery çıktısı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 bulunabilen sonuçlar döndürülür. Belirtilen yapılandırmada hiçbir sonuç bulunamazsa sorgu başarısız olur.

Seçenekler

Derleme seçenekleri

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

Sorgu seçeneklerini kullanma

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

Genellikle, yapılandırılmış hedeflerin bağımlılıkları geçişlerden geçer. Bu durum, yapılandırmalarının bağımlılardan 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. Böylece aşağıdaki sorgular, aşağıdaki çıkışları oluşturur:

Sorgu Oluşturulan Hedef Çı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 bunun yerine, sorgu ifadesinde belirtilen tüm hedefler oluşturulur. Oluşturulan hedeflerin geçişli kapanması sorgunun evreni olarak kullanılır. Her iki durumda da, oluşturulacak hedefler en üst düzeyde oluşturulabilir (yani üst düzey seçeneklerle uyumlu olmalıdır). cquery, bu üst düzey hedeflerin geçişli olarak kapatılmasıyla sonuç döndürür.

Bir sorgu ifadesinde tüm hedefleri üst düzeyde oluşturmak mümkün olsa da bunu yapmamak faydalı olabilir. Örneğin, --universe_scope özelliğini açık bir şekilde ayarlamak, ilgilenmediğiniz yapılandırmalarda birden fazla kez hedef oluşturulmasını engelleyebilir. Arama, bir hedefin hangi yapılandırma sürümünü aradığınızı 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) ifadesinden daha karmaşıksa bu işareti ayarlamanız gerekir.

--implicit_deps (boole, varsayılan=Doğru)

Bu işaretin yanlış değerine ayarlanması, BUILD dosyasında açık bir şekilde ayarlanmayan ve bunun yerine Bazel tarafından başka bir yere ayarlanan tüm sonuçları filtreler. Çözümlenmiş araç zincirlerini filtrelemek de buna dahildir.

--tool_deps (boole, varsayılan=Doğru)

Bu işaretin Yanlış değerine ayarlanması, sorgulanan hedeften gelen yolun hedef yapılandırma ile hedeflenmeyen yapılandırmalar arasında bir geçişle karşılaştığı tüm yapılandırılmış hedefleri filtreler. Sorgulanan hedef, hedef yapılandırmadaysa --notool_deps ayarı yalnızca hedef yapılandırmada da bulunan hedefleri döndürür. Sorgulanan hedef, hedeflenmeyen bir yapılandırmadaysa --notool_deps ayarı hedef olmayan yapılandırmalarda da yalnızca hedefleri döndürür. Bu ayar genellikle çözümlenmiş araç zincirlerinin filtrelenmesini etkilemez.

--include_aspects (boole, varsayılan=Doğru)

Yönler, bir derlemeye ek bağımlılıklar ekleyebilir. Varsayılan olarak cquery, sorgulanabilir grafiği büyüterek daha fazla bellek kullanılmasına yol açtığından yönleri takip etmez. Ama bunları takip etmek daha doğru sonuçlar üretir.

Büyük sorguların bellek üzerindeki etkisi hakkında endişelenmiyorsanız, Marketplace'te bu işareti varsayılan olarak etkinleştirin.

Yönler devre dışı olarak sorgulanırsanız hedef Y hedefi oluştururken X hedefi başarısız olur, ancak cquery somepath(Y, X) ve cquery deps(Y) | grep 'X' hiçbir sonuç döndürmez, çünkü bağımlılık bir özellik üzerinden gerçekleşir.

Çıkış biçimleri

Varsayılan olarak sorgu çıktıları, bağımlılık sırasına göre etiket ve yapılandırma çiftleri listesiyle sonuçlanı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 hedeflerden farklı yapılandırmalarda, üst düzey hedeflerin altında hedefler oluşturmak için kullanılır.

Örneğin bir hedef, tools özelliğindeki tüm bağımlılıklara ana makine yapılandırmasına geçiş uygulayabilir. Bunlara özellik geçişleri denir. Kurallar da kendi yapılandırmalarına geçişler uygulayabilir. Bu geçişler, kural sınıfı geçişleri olarak bilinir. Bu çıktı biçimi, söz konusu geçişlerin türü ve derleme seçenekleri üzerindeki etkisi gibi, geçişler hakkında bilgi verir.

Bu çıkış biçimi, varsayılan olarak NONE değerine ayarlanan --transitions işareti tarafından tetiklenir. FULL veya LITE moduna ayarlanabilir. FULL modu, kural sınıfı geçişleri ve özellik geçişleri hakkında bilgiler verir. Bu bilgilere, geçişten önceki ve sonraki seçeneklerin ayrıntılı farkları da dahildir. LITE modu, seçenek farkı olmadan aynı bilgileri verir.

Protokol mesajı çıkışı

--output=proto

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

CqueryResult, sorgu sonuçlarını içeren üst düzey mesajdır. Mesajda ConfiguredTarget mesaj ve Configuration mesaj listesi bulunur. Her ConfiguredTarget, değeri karşılık gelen Configuration mesajındaki id alanının değerine eşit olan bir configuration_id içerir.

--[no]proto:include_configurations

Varsayılan olarak sorgu sonuçları, yapılandırılmış her hedefin bir parçası olarak yapılandırma bilgilerini döndürür. Bu bilgileri atlamak ve sorgunun proto çıktısı gibi biçimlendirilmiş bir proto çıkışı almak istiyorsanız bu işareti "false" (yanlış) değerine ayarlayın.

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

Grafik çıktısı

--output=graph

Bu seçenek, Graphviz uyumlu .dot dosyası olarak çıktı oluşturur. Ayrıntılar için query uygulamasını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 bir hedef tarafından oluşturulan çıkış dosyalarının listesini yazdırır. Çıkış yalnızca --output_groups işaretiyle belirlenen istenen çıkış gruplarında tanıtılan dosyaları içerir. Kaynak dosyalar içerir.

Starlark'ı kullanarak çıktı biçimini tanımlama

--output=starlark

Bu çıkış biçimi, sorgu sonucundaki her yapılandırılmış hedef için bir Starlark işlevi çağırır ve çağrının döndürdüğü değeri yazdırır. --starlark:file işareti, tek bir parametreyle format adlı bir işlevi tanımlayan Starlark dosyasının konumunu belirtir (target). Bu işlev, sorgu sonucundaki her bir Hedef için çağrılır. Alternatif olarak, kolaylık olması açısından --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

Starlark sorgusunun ortamı BUILD veya .bzl dosyasından farklıdır. Tüm temel Starlark yerleşik sabitlerini ve işlevlerini, aşağıda açıklanan sorguya özel birkaç tanesini içerir ancak (örneğin) glob, native veya rule ifadelerini içermez ve yükleme ifadelerini desteklemez.

build_options(target)

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

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

sağlayıcılar(hedef)

providers(target), anahtarları sağlayıcı adları (örneğin, "DefaultInfo") ve değerleri Starlark değerleri olan bir eşleme döndürür. Değerleri yasal Starlark değerleri olmayan sağlayıcılar bu eşlemeden çıkarılır.

Örnekler

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

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

//bar içindeki ve alt paketlerindeki kural hedefleri tarafından oluşturulan tüm dosyaları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 hatırlatı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ının listesini yazdır.

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

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

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

Tam olarak bir çıktıyla her bir hedefin etiketini yazdırın. Bu örnekte, bir dosyada tanımlanmış 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

Tümüyle Python 3 olan her bir hedefin etiketini yazdırın. Bu örnekte, bir dosyada tanımlanmış 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 çıkarı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 sorgu karşılaştırması

cquery ve query birbirini tamamlar ve farklı nişlerde başarılı olur. Sizin için hangisinin doğru olduğuna karar verirken 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 bilemez. Bu nedenle, tüm dalları dahil ederek yaklaşık olarak belirtilenden daha yüksek olur.
  • cquery metriğinin hassasiyeti için, query ile karşılaştırıldığında daha fazla grafik oluşturulması gerekiyor. Spesifik olarak, cquery yapılandırılmış hedefleri, query ise yalnızca hedefleri değerlendirir. Bu işlem daha fazla zaman alır ve daha fazla bellek kullanır.
  • cquery'ın sorgu dilini yorumlaması, query tarafından kaçınılan belirsizliğe yol açar. Örneğin, "//foo" iki yapılandırmada mevcutsa cquery "deps(//foo)" hangisini kullanmalıdır? [config](#config) işlevi bu konuda size yardımcı olabilir.
  • cquery, daha yeni bir araç olduğundan belirli kullanım alanları için destek sunmamaktadır. Ayrıntılar için Bilinen sorunlar sayfasına bakın.

Bilinen sorunlar

cquery tarafından "oluşturduğu" tüm hedefler aynı yapılandırmaya sahip olmalıdır.

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

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

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

Belirleyici olmayan çıkış.

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

Bu geçişin uzun vadeli 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şlatma seçeneğini değiştirin. Örneğin, derleme komutunuza --test_arg=&lt;whatever&gt; ekleyin.

Sorun giderme

Yinelemeli 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, yanlış bir şekilde //foo paketinin --universe_scope=//foo:app içerdiği halde kapsam dahilinde olmadığı anlamına geliyor. Bunun nedeni, cquery içindeki tasarım sınırlamalarıdır. Geçici bir çözüm olarak, //foo/... öğesini evren kapsamına açıkça ekleyin:

$ 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 bayraklarıyla oluşturamadığı için) ön işleme sorgusu kullanarak kalıbın kendi bileşen paketlerine manuel olarak sarmasını 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 "+" -))"