Alet Zincirleri

Sorun bildir Kaynağı göster

Bu sayfada, kural yazarlarının kural mantığını platform tabanlı araç seçiminden ayırmalarına olanak tanıyan araç zinciri çerçevesi açıklanmaktadır. Devam etmeden önce kurallar ve platformlar sayfalarını okumanız önerilir. Bu sayfada araç zincirlerinin neden gerekli olduğu, bunların nasıl tanımlanıp kullanılacağı ve Bazel'ın platform kısıtlamalarına göre nasıl uygun bir araç zinciri seçtiği ele alınmaktadır.

Motivasyon

İlk olarak, araç zincirlerinin çözmek için tasarlandığı probleme göz atalım. "Çubuk" programlama dilini destekleyecek kurallar yazdığınızı varsayalım. bar_binary kuralınız, çalışma alanınızda başka bir hedef olarak oluşturulmuş bir araç olan barc derleyicisini kullanarak *.bar dosyalarını derler. bar_binary hedefleri yazan kullanıcıların derleyiciye bağımlılık belirtmesi gerekmediğinden, bağımlılığı kural tanımına gizli özellik olarak ekleyerek bunu dolaylı bir bağımlılık haline getirirsiniz.

bar_binary = rule(
    implementation = _bar_binary_impl,
    attrs = {
        "srcs": attr.label_list(allow_files = True),
        ...
        "_compiler": attr.label(
            default = "//bar_tools:barc_linux",  # the compiler running on linux
            providers = [BarcInfo],
        ),
    },
)

//bar_tools:barc_linux artık her bar_binary hedefinin bağımlılığı olduğu için herhangi bir bar_binary hedefinden önce oluşturulacak. Bu kurala, diğer herhangi bir özellik gibi kuralın uygulama işleviyle erişilebilir:

BarcInfo = provider(
    doc = "Information about how to invoke the barc compiler.",
    # In the real world, compiler_path and system_lib might hold File objects,
    # but for simplicity they are strings for this example. arch_flags is a list
    # of strings.
    fields = ["compiler_path", "system_lib", "arch_flags"],
)

def _bar_binary_impl(ctx):
    ...
    info = ctx.attr._compiler[BarcInfo]
    command = "%s -l %s %s" % (
        info.compiler_path,
        info.system_lib,
        " ".join(info.arch_flags),
    )
    ...

Buradaki sorun, derleyicinin etiketinin kodunun bar_binary içine gömülmesidir. Ancak, farklı hedeflerin, hangi platform için ve hangi platform üzerinde oluşturulduklarına bağlı olarak farklı derleyicilere ihtiyacı olabilir. Bunlar, sırasıyla hedef platform ve yürütme platformu olarak adlandırılır. Dahası, kuralın yazarı, kullanılabilir tüm araçları ve platformları bilemeyebilir. Bu nedenle, bunları kuralın tanımına gömmek mümkün değildir.

_compiler özelliğini gizli olmayacak şekilde ayarlayarak yükü kullanıcılara aktarmak, ideal olmayan bir çözüm olacaktır. Sonrasında hedefler bir platform veya başka bir platform için ayrı ayrı kodlanabilir.

bar_binary(
    name = "myprog_on_linux",
    srcs = ["mysrc.bar"],
    compiler = "//bar_tools:barc_linux",
)

bar_binary(
    name = "myprog_on_windows",
    srcs = ["mysrc.bar"],
    compiler = "//bar_tools:barc_windows",
)

Bu çözümü geliştirmek için select kullanın ve compiler platforma göre seçin:

config_setting(
    name = "on_linux",
    constraint_values = [
        "@platforms//os:linux",
    ],
)

config_setting(
    name = "on_windows",
    constraint_values = [
        "@platforms//os:windows",
    ],
)

bar_binary(
    name = "myprog",
    srcs = ["mysrc.bar"],
    compiler = select({
        ":on_linux": "//bar_tools:barc_linux",
        ":on_windows": "//bar_tools:barc_windows",
    }),
)

Ancak bu yorucu ve her bar_binary kullanıcısından biraz istemesi gereken bir iştir. Bu stil, çalışma alanı boyunca tutarlı bir şekilde kullanılmazsa tek bir platformda iyi çalışan ancak çok platformlu senaryolara genişletildiğinde başarısız olan derlemeler ortaya çıkar. Ayrıca mevcut kuralları veya hedefleri değiştirmeden yeni platformlar ve derleyiciler için destek ekleme sorununu da ele almaz.

Araç zinciri çerçevesi, bu sorunu fazladan bir dolaylı yol ekleyerek çözer. Esas olarak, kuralınızın hedef ailesinin bazı üyesine (bir araç zinciri türü) soyut bir bağımlılığı olduğunu beyan edersiniz ve Bazel, geçerli platform kısıtlamalarına göre bunu otomatik olarak belirli bir hedefe (araç zinciri) çözer. Kural yazarının da hedef yazarının da kullanılabilir platformlar ve araç zincirleri setinin tamamını bilmesine gerek yoktur.

Araç zincirlerini kullanan kurallar yazma

Araç zinciri çerçevesi kapsamında, kuralların doğrudan araçlara bağlı olması yerine araç zinciri türlerine bağlı olurlar. Araç zinciri türü, farklı platformlarda aynı görevi yerine getiren bir araç sınıfını temsil eden basit bir hedeftir. Örneğin, çubuk derleyiciyi temsil eden bir tür bildirebilirsiniz:

# By convention, toolchain_type targets are named "toolchain_type" and
# distinguished by their package path. So the full path for this would be
# //bar_tools:toolchain_type.
toolchain_type(name = "toolchain_type")

Önceki bölümde yer alan kural tanımı, derleyiciyi özellik olarak almak yerine //bar_tools:toolchain_type araç zincirini kullandığını bildirecek şekilde değiştirilir.

bar_binary = rule(
    implementation = _bar_binary_impl,
    attrs = {
        "srcs": attr.label_list(allow_files = True),
        ...
        # No `_compiler` attribute anymore.
    },
    toolchains = ["//bar_tools:toolchain_type"],
)

Uygulama işlevi artık bu bağımlılığa ctx.attr yerine ctx.toolchains altında erişir ve anahtar olarak araç zinciri türünü kullanır.

def _bar_binary_impl(ctx):
    ...
    info = ctx.toolchains["//bar_tools:toolchain_type"].barcinfo
    # The rest is unchanged.
    command = "%s -l %s %s" % (
        info.compiler_path,
        info.system_lib,
        " ".join(info.arch_flags),
    )
    ...

ctx.toolchains["//bar_tools:toolchain_type"], Bazel'ın araç zinciri bağımlılığını çözdüğü hedefin ToolchainInfo sağlayıcısını döndürür. ToolchainInfo nesnesinin alanları, temel aracın kuralı tarafından ayarlanır. Sonraki bölümde, bu kural bir BarcInfo nesnesini sarmalayan barcinfo alanı olacak şekilde tanımlanır.

Bazel'in araç zincirlerini hedeflere ulaştırma prosedürü aşağıda açıklanmıştır. Aslında yalnızca çözümlenen araç zinciri hedefi, aday araç zincirlerinin tamamı değil, bar_binary hedefinin bağımlılığı haline getirilir.

Zorunlu ve İsteğe Bağlı Araç Zincirleri

Varsayılan olarak, bir kural çıplak etiket (yukarıda gösterildiği gibi) kullanarak araç zinciri türü bağımlılığı ifade ettiğinde (yukarıda gösterildiği gibi) araç zinciri türü zorunlu olarak kabul edilir. Bazel, zorunlu bir araç zinciri türü için eşleşen bir araç zinciri bulamıyorsa (aşağıdaki Araç zinciri çözümü bölümüne bakın) bu bir hatadır ve analiz durdurulur.

Bunun yerine, aşağıdaki gibi isteğe bağlı bir araç zinciri türü bağımlılığı beyan edebilirsiniz:

bar_binary = rule(
    ...
    toolchains = [
        config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = False),
    ],
)

İsteğe bağlı bir araç zinciri türü çözümlenemezse analiz devam eder ve ctx.toolchains["//bar_tools:toolchain_type"] sonucu None olur.

config_common.toolchain_type işlevi varsayılan olarak zorunludur.

Aşağıdaki formlar kullanılabilir:

  • Zorunlu araç zinciri türleri:
    • toolchains = ["//bar_tools:toolchain_type"]
    • toolchains = [config_common.toolchain_type("//bar_tools:toolchain_type")]
    • toolchains = [config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = True)]
  • İsteğe bağlı araç zinciri türleri:
    • toolchains = [config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = False)]
bar_binary = rule(
    ...
    toolchains = [
        "//foo_tools:toolchain_type",
        config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = False),
    ],
)

Aynı kuralda formları da karıştırabilir ve eşleştirebilirsiniz. Bununla birlikte, aynı araç zinciri türü birden çok kez listelenirse en katı sürümü kullanılır. Burada zorunluluk, isteğe bağlı olarak daha katıdır.

Araç zincirlerini kullanan yönleri yazma

Yönlerin kurallarla aynı araç zinciri API'sine erişimi vardır: Gerekli araç zinciri türlerini tanımlayabilir, araç zincirlerine bağlam üzerinden erişebilir ve bunları araç zincirini kullanarak yeni işlemler oluşturmak için kullanabilirsiniz.

bar_aspect = aspect(
    implementation = _bar_aspect_impl,
    attrs = {},
    toolchains = ['//bar_tools:toolchain_type'],
)

def _bar_aspect_impl(target, ctx):
  toolchain = ctx.toolchains['//bar_tools:toolchain_type']
  # Use the toolchain provider like in a rule.
  return []

Araç zincirlerini tanımlama

Belirli bir araç zinciri türüne yönelik araç zincirlerini tanımlamak için üç şeye ihtiyacınız vardır:

  1. Araç veya araç paketinin türünü temsil eden dile özgü kural. Kural olarak, bu kuralın adı "_toolchain" şeklinde sonlandırılır.

    1. Not: \_toolchain kuralı herhangi bir derleme işlemi oluşturamaz. Bunun yerine, diğer kurallardaki yapıları toplayıp araç zincirini kullanan kurala yönlendirir. Bu kural, tüm derleme işlemlerinin oluşturulmasından sorumludur.
  2. Bu kural türünün, farklı platformlar için aracın veya araç paketinin sürümlerini temsil eden çeşitli hedefler.

  3. Araç zinciri çerçevesi tarafından kullanılan meta verileri sağlamak amacıyla bu tür her hedef için genel toolchain kuralının ilişkili bir hedefi. Bu toolchain hedefi, bu araç zinciriyle ilişkilendirilmiş toolchain_type değerini de ifade eder. Bu, belirli bir _toolchain kuralının herhangi bir toolchain_type ile ilişkilendirilebileceği ve yalnızca bu _toolchain kuralını kullanan toolchain örneğinde kuralın bir toolchain_type ile ilişkilendirilebileceği anlamına gelir.

Çalışan örneğimizde bar_toolchain kuralının tanımı aşağıda verilmiştir. Örneğimizde yalnızca bir derleyici vardır, ancak bağlayıcı gibi başka araçlar da onun altında gruplandırılabilir.

def _bar_toolchain_impl(ctx):
    toolchain_info = platform_common.ToolchainInfo(
        barcinfo = BarcInfo(
            compiler_path = ctx.attr.compiler_path,
            system_lib = ctx.attr.system_lib,
            arch_flags = ctx.attr.arch_flags,
        ),
    )
    return [toolchain_info]

bar_toolchain = rule(
    implementation = _bar_toolchain_impl,
    attrs = {
        "compiler_path": attr.string(),
        "system_lib": attr.string(),
        "arch_flags": attr.string_list(),
    },
)

Kural bir ToolchainInfo sağlayıcısı döndürmelidir. Bu sağlayıcı, tüketen kuralının ctx.toolchains ve araç zinciri türünün etiketini kullanarak aldığı nesne haline gelir. ToolchainInfo, struct gibi rastgele alan-değer çiftleri içerebilir. ToolchainInfo öğesine tam olarak hangi alanların ekleneceğiyle ilgili spesifikasyon, araç zinciri türünde açıkça belgelenmelidir. Bu örnekte, değerler yukarıda tanımlanan şemanın yeniden kullanılması için bir BarcInfo nesnesinde sarmalanmış şekilde döndürülür; bu stil, doğrulama ve kodun yeniden kullanımı için yararlı olabilir.

Artık belirli barc derleyicileri için hedefler tanımlayabilirsiniz.

bar_toolchain(
    name = "barc_linux",
    arch_flags = [
        "--arch=Linux",
        "--debug_everything",
    ],
    compiler_path = "/path/to/barc/on/linux",
    system_lib = "/usr/lib/libbarc.so",
)

bar_toolchain(
    name = "barc_windows",
    arch_flags = [
        "--arch=Windows",
        # Different flags, no debug support on windows.
    ],
    compiler_path = "C:\\path\\on\\windows\\barc.exe",
    system_lib = "C:\\path\\on\\windows\\barclib.dll",
)

Son olarak, iki bar_toolchain hedefi için toolchain tanımı oluşturuyorsunuz. Bu tanımlar, dile özgü hedefleri araç zinciri türüne bağlar ve araç zincirinin belirli bir platform için ne zaman uygun olduğunu Bazel'e bildiren kısıtlama bilgilerini sağlar.

toolchain(
    name = "barc_linux_toolchain",
    exec_compatible_with = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
    ],
    target_compatible_with = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
    ],
    toolchain = ":barc_linux",
    toolchain_type = ":toolchain_type",
)

toolchain(
    name = "barc_windows_toolchain",
    exec_compatible_with = [
        "@platforms//os:windows",
        "@platforms//cpu:x86_64",
    ],
    target_compatible_with = [
        "@platforms//os:windows",
        "@platforms//cpu:x86_64",
    ],
    toolchain = ":barc_windows",
    toolchain_type = ":toolchain_type",
)

Yukarıdaki göreli yol söz diziminin kullanılması, bu tanımların tümünün aynı pakette olduğunu gösterir ancak araç zinciri türünün, dile özgü araç zinciri hedeflerinin ve toolchain tanım hedeflerinin hepsinin ayrı paketlerde olmamasının hiçbir nedeni yoktur.

Gerçek hayattan bir örnek için bkz. go_toolchain.

Araç zincirleri ve yapılandırmalar

Kural yazarları için önemli bir soru, bir bar_toolchain hedefi analiz edildiğinde hangi yapılandırmayı gördüğü ve bağımlılıklar için hangi geçişlerin kullanılması gerektiğidir? Yukarıdaki örnekte dize özellikleri kullanılmış olsa da, Bazel deposundaki diğer hedeflere dayalı daha karmaşık bir araç zincirinde ne olur?

Şimdi bar_toolchain öğesinin daha karmaşık bir sürümünü inceleyelim:

def _bar_toolchain_impl(ctx):
    # The implementation is mostly the same as above, so skipping.
    pass

bar_toolchain = rule(
    implementation = _bar_toolchain_impl,
    attrs = {
        "compiler": attr.label(
            executable = True,
            mandatory = True,
            cfg = "exec",
        ),
        "system_lib": attr.label(
            mandatory = True,
            cfg = "target",
        ),
        "arch_flags": attr.string_list(),
    },
)

attr.label kullanımı standart bir kuralla aynıdır ancak cfg parametresinin anlamı biraz farklıdır.

Bir hedeften ("üst öğe" denir) araç zinciri çözümlemesi aracılığıyla bir araç zincirine bağımlılık, "araç zinciri geçişi" adı verilen özel bir yapılandırma geçişi kullanır. Araç zinciri geçişi, yapılandırmayı aynı tutar. Tek fark, yürütme platformunu araç zinciri için üst platformla aynı olmaya zorlamaktır (aksi takdirde, araç zincirinin araç zinciri çözünürlüğü herhangi bir yürütme platformunu seçebilir ve üst platformdakiyle aynı olmaz). Bu, araç zincirinin exec bağımlılıklarının üst öğenin derleme işlemleri için de yürütülebilir olmasına izin verir. Araç zincirinin, cfg = "target" kullanan (veya "target" varsayılan olduğu için cfg belirtmeyen) tüm bağımlılıkları, üst platformla aynı hedef platform için oluşturulur. Bu, araç zinciri kurallarının hem kitaplıkları (yukarıdaki system_lib özelliği) hem de araçları (compiler özelliği) bunlara ihtiyaç duyan derleme kurallarına katkıda bulunmasına olanak tanır. Sistem kitaplıkları nihai yapıya bağlıdır. Bu nedenle, aynı platform için derlenmesi gerekir. Öte yandan derleyici, derleme sırasında çağrılan bir araçtır ve yürütme platformunda çalışabilmelidir.

Araç zincirleriyle kaydolma ve geliştirme

Bu noktada tüm yapı taşları birleştirilir ve sadece araç zincirlerini Bazel'in çözüm prosedürü için kullanılabilir hale getirmeniz gerekir. Bu işlem, araç zincirinin register_toolchains() kullanılarak MODULE.bazel dosyasına kaydedilmesi veya --extra_toolchains işaretini kullanarak araç zinciri etiketlerinin komut satırında iletilmesiyle gerçekleştirilir.

register_toolchains(
    "//bar_tools:barc_linux_toolchain",
    "//bar_tools:barc_windows_toolchain",
    # Target patterns are also permitted, so you could have also written:
    # "//bar_tools:all",
    # or even
    # "//bar_tools/...",
)

Araç zincirlerini kaydetmek için hedef kalıpları kullanılırken her bir araç zincirinin kaydedilme sırası aşağıdaki kurallar tarafından belirlenir:

  • Bir paketin alt paketinde tanımlanan araç zincirleri, paketin kendisinde tanımlanan araç zincirlerinden önce kaydedilir.
  • Araç zincirleri bir pakette, adlarının sözlük sıralamasına göre kaydedilir.

Artık bir araç zinciri türüne bağlı olan bir hedef oluşturduğunuzda, hedef ve yürütme platformlarına göre uygun bir araç zinciri seçilir.

# my_pkg/BUILD

platform(
    name = "my_target_platform",
    constraint_values = [
        "@platforms//os:linux",
    ],
)

bar_binary(
    name = "my_bar_binary",
    ...
)
bazel build //my_pkg:my_bar_binary --platforms=//my_pkg:my_target_platform

Bazel, //my_pkg:my_bar_binary ürününün @platforms//os:linux içeren bir platformla oluşturulduğunu görür ve bu nedenle //bar_tools:toolchain_type referansını //bar_tools:barc_linux_toolchain öğesine çözer. Bu işlem sonucunda //bar_tools:barc_linux oluşturulur, ancak //bar_tools:barc_windows oluşturulmaz.

Araç zinciri çözünürlüğü

Araç zincirlerini kullanan her hedef için Bazel'in araç zinciri çözüm prosedürü, hedefin somut araç zinciri bağımlılıklarını belirler. Prosedürde; gerekli araç zinciri türlerini, hedef platformu, mevcut yürütme platformlarının ve mevcut araç zincirlerinin listesini girin. Çıkışları, her araç zinciri türü için seçilen bir araç zincirinin yanı sıra mevcut hedef için seçili bir yürütme platformu olur.

Kullanılabilir yürütme platformları ve araç zincirleri, MODULE.bazelfiles. Additional execution platforms and toolchains may also be specified on the command line via [--extra_execution_platforms](/reference/command-line-reference#flag--extra_execution_platforms) and [--extra_toolchains'](/reference/command-line-reference#flag--extra_toolchains) içindeki register_execution_platforms ve register_toolchains çağrıları aracılığıyla dış bağımlılık grafiğinden toplanır. Ana makine platformu, otomatik olarak kullanılabilir bir yürütme platformu olarak eklenir. Kullanılabilir platformlar ve araç zincirleri, determinizm için sıralı listeler olarak izlenir ve listedeki ilk öğelere öncelik verilir.

Öncelik sırasına göre sunulan araç zincirleri grubu, --extra_toolchains ve register_toolchains öğelerinden oluşturulur:

  1. --extra_toolchains kullanılarak kaydedilen araç zincirleri önce eklenir. (Bunlar içinde, son araç zinciri en yüksek önceliğe sahiptir.)
  2. Geçişli dış bağımlılık grafiğinde register_toolchains kullanılarak kaydedilen araç zincirleri aşağıdaki sırayla gösterilir: (Bunların içinde, belirtilen ilk araç zinciri en yüksek önceliğe sahiptir.)
    1. Kök modül (çalışma alanı kökündeki MODULE.bazel gibi) tarafından kaydedilen araç zincirleri;
    2. Kullanıcının WORKSPACE dosyasında kayıtlı olan araç zincirleri (bu dosyadan çağrılan tüm makrolar dahil);
    3. Kök olmayan modüller tarafından kaydedilen araç zincirleri (kök modül tarafından belirtilen bağımlılıklar ve bunların bağımlılıkları vb.);
    4. "WORKSPACE son ekine" kayıtlı araç zincirleri; bu öğe yalnızca Bazel kurulumuyla birlikte sunulan belirli yerel kurallar tarafından kullanılır.

NOT: :all, :* ve /... gibi sözde hedefler, sözlüğe göre sıralama kullanan Bazel'in paket yükleme mekanizmasına göre sıralanır.

Çözüm adımları aşağıdaki gibidir.

  1. target_compatible_with veya exec_compatible_with ifadesi, listesindeki her constraint_value için platform constraint_value (açıkça veya varsayılan olarak) da içeriyorsa platform eşleşir.

    Platformda, ifadenin referans vermediği constraint_setting kaynaklı constraint_value varsa bunlar eşleşmeyi etkilemez.

  2. Oluşturulan hedef exec_compatible_with özelliğini (veya kural tanımında exec_compatible_with bağımsız değişkenini belirtiyorsa) kullanılabilir yürütme platformlarının listesi, yürütme kısıtlamalarıyla eşleşmeyenleri kaldıracak şekilde filtrelenir.

  3. Mevcut araç zincirlerinin listesi, mevcut yapılandırmayla eşleşmeyen ve target_settings belirten tüm araç zincirlerini kaldırmak için filtrelenir.

  4. Mevcut her yürütme platformu için her bir araç zinciri türünü, varsa bu yürütme platformu ve hedef platformla uyumlu olan ilk araç zinciriyle ilişkilendirirsiniz.

  5. Araç zinciri türlerinden biriyle uyumlu bir zorunlu araç zinciri bulamayan tüm yürütme platformları dikkate alınmaz. Kalan platformlar arasından ilki, mevcut hedefin yürütme platformu olur ve ilişkili araç zincirleri (varsa) hedefin bağımlılıkları haline gelir.

Seçilen yürütme platformu, hedefin oluşturduğu tüm işlemleri çalıştırmak için kullanılır.

Aynı hedefin aynı derleme içinde birden fazla yapılandırmada (farklı CPU'lar için olduğu gibi) oluşturulabildiği durumlarda çözüm prosedürü, hedefin her sürümüne bağımsız olarak uygulanır.

Kural yürütme gruplarını kullanıyorsa her yürütme grubu araç zinciri çözümünü ayrı olarak gerçekleştirir ve her birinin kendi yürütme platformu ve araç zincirleri vardır.

Hata ayıklama araç zincirleri

Mevcut bir kurala araç zinciri desteği ekliyorsanız --toolchain_resolution_debug=regex işaretini kullanın. Araç zinciri çözümlemesi sırasında işaret, normal ifade değişkeniyle eşleşen araç zinciri türleri veya hedef adları için ayrıntılı çıktı sağlar. Tüm bilgilerin çıktısını almak için .* kullanabilirsiniz. Bazel, çözüm sürecinde kontrol ettiği ve atladığı araç zincirlerinin adlarını üretir.

Hangi cquery bağımlılıklarının araç zinciri çözümünden geldiğini görmek isterseniz cquery --transitions işaretini kullanın:

# Find all direct dependencies of //cc:my_cc_lib. This includes explicitly
# declared dependencies, implicit dependencies, and toolchain dependencies.
$ bazel cquery 'deps(//cc:my_cc_lib, 1)'
//cc:my_cc_lib (96d6638)
@bazel_tools//tools/cpp:toolchain (96d6638)
@bazel_tools//tools/def_parser:def_parser (HOST)
//cc:my_cc_dep (96d6638)
@local_config_platform//:host (96d6638)
@bazel_tools//tools/cpp:toolchain_type (96d6638)
//:default_host_platform (96d6638)
@local_config_cc//:cc-compiler-k8 (HOST)
//cc:my_cc_lib.cc (null)
@bazel_tools//tools/cpp:grep-includes (HOST)

# Which of these are from toolchain resolution?
$ bazel cquery 'deps(//cc:my_cc_lib, 1)' --transitions=lite | grep "toolchain dependency"
  [toolchain dependency]#@local_config_cc//:cc-compiler-k8#HostTransition -> b6df211