Bu sayfada, kural yazarlarının kural mantığını platform tabanlı araç seçiminden ayırmaktadır. Evet kuralları ve platformları okumanız önerilir sayfaları inceleyin. Bu sayfada, araç zincirlerinin neden gerekli olduğu, bunları tanımlayıp kullanmalarını ve Bazel'in bu verilere bağlı olarak platform kısıtlamalarını artırır.
Motivasyon
Öncelikle araç zincirlerinin çözmek için tasarlandığı soruna bakalım. Diyelim ki
"çubuk"u destekleyecek kurallar yazan programlama dili. Size ait bar_binary
kuralı, *.bar
dosyalarını derleyici olan barc
derleyiciyi kullanarak derler. Bu araç
çalışma alanınızda başka bir hedef olarak oluşturulduğundan emin olun. bar_binary
yazan kullanıcılardan beri
hedeflerin derleyiciye bir bağımlılık belirtmesi gerekmez; bunu
örtülü bağımlılığı ifade eder.
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
hedefi için bir bağımlılık. Bu nedenle
herhangi bir bar_binary
hedefinden önce oluşturulur. Kurala göre,
diğer özellikler gibi bir uygulama işlevine de sahip olursunuz:
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, derleyici etiketinin bar_binary
koduna gömülmüş olmasıdır.
farklı hedefler, kullandıkları platforma bağlı olarak farklı derleyicilere ihtiyaç duyabilir
oluşturulmakta olduklarına ve hangi platform üzerinde geliştirildiklerine
hedef platform ve yürütme platformu. Ayrıca kural,
mevcut tüm araçları ve platformları bile bilmediğinden,
bunları kuralın tanımına gömmek mümkün değildir.
İdeal olmayan bir çözüm, bir görevi yerine getirerek birtakım
_compiler
özelliği gizli değil. Bu durumda ayrı ayrı hedefler
koda gömüldüğünden emin olun.
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",
)
compiler
seçmek için select
kullanarak 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 çok yorucu ve her bar_binary
kullanıcısından sormanız gereken biraz fazla bir şey var.
Bu stil çalışma alanı boyunca tutarlı bir şekilde kullanılmazsa
tek bir platformda sorunsuz çalışan ancak
senaryoları inceleyelim. Destek ekleme ve
.
Araç zinciri çerçevesi bu sorunu çözmek için fazladan bir düzey dolaylı da olabilir. Özetle, kuralınızın soyut bir bağımlılığı olduğunu hedef ailesinin (araç zinciri türü) bazı üyelerinde ve Bazel'de buna göre belirli bir hedefe (araç zinciri) otomatik olarak geçerli platform kısıtlamalarına tabidir. Kuralın yazarı da hedef yazarı da değil mevcut platformların ve araç zincirlerinin tamamını bilmeniz gerekir.
Araç zincirleri 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ıdır. Araç zinciri türü, basit bir hedeftir Bu bir dizi, farklı anahtar kelimeler için aynı rolü platformlar. Örneğin, çubuğu temsil eden bir tür tanımlayabilirsiniz. derleyici:
# 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ı,
kod, derleyiciyi bir özellik olarak aldığında,
//bar_tools:toolchain_type
araç zincirini kullanmaya devam edebilirsiniz.
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.toolchains
altından erişiyor
yerine ctx.attr
yerine araç zinciri türünü kullanın.
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"]
şunu döndürür:
ToolchainInfo
sağlayıcı
Bazel'ın araç zinciri bağımlılığını çözdüğü her hedefin bir örneğidir.
ToolchainInfo
nesnesi temel aracın kuralı tarafından ayarlanır; sonraki
bölümünde, bu kural sarmalanan bir barcinfo
alanı olacak şekilde tanımlanır
BarcInfo
nesnesini ifade eder.
Bazel'in araç zincirlerini hedeflere çözme prosedürü açıklanıyor
burada bulabilirsiniz. Çözümlenmiş araç zinciri hedefi aslında
tüm aday alanına değil, bar_binary
hedefine bağımlı hale geldi
araç zincirleri
olarak düşünebilirsiniz.
Zorunlu ve İsteğe Bağlı Araç Zincirleri
Varsayılan olarak, bir kural çıplak etiket kullanarak araç zinciri türü bağımlılığı ifade ettiğinde (yukarıda gösterildiği gibi) araç zinciri türünün zorunlu olduğu kabul edilir. Bazel eşleşen bir araç zinciri bulamıyorsa (bkz. Araç zinciri çözünürlüğünü kullanın) bu bir hatadır ve analiz durdurulur.
Bunun yerine isteğe bağlı bir araç zinciri türü bağımlılığı tanımlamak mümkündür. şöyle olur:
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"]
işlevinin sonucu None
.
config_common.toolchain_type
işlevinin varsayılan olarak ayarlanması 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),
],
)
Ayrıca, aynı kuralda formları karıştırıp eşleştirebilirsiniz. Ancak aynı araç zinciri türü birden çok kez listeleniyorsa en katı olanı alır. daha katı olduğu durumlar için bunu yapabiliriz.
Araç zincirlerini kullanan özellikleri yazma
Boyutların kurallarla aynı araç zinciri API'sine erişimi vardır: Gerekli araç zinciri türlerini, bağlam yoluyla araç zincirlerine erişme ve bunları kullanarak yeni işlemleri nasıl yapacağınızla ilgilidir.
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 araç zinciri tanımlamak üzere üç şeye ihtiyacınız vardır:
Aracın veya araç paketinin türünü temsil eden dile özgü bir kural. Ölçüt bu kural adının sonunda "_toolchain" bulunur.
- Not:
\_toolchain
kuralı derleme işlemi oluşturamaz. Bunun yerine, diğer kurallardan eserleri toplayıp ilkesini ele alalım. Bu kural, tüm sorumluluklarınızı derleme işlemleri için de geçerlidir.
- Not:
Bu kural türündeki birkaç hedef (araç veya aracın sürümlerini temsil eder) yardımcı olan araçlardır.
Bu tür her bir hedef için genel
toolchain
kuralıyla birlikte araç zinciri çerçevesi tarafından kullanılan meta verileri sağlar. Butoolchain
hedef aynı zamanda bu araç zinciriyle ilişkilendirilmiştoolchain_type
anlamına gelir. Bu, belirli bir_toolchain
kuralının herhangi bir reklamverenletoolchain_type
ve bu yalnızcatoolchain
toolchain_type
ile ilişkili olduğunu belirten bu_toolchain
kuralını uygulayın.
Çalışan örneğimizde, bar_toolchain
kuralının tanımını aşağıda bulabilirsiniz. Bizim
örnekte yalnızca bir derleyici bulunur, ancak bağlayıcı gibi diğer araçlar da
altında gruplandırılır.
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ı döndürmelidir. Bu sağlayıcı,
alıcı kuralı, ctx.toolchains
ve
araç zinciri türünü seçin. ToolchainInfo
(struct
gibi) rastgele alan değeri içerebilir
çiftler. ToolchainInfo
öğesine tam olarak hangi alanların ekleneceğine ilişkin spesifikasyon
araç zinciri türünde açıkça belgelenmelidir. Bu örnekte, değerler
yukarıda tanımlanan şemayı yeniden kullanmak için bir BarcInfo
nesnesi içine sarmalanmış daima; 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şturursunuz.
Bu tanımlar, dile özgü hedefleri araç zinciri türüne bağlar ve
araç zincirinin ne zaman çalışacağını Bazel'a bildiren kısıtlama bilgilerini
bir şablon görevi görür.
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ımı, bu tanımların tümünün
eder. Ancak bunun için araç zinciri türünün, dile özgü
araç zinciri hedefleri ve toolchain
tanım hedeflerinin hepsi ayrı olamaz
paketlerini ekleyebilirsiniz.
go_toolchain
sayfasını inceleyin.
örneği inceleyelim.
Araç zincirleri ve yapılandırmalar
Kural yazarları için önemli bir soru şudur: bar_toolchain
hedefi
hangi yapılandırmayı gördüğü ve hangi geçişlerin
bağımlılıklar için nasıl kullanılmalıdır? Yukarıdaki örnekte dize özellikleri kullanılmıştır, ancak
diğer hedeflere dayalı daha karmaşık bir araç zincirine
hangi yöntemi kullanır?
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.
Araç zinciri aracılığıyla bir hedeften ("üst öğe" denir) araç zincirine bağımlılık
Çözünürlüğü "araç zinciri" adı verilen özel bir yapılandırma geçişi kullanır
geçiş" gibi bir ifade kullanabilirsiniz. Araç zinciri geçişi, aşağıdaki hariç yapılandırma işlemleri için aynı kalır:
yürütme platformunu, araç zinciri için
(aksi takdirde, araç zincirinin araç zinciri çözünürlüğünü
yürütme platformundakilerle aynı olmayabilir). Bu
araç zincirinin tüm exec
bağımlılıklarının
üst öğe derleme işlemlerini içerebilir. Araç zincirinin cfg =
"target"
kullanan (veya "target" varsayılan olduğu için cfg
belirtmeyen) bağımlılıklarından herhangi biri
ana platformla aynı hedef platform için oluşturulmuş olmalıdır. Bu şekilde, araç zinciri kurallarının
hem kitaplıklara (yukarıdaki system_lib
özelliği) hem de araçlara (
compiler
özelliği) ekleyin. Sistem kitaplıkları
ve nihai eserle bağlantılı olduğu için aynı yapı için
platformunda çağrılan derleyici ise derleme sırasında çağrılan bir araçtır ve
yürütme platformunda çalıştırılabilir.
Araç zincirleriyle kaydolma ve derleme
Bu noktada tüm yapı taşları birleştirilir ve sadece birkaç küçük yapı içinde
Bazel'in çözümleme prosedüründe kullanılabilecek araç zincirleridir. Bu,
kullanarak bir MODULE.bazel
dosyasına veya araç zincirini
register_toolchains()
veya araç zincirlerinin komuttaki etiketler
satırında --extra_toolchains
işaretini kullanabilirsiniz.
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ırken, her birinin kaydedilmesi aşağıdaki kurallara göre belirlenir:
- Bir paketin alt paketinde tanımlanan araç zincirleri, araç zincirleri bulunur.
- Paket içinde araç zincirleri; terimler sözlüğü sırasına göre adlarını ekleyebilirsiniz.
Artık bir araç zinciri türüne bağlı olan bir hedef oluşturduğunuzda araç zinciri, hedefe ve yürütme platformlarına göre 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çeriyor ve bu nedenle
//bar_tools:barc_linux_toolchain
için //bar_tools:toolchain_type
referansı.
Bu işlem //bar_tools:barc_linux
uzantısıyla sonuçlanacaktır
//bar_tools:barc_windows
.
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ür bir dizi gerekli araç zinciri türünü, hedef platformun, dönüşüm hunisinin mevcut yürütme platformlarını ve kullanılabilir araç zincirlerinin listesini içerir. Çıktıları her bir araç zinciri türü için seçilmiş bir araç zinciri ve aynı zamanda seçili yürütme platformu belirleyin.
Mevcut yürütme platformları ve araç zincirleri,
dış bağımlılık grafiği
register_execution_platforms
ve
register_toolchains
arama şurada:
MODULE.bazel
dosya.
Ayrıca,
komut satırı üzerinden
--extra_execution_platforms
ve
--extra_toolchains
.
Ana makine platformu da otomatik olarak kullanılabilir bir yürütme platformu arasına eklenir.
Kullanılabilir platformlar ve araç zincirleri, deterministikçi göstermek amacıyla sıralı listeler olarak takip edilir.
listenin önceki öğelerine verilen tercihle.
Mevcut araç zincirleri grubu, öncelik sırasına göre şuradan oluşturulur:
--extra_toolchains
ve register_toolchains
:
--extra_toolchains
kullanılarak kaydedilen araç zincirleri önce eklenir. ( son araç zinciri en yüksek önceliğe sahiptir.)- Geçişli harici modda
register_toolchains
kullanılarak kaydedilen araç zincirleri bağımlılık grafiğine aşağıdaki sıralamayla ulaşabilirsiniz: (Bunların içinde, birinci belirtilen araç zincirinin en yüksek önceliğe sahip olduğunu unutmayın.)- Kök modül tarafından kaydedilen araç zincirleri (ör.
MODULE.bazel
workspace root); - Kullanıcının
WORKSPACE
dosyasına kayıtlı araç zincirleri. buradan çağrılan makrolar; - Kök olmayan modüller tarafından kaydedilen araç zincirleri ( kök modül, bunların bağımlılıkları vb.).
- "WORKSPACE son ekinde" kayıtlı araç zincirleri; yalnızca tarafından kullanılan Bazel yüklemesiyle paket halinde sunulan belirli yerel kurallar.
- Kök modül tarafından kaydedilen araç zincirleri (ör.
NOT: :all
, :*
ve gibi sözde hedefler
/...
, Bazel'in paketine göre sıralanıyor
kullanılan yükleme mekanizmasıdır.
Çözüm adımları aşağıda açıklanmıştır.
target_compatible_with
veyaexec_compatible_with
ifade şununla eşleşir: a platform, listesindeki herconstraint_value
için aynı zamanda buconstraint_value
(açıkça veya varsayılan olarak).Platformda
constraint_setting
yerineconstraint_value
varsa tarafından referansta bulunulması durumunda eşleşmeler etkilenmez.Oluşturulmakta olan hedef
exec_compatible_with
özelliği (veya kural tanımıexec_compatible_with
bağımsız değişken), Mevcut yürütme platformlarının listesi filtrelenerek kaldırılarak yürütülme kısıtlamalarıyla eşleşmeyen tüm anahtar kelimeler.Mevcut araç zincirleri listesi, tüm araç zincirlerini kaldıracak şekilde filtrelenir Mevcut yapılandırmayla eşleşmeyen
target_settings
belirtiliyor.Mevcut her yürütme platformu için her araç zinciri türünü bununla uyumlu ilk araç zinciri (varsa), ve hedef platforma göre hazırlanır.
Uyumlu bir zorunlu araç zinciri bulamayan yürütme platformları devre dışı bırakıldığını görebilirsiniz. Diğer platformlar arasından ilki mevcut hedefin yürütme platformu olur ve ilişkilendirilmiş araç zincirleri (varsa) hedefin bağımlılıkları haline gelir.
Seçilen yürütme platformu, hedefin gerçekleştireceği tüm işlemleri çalıştırmak için oluşturuyor.
Aynı hedefin birden fazla yapılandırmada oluşturulabildiği (örneğin, aynı derlemede) çözümleme prosedürü uygulanırsa her sürümü için ayrı ayrı düzenleyebilirsiniz.
Kural yürütme grupları kullanıyorsa her yürütme grubu, araç zinciri çözümlemesini ayrı ayrı gerçekleştirir ve her grubun kendi yürütmesi vardır birçok farklı araç bulunur.
Hata ayıklama araç zincirleri
Mevcut bir kurala araç zinciri desteği ekliyorsanız
--toolchain_resolution_debug=regex
işareti. Araç zinciri çözümlemesi 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. Siz
.*
öğesini kullanarak tüm bilgilerin çıkışını sağlayabilir. Bazel, oluşturulan araç zincirlerinin adlarını çıkarır
kontroller ve atlamalar yaşar.
Hangi cquery
bağımlılıklarının araç zincirinden geldiğini görmek istiyorsanız
cquery
çözünürlüğü için --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