Alet Zincirleri

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

Bu sayfada, kural yazarlarının kural mantıkları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, nasıl tanımlanıp kullanılacağı ve Bazel'in platform kısıtlamalarına göre uygun bir araç zincirini nasıl seçeceği açıklanmaktadır.

Motivasyon

Öncelikle, araç zincirlerinin çözmek için tasarlandığı soruna bakalım. "bar" programlama dilini desteklemek için kurallar yazdığınızı varsayalım. bar_binary Kuralınız, çalışma alanınızda başka bir hedef olarak oluşturulan bir araç olan barc derleyicisini kullanarak *.bar dosyalarını derler. bar_binary Hedefler yazan kullanıcıların derleyiciye bağımlılık belirtmesi gerekmediğinden, kural tanımına özel bir özellik olarak ekleyerek bunu örtülü 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ığıdır. Bu nedenle, herhangi bir bar_binary hedefinden önce oluşturulur. Bu özelliğe, kuralın uygulama işlevi tarafından diğer tüm özellikler gibi 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 bar_binary içine sabit kodlanmış olmasıdır. Ancak farklı hedefler, oluşturuldukları ve oluşturuldukları platforma bağlı olarak farklı derleyiciler gerektirebilir. Bunlara sırasıyla hedef platform ve yürütme platformu adı verilir. Ayrıca, kuralı oluşturan kişi mevcut tüm araçları ve platformları bilmeyebilir. Bu nedenle, bunları kuralın tanımına sabit kodlamak mümkün değildir.

İdeal olmayan bir çözüm, _compiler özelliğini herkese açık hale getirerek yükü kullanıcılara yüklemek olacaktır. Ardından, tek tek hedefler bir platform veya başka bir platform için oluşturulacak şekilde sabit 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",
)

select kullanarak compiler seçerek bu çözümü iyileştirebilirsiniz platforma göre:

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 işlem sıkıcıdır ve her bir bar_binary kullanıcısından bunu yapmasını istemek biraz fazla olur. Bu stil, çalışma alanında tutarlı bir şekilde kullanılmazsa tek bir platformda sorunsuz çalışan ancak çok platformlu senaryolara genişletildiğinde başarısız olan derlemelere yol açar. Ayrıca, mevcut kuralları veya hedefleri değiştirmeden yeni platformlar ve derleyiciler için destek ekleme sorununu da çözmez.

Araç zinciri çerçevesi, ek bir yönlendirme katmanı ekleyerek bu sorunu çözer. Temel olarak, kuralınızın bir hedef ailesinin (bir araç zinciri türü) bazı üyelerine soyut bir bağımlılığı olduğunu beyan edersiniz ve Bazel, bunu geçerli platform kısıtlamalarına göre belirli bir hedefe (bir araç zinciri) otomatik olarak çözümler. Ne kuralı oluşturan ne de hedef yazar, mevcut platformların ve araç zincirlerinin tamamını bilmek zorunda değildir.

Araç zincirlerini kullanan kurallar yazma

Araç zinciri çerçevesinde, kurallar doğrudan araçlara bağlı olmak yerine araç zinciri türlerine bağlıdır. Araç zinciri türü, farklı platformlarda aynı rolü üstlenen 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ümdeki kural tanımı, derleyiciyi özellik olarak almak yerine bir //bar_tools:toolchain_type araç zinciri kullandığını belirtecek ş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 anahtar olarak araç zinciri türünü kullanarak ctx.attr yerine ctx.toolchains altında erişiyor.

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'in araç zinciri bağımlılığını çözdüğü hedefteki ToolchainInfo sağlayıcıyı döndürür. ToolchainInfo nesnesinin alanları, temel alınan aracın kuralıyla ayarlanır. Sonraki bölümde bu kural, BarcInfo nesnesini sarmalayan bir barcinfo alanı olacak şekilde tanımlanır.

Bazel'in araç zincirlerini hedeflere çözme prosedürü aşağıda açıklanmıştır. bar_binary hedefinin bağımlılığı aslında yalnızca çözümlenmiş araç zinciri hedefidir. Aday araç zincirlerinin tamamı bağımlılık değildir.

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

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

Bunun yerine, aşağıdaki gibi bir isteğe bağlı 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ümlenemediğinde 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ı karıştırıp eşleştirebilirsiniz. Ancak aynı araç zinciri türü birden fazla kez listelenirse en katı sürüm kullanılır. Burada zorunlu, isteğe bağlıdan daha katıdır.

Araç zincirlerini kullanan yazma yönleri

Aspect'ler, kurallarla aynı araç zinciri API'sine erişebilir: Gerekli araç zinciri türlerini tanımlayabilir, bağlam üzerinden araç zincirlerine erişebilir ve bunları kullanarak araç zinciriyle yeni işlemler oluşturabilirsiniz.

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ü için bazı araç zincirlerini tanımlamak üzere üç şeye ihtiyacınız vardır:

  1. Araç türünü veya araç paketini temsil eden dile özgü bir kural. Bu kuralın adı, kurala göre "_toolchain" ile bitirilir.

    1. Not: \_toolchain kuralı, derleme işlemleri oluşturamaz. Bunun yerine, diğer kurallardan yapıtlar toplar ve bunları araç zincirini kullanan kurala iletir. Bu kural, tüm derleme işlemlerini oluşturmaktan sorumludur.
  2. Bu kural türünün, farklı platformlar için aracın veya araç paketinin sürümlerini temsil eden çeşitli hedefleri.

  3. Her hedef için, araç zinciri çerçevesi tarafından kullanılan meta verileri sağlamak üzere genel toolchain kuralının ilişkili bir hedefi. Bu toolchain hedefi, bu araç zinciriyle ilişkili toolchain_type için de geçerlidir. Bu, belirli bir _toolchain kuralının herhangi bir toolchain_type ile ilişkilendirilebileceği ve kuralın yalnızca bu _toolchain kuralını kullanan bir toolchain örneğinde toolchain_type ile ilişkilendirileceği anlamına gelir.

Çalışan örneğimiz için bar_toolchain kuralının tanımı aşağıda verilmiştir. Örneğimizde yalnızca bir derleyici var ancak bağlayıcı gibi diğer araçlar da bunun 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, ToolchainInfo sağlayıcısını döndürmelidir. Bu sağlayıcı, tüketen kuralın ctx.toolchains ve araç zinciri türünün etiketi kullanılarak aldığı nesne olur. ToolchainInfo, struct gibi, rastgele alan-değer çiftleri içerebilir. ToolchainInfo öğesine hangi alanların eklendiği, araç zinciri türünde açıkça belgelenmelidir. Bu örnekte, yukarıda tanımlanan şemayı yeniden kullanmak için değerler BarcInfo nesnesi içinde döndürülür. Bu stil, doğrulama ve kodun yeniden kullanılması 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, toolchainiki hedef için tanımlar bar_toolchain oluşturursunuz. Bu tanımlar, dile özgü hedefleri araç zinciri türüne bağlar ve Bazel'e araç zincirinin belirli bir platform için ne zaman uygun olduğunu söyleyen 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 hepsinin aynı pakette olduğunu gösterir ancak araç zinciri türü, dile özgü araç zinciri hedefleri ve toolchain tanım hedeflerinin ayrı paketlerde olmaması için bir neden yoktur.

Gerçek hayattan bir örnek için go_toolchain bölümüne bakın.

Araç zincirleri ve yapılandırmalar

Kural yazarları için önemli bir soru şudur: Bir bar_toolchain hedefi analiz edildiğinde hangi yapılandırmayı görür ve bağımlılıklar için hangi geçişler kullanılmalıdır? Yukarıdaki örnekte dize özellikleri kullanılıyor ancak Bazel deposundaki diğer hedeflere bağlı olan daha karmaşık bir araç zincirinde ne olur?

Şimdi bar_toolchain'nın daha karmaşık bir sürümüne bakalım:

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 kuraldakiyle aynıdır ancak cfg parametresinin anlamı biraz farklıdır.

Bir hedeften ("üst" olarak adlandırılır) araç zinciri çözümü aracılığıyla araç zincirine olan 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. Ancak, yürütme platformunun araç zinciri ve üst öğe için aynı olması zorunlu tutulur (aksi takdirde, araç zinciri için araç zinciri çözümü herhangi bir yürütme platformunu seçebilir ve üst öğe ile aynı olmayabilir). Bu, araç zincirinin exec bağımlılıklarının üst öğenin derleme işlemleri için de yürütülebilir olmasını sağlar. cfg = "target" kullanan (veya "target" varsayılan değer olduğundan cfg belirtmeyen) araç zincirinin bağımlılıkları, üst öğeyle aynı hedef platform için oluşturulur. Bu, araç zinciri kurallarının, ihtiyaç duydukları derleme kurallarına hem kitaplıklar (yukarıdaki system_lib özelliği) hem de araçlar (compiler özelliği) sağlamasına olanak tanır. Sistem kitaplıkları nihai yapıtla bağlantılı olduğundan aynı platform için oluşturulması gerekir. Derleyici ise derleme sırasında çağrılan bir araçtır ve yürütme platformunda çalışabilmesi gerekir.

Araç zincirleriyle kaydetme ve derleme

Bu noktada tüm yapı taşları bir araya getirilmiştir ve yalnızca araç zincirlerini Bazel'in çözümleme prosedürüne sunmanız gerekir. Bu işlem, araç zincirini MODULE.bazel dosyasında register_toolchains() kullanarak veya komut satırında --extra_toolchains işaretini kullanarak araç zincirlerinin etiketlerini ileterek kaydederek yapılır.

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, tek tek araç zincirlerinin kaydedilme sırası aşağıdaki kurallara göre belirlenir:

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

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

# 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 öğesinin @platforms//os:linux içeren bir platformda oluşturulduğunu görür ve bu nedenle //bar_tools:toolchain_type referansını //bar_tools:barc_linux_toolchain olarak çözer. Bu işlem, //bar_tools:barc_linux öğesini oluşturur ancak //bar_tools:barc_windows öğesini oluşturmaz.

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

Araç zincirlerini kullanan her hedef için Bazel'in araç zinciri çözümleme prosedürü, hedefin somut araç zinciri bağımlılıklarını belirler. Prosedür, giriş olarak gerekli araç zinciri türleri kümesini, hedef platformu, kullanılabilir yürütme platformlarının listesini ve kullanılabilir araç zincirlerinin listesini alır. Çıkışları, her araç zinciri türü için seçilen bir araç zinciri ve mevcut hedef için seçilen bir yürütme platformudur.

Kullanılabilir yürütme platformları ve araç zincirleri, MODULE.bazel dosyalarındaki register_execution_platforms ve register_toolchains çağrıları aracılığıyla harici bağımlılık grafiğinden toplanır. Ek yürütme platformları ve araç zincirleri, komut satırında --extra_execution_platforms ve --extra_toolchains ile de belirtilebilir. Ana makine platformu, kullanılabilir bir yürütme platformu olarak otomatik olarak dahil edilir. Kullanılabilir platformlar ve araç zincirleri, determinizm için sıralı listeler olarak izlenir. Listede daha önce yer alan öğelere öncelik verilir.

Öncelik sırasına göre kullanılabilen araç zincirleri kümesi, --extra_toolchains ve register_toolchains kullanılarak oluşturulur:

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

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

Çözüm adımları şu şekildedir.

  1. Bir target_compatible_with veya exec_compatible_with maddesi, listedeki her constraint_value için platformda da aynı constraint_value (açıkça veya varsayılan olarak) varsa platformla eşleşir.

    Platformda, madde tarafından referans verilmeyen constraint_setting kaynaklı constraint_value varsa bunlar eşleşmeyi etkilemez.

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

  3. Kullanılabilir araç zincirleri listesi, geçerli yapılandırmayla eşleşmeyen target_settings belirten araç zincirlerini kaldıracak şekilde filtrelenir.

  4. Kullanılabilir her yürütme platformu için her araç zinciri türünü, bu yürütme platformu ve hedef platformla uyumlu olan ilk kullanılabilir araç zinciriyle (varsa) ilişkilendirirsiniz.

  5. Araç zinciri türlerinden biri için uyumlu bir zorunlu araç zinciri bulamayan tüm yürütme platformları elenir. Kalan platformlardan ilki, mevcut hedefin yürütme platformu olur ve ilişkili araç zincirleri (varsa) hedefin bağımlılıkları haline gelir.

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

Aynı hedefin aynı derleme içinde birden fazla yapılandırmada (ör. farklı CPU'lar için) oluşturulabildiği durumlarda çözümleme 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ümlemesini ayrı ayrı gerçekleştirir ve her birinin kendi yürütme platformu ve araç zincirleri vardır.

Araç zincirlerinde hata ayıklama

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

Örneğin, doğrudan //my:target tarafından oluşturulan tüm işlemler için araç zinciri seçiminde hata ayıklamak istiyorsanız:

$ bazel build //my:all --toolchain_resolution_debug=//my:target

Tüm derleme hedeflerindeki tüm işlemler için araç zinciri seçiminde hata ayıklamak üzere:

$ bazel build //my:all --toolchain_resolution_debug=.*

Hangi cquery bağımlılıklarının araç zinciri çözümlemesinden geldiğini görmek istiyorsanız cquery'nın --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