Kural, Bazel'in girişlerde gerçekleştirdiği ve bir dizi çıkış üreten bir dizi işlem tanımlar. Bu çıkışlara, kuralın uygulama işlevi tarafından döndürülen sağlayıcılarda referans verilir. Örneğin, bir C++ ikili kuralı şunları yapabilir:
- Bir dizi
.cpp
kaynak dosyası (giriş) alın. - Kaynak dosyalarda
g++
komutunu çalıştırın (işlem). - Yürütülebilir çıktıyı ve diğer dosyaları içeren
DefaultInfo
sağlayıcısını iade edin kullanılabilir hale getirmektir. CcInfo
sağlayıcısını, ve bağımlılıklarını konuşacağız.
Bazel açısından bakıldığında g++
ve standart C++ kitaplıkları da
ekleyin. Kural yazarı olarak, yalnızca bir kurala kullanıcı tarafından sağlanan girişleri değil, aynı zamanda işlemleri yürütmek için gereken tüm araçları ve kitaplıkları da dikkate almanız gerekir.
Herhangi bir kural oluşturmadan veya değiştirmeden önce Bazel'in geliştirme aşamalarına göz atın. Üç noktayı anlamanız önemlidir, aşamalarından (yükleme, analiz ve yürütme) oluşur. Kurallar ile makrolar arasındaki farkı anlamak için makrolar hakkında bilgi edinmeniz de faydalı olacaktır. Başlamak için önce Kurallar Eğitimi'ni inceleyin. Ardından, bu sayfayı referans olarak kullanın.
Bazel'in kendisinde birkaç kural oluşturulmuştur. Bu yerel kurallar, örneğin
cc_library
ve java_binary
, belirli diller için temel destek sağlar.
Kendi kurallarınızı tanımlayarak Bazel'in doğal olarak desteklemediği diller ve araçlar için benzer destek ekleyebilirsiniz.
Bazel,
Starlark'ın dili. Bu kurallar .bzl
dosyalarına yazılır ve doğrudan BUILD
dosyalarından yüklenebilir.
Kendi kuralınızı tanımlarken hangi özellikleri destekleyeceğine ve çıkışlarını nasıl oluşturacağına siz karar verirsiniz.
Kuralın implementation
işlevi, analiz aşaması sırasındaki tam davranışını tanımlar. Bu işlev herhangi bir harici komut çalıştırmaz. Bunun yerine, bu araçtan yararlanmak için işlemleri
sonraki aşamalarda devreye girerek kuralın çıktılarını
gerekir.
Kural oluşturma
Bir .bzl
dosyasında yeni bir kural tanımlamak için rule işlevini kullanın
kuralına ekleyin ve sonucu genel bir değişkende depolayın. rule
çağrısı, özellikleri ve uygulama işlevini belirtir:
example_library = rule(
implementation = _example_library_impl,
attrs = {
"deps": attr.label_list(),
...
},
)
Bu, example_library
adlı bir kural türünü tanımlar.
rule
çağrısı, kuralın
executable çıkış (executable=True
ile) veya özel olarak
yürütülebilir bir test (test=True
ile). İkincisi ise kural bir test kuralı ise
ve kuralın adı _test
ile bitmelidir.
Hedef örneği oluşturma
Kurallar BUILD
dosyalarında yüklenebilir ve çağrılabilir:
load('//some/pkg:rules.bzl', 'example_library')
example_library(
name = "example_target",
deps = [":another_target"],
...
)
Bir oluşturma kuralına yapılan her çağrı değer döndürmez ancak bir hedef tanımlama yan etkisine sahiptir. Buna, kuralın tetiklenmesi denir. Bu, Hedefin özellikleri için yeni hedef ve değerler girin.
Kurallar, Starlark işlevlerinden çağrılabilir ve .bzl
dosyalarına yüklenebilir.
Kuralları çağıran Starlark işlevleri Starlark makroları olarak adlandırılır.
Starlark makroları nihayetinde BUILD
dosyalarından çağrılmalıdır ve yalnızca BUILD
dosyalarının hedefleri örneklemek için değerlendirildiği yükleme aşamasında çağrılabilir.
Özellikler
Özellik, bir kural bağımsız değişkenidir. Özellikler, bir hedefin uygulanması için belirli değerler sağlayabilir veya diğer hedeflere atıfta bulunarak bağımlılık grafiği oluşturabilir.
srcs
veya deps
gibi kurala özgü özellikler, özellik adlarından şemalara (attr
modülü kullanılarak oluşturulur) bir eşleme geçirilerek rule
'in attrs
parametresine aktarılarak tanımlanır.
Şunlar gibi ortak özellikler
name
ve visibility
, tüm kurallara dolaylı olarak eklenir. Ek özellikler özellikle yürütülebilir ve test kurallarına dolaylı olarak eklenir. Bir kurala dolaylı olarak eklenen özellikler, attrs
parametresine iletilen sözlüğe dahil edilemez.
Bağımlılık özellikleri
Kaynak kodunu işleyen kurallar genellikle çeşitli bağımlılıkları işlemek için aşağıdaki özellikleri tanımlar:
srcs
, hedefin işlemleri tarafından işlenen kaynak dosyaları belirtir. Özellik şeması genellikle, kuralın işlediği kaynak dosya türü için hangi dosya uzantılarının beklendiğini belirtir. Başlık dosyası içeren diller için kurallar genellikle bir hedef ve tüketicileri tarafından işlenen üstbilgiler için ayrı birhdrs
özelliği belirtir.deps
, bir hedef için kod bağımlılıklarını belirtir. Özellik şeması Bu bağımlıların hangi sağlayıcıları sağlaması gerektiğini belirtin. (Örneğin,cc_library
,CcInfo
sağlar.)data
, bir hedefe bağlı olan tüm yürütülebilir dosyalara çalışma zamanında kullanıma sunulacak dosyaları belirtir. Bu sayede, istediğiniz dosyaları belirtebilirsiniz.
example_library = rule(
implementation = _example_library_impl,
attrs = {
"srcs": attr.label_list(allow_files = [".example"]),
"hdrs": attr.label_list(allow_files = [".header"]),
"deps": attr.label_list(providers = [ExampleInfo]),
"data": attr.label_list(allow_files = True),
...
},
)
Bunlar bağımlılık özelliklerine örnektir. Belirttiği herhangi bir özellik:
giriş etiketi (
attr.label_list
,
attr.label
veya
attr.label_keyed_string_dict
)
belirli bir türdeki bağımlılıkları belirtir
arasında bir hedef ile etiketleri (veya ilgili
Label
nesne) söz konusu özellikte listelenir.
tanımlanmıştır. Bu etiketlerin depolama alanı ve muhtemelen yolu, tanımlanan hedefe göre çözülür.
example_library(
name = "my_target",
deps = [":other_target"],
)
example_library(
name = "other_target",
...
)
Bu örnekte other_target
, my_target
'un bir bağımlısıdır ve bu nedenle önce other_target
analiz edilir. Hedeflerin bağımlılık grafiğinde döngü varsa hata oluşur.
Gizli özellikler ve gizli bağımlılıklar
Varsayılan değere sahip bir bağımlılık özelliği dolaylı bağımlılık oluşturur. Google
kullanıcının aramadığı veya almadığı hedef grafiğin bir parçası olduğu için,
BUILD
dosyasında belirtin. Kullanıcılar çoğu zaman kuralın kullandığı aracı belirtmek istemediğinden, kural ile araç (derleme zamanı bağımlılığı, derleyici gibi) arasındaki ilişkiyi sabit kodlamak için örtülü bağımlılıklar kullanışlıdır. Kuralın uygulama işlevinde bu, diğer bağımlılıklarla aynı şekilde ele alınır.
Kullanıcının bu değeri geçersiz kılmasına izin vermeden örtülü bir bağımlılık sağlamak istiyorsanız özelliği, alt çizgiyle (_
) başlayan bir adla gizli yapabilirsiniz. Gizli özelliklerde varsayılan değerler olmalıdır. Özel özellikleri genellikle yalnızca gizli bağımlılıklarda kullanmak mantıklıdır.
example_library = rule(
implementation = _example_library_impl,
attrs = {
...
"_compiler": attr.label(
default = Label("//tools:example_compiler"),
allow_single_file = True,
executable = True,
cfg = "exec",
),
},
)
Bu örnekte, example_library
türündeki her hedefin
şu derleyicide bağımlılık: //tools:example_compiler
. Bu, kullanıcı etiketini giriş olarak iletmemiş olsa bile example_library
'ün uygulama işlevinin derleyiciyi çağıran işlemler oluşturmasına olanak tanır. Başlangıç
_compiler
gizli bir özelliktir. Bu özelliğe uyulması gerekir: ctx.attr._compiler
bu kuralın tüm hedeflerinde her zaman //tools:example_compiler
değerini gösterir
türü. Alternatif olarak, özelliği alt çizgi olmadan compiler
olarak adlandırabilir ve varsayılan değeri koruyabilirsiniz. Bu, kullanıcıların gerekirse farklı bir derleyici kullanmalarına olanak tanır ancak derleyicinin etiketi hakkında bilgi sahibi olmalarını gerektirmez.
Örtük bağımlılıklar genellikle kural uygulamasıyla aynı depoda bulunan araçlar için kullanılır. Araç yürütme platformuna veya farklı bir depoya kuralının söz konusu aracı bir araç zincirinden edinmesi gerekir.
Çıkış özellikleri
Çıkış özellikleri, örneğin attr.output
ve
attr.output_list
ise bir çıkış dosyası bildirin.
anlamına gelir. Bu özellikler, bağımlılık özelliklerinden iki şekilde farklıdır:
- Tanımlanan hedeflere başvurmak yerine çıkış dosyası hedeflerini tanımlarlar olduğunu anlayabilir.
- Çıkış dosyası hedefleri, şunun yerine örneklenen kural hedefine dayanır: tam tersi de geçerlidir.
Çıkış özellikleri genellikle yalnızca bir kuralın, hedef ada dayandırılamayan kullanıcı tanımlı adlarla çıkış oluşturması gerektiğinde kullanılır. Bir kuralın bir çıkış özelliği varsa kural genellikle out
veya outs
olarak adlandırılır.
Çıkış özellikleri, önceden bildirilmiş çıkışlar oluşturmanın tercih edilen yoludur. Bu çıkışlara özel olarak bağımlı olunabilir veya komut satırında istenebilir.
Uygulama işlevi
Her kural için bir implementation
işlevi gerekir. Bu işlevler
yalnızca analiz aşamasında olması ve
yükleme aşamasında oluşturulan hedeflerin grafik
eylemlerin belirlenmesine yardımcı olur. Dolayısıyla,
uygulama işlevleri dosya okuyamaz veya yazamaz.
Kural uygulama işlevleri genellikle özeldir (başında alt çizgi bulunan bir adla adlandırılır). Kurallarıyla aynı şekilde adlandırılırlar ancak sonlarına _impl
eklenir.
Uygulama işlevleri tam olarak bir parametre alır:
kural bağlamı, geleneksel olarak ctx
olarak adlandırılır. Sağlayıcıların listesini döndürürler.
Hedefler
Bağımlılıklar, analiz sırasında Target
nesneleri olarak temsil edilir. Bu nesneler, hedefin uygulama işlevi yürütüldüğünde oluşturulan sağlayıcıları içerir.
ctx.attr
her bir kullanıcının adına karşılık gelen alanlar içeriyor
Her bir doğrudan temsil eden Target
nesneyi içeren bağımlılık özelliği
bu özellik üzerinden gelen
bağımlılığı ifade eder. label_list
özellikleri için bu, Targets
öğelerinin bir listesidir. label
özellikleri için bu, tek bir Target
veya None
değeridir.
Bir hedefin uygulama işlevi, sağlayıcı nesnelerinin bir listesini döndürür:
return [ExampleInfo(headers = depset(...))]
Bunlara dizin gösterimi ([]
) kullanılarak erişilebilir. Sağlayıcı türü şu şekildedir:
kullanabilirsiniz. Bunlar, Starlark'ta tanımlanan özel sağlayıcılar veya
Starlark olarak kullanılabilen yerel kural sağlayıcıları
kullanabilirsiniz.
Örneğin, bir kural hdrs
özelliği aracılığıyla üstbilgi dosyalarını alır ve bunları hedefin ve tüketicilerinin derleme işlemlerine sağlarsa bunları aşağıdaki gibi toplayabilir:
def _example_library_impl(ctx):
...
transitive_headers = [hdr[ExampleInfo].headers for hdr in ctx.attr.hdrs]
Hedefin uygulama işlevinden sağlayıcı nesneleri listesi yerine struct
döndürüldüğü eski stil için:
return struct(example_info = struct(headers = depset(...)))
Sağlayıcılar, Target
nesnesinin ilgili alanından alınabilir:
transitive_headers = [hdr.example_info.headers for hdr in ctx.attr.hdrs]
Bu stilin kullanılması önerilmez ve kurallar bu stilde taşınmamalıdır.
Dosyalar
Dosyalar File
nesneleriyle temsil edilir. Bazel, analiz aşamasında dosya G/Ç işlemi gerçekleştirmediğinden bu nesneler, dosya içeriğini doğrudan okumak veya yazmak için kullanılamaz. Bunun yerine, işlem grafiğinin parçalarını oluşturmak için işlem yayınlayan işlevlere (ctx.actions
bölümüne bakın) iletilir.
File
, bir kaynak dosya veya oluşturulmuş bir dosya olabilir. Oluşturulan her dosya
tam olarak bir işlemin sonucu olmalıdır. Kaynak dosyalar şunun çıktısı olamaz:
herhangi bir işlem.
Her bir bağımlılık özelliği için, karşılık gelen
ctx.files
, tüm varsayılan çıkışların listesini içerir
bağımlılıklarını görebilirsiniz:
def _example_library_impl(ctx):
...
headers = depset(ctx.files.hdrs, transitive=transitive_headers)
srcs = ctx.files.srcs
...
ctx.file
, şunlar için tek bir File
veya None
içerir:
özellikleri allow_single_file=True
olarak ayarlanmış bağımlılık özellikleri.
ctx.executable
, ctx.file
ile aynı şekilde davranır ancak yalnızca
özellikleri executable=True
olarak ayarlanmış bağımlılık özelliklerine ilişkin alanları içerir.
Çıktıları beyan etme
Analiz aşamasında, bir kuralın uygulama işlevi çıkışlar oluşturabilir.
Yükleme aşamasında tüm etiketlerin bilinmesi gerektiğinden, bu ek etiketler
çıkışların etiketi yok. Çıkışlar için File
nesne aşağıdakileri kullanarak oluşturulabilir:
ctx.actions.declare_file
ve
ctx.actions.declare_directory
. Çıktıların adları genellikle hedefin adına göre belirlenir (ctx.label.name
):
def _example_library_impl(ctx):
...
output_file = ctx.actions.declare_file(ctx.label.name + ".output")
...
Çıkış özellikleri için oluşturulanlar gibi önceden bildirilmiş çıkışlar için ctx.outputs
'nin ilgili alanlarından File
nesneleri alınabilir.
İşlemler
Eylemde, kontrol grubu için bir dizi girdiden bir dizi çıkışın nasıl oluşturulacağını örnek: "hello.c'de gcc'yi çalıştır ve hello.o'yu al". Bir eylem oluşturulduğunda Bazel komutu hemen çalıştırmaz. Projeyi bir bağımlılık grafiğine kaydeder, çünkü bir eylem, bir başka işlemin sonucuna bağlı olabilir. Örneğin, C'de, bağlayıcı, derleyiciden sonra çağrılmalıdır.
İşlem oluşturan genel amaçlı işlevler ctx.actions
içinde tanımlanır:
- Yürütülebilir bir dosyayı çalıştırmak için
ctx.actions.run
. ctx.actions.run_shell
, kabuk komutu çalıştırmak içinctx.actions.write
: Dosyaya dize yazmak için.ctx.actions.expand_template
, - şablondan dosya oluşturabilirsiniz.
ctx.actions.args
, verimli bir şekilde kullanılabilir.
argümanları biriktirir. Yürütme zamanına kadar depsetlerin düzleştirilmesini önler:
def _example_library_impl(ctx):
...
transitive_headers = [dep[ExampleInfo].headers for dep in ctx.attr.deps]
headers = depset(ctx.files.hdrs, transitive=transitive_headers)
srcs = ctx.files.srcs
inputs = depset(srcs, transitive=[headers])
output_file = ctx.actions.declare_file(ctx.label.name + ".output")
args = ctx.actions.args()
args.add_joined("-h", headers, join_with=",")
args.add_joined("-s", srcs, join_with=",")
args.add("-o", output_file)
ctx.actions.run(
mnemonic = "ExampleCompile",
executable = ctx.executable._compiler,
arguments = [args],
inputs = inputs,
outputs = [output_file],
)
...
İşlemler, giriş dosyalarının bir listesini veya depset'ini alır ve çıkış dosyalarının (boş olmayan) bir listesini oluşturur. Giriş ve çıkış dosyaları grubu, analiz aşamasından geçti. Bağımlılıklardan gelen sağlayıcılar da dahil olmak üzere özelliklerin değerine bağlı olabilir ancak yürütmenin sonucuna bağlı olamaz. Örneğin, işleminiz sıkıştırılmış dosya açma komutunu çalıştırıyorsa hangi dosyaların şişirilmesini beklediğinizi belirtmelidir (sıkıştırmayı açmadan önce). Dahili olarak değişken sayıda dosya oluşturan işlemler, bu dosyaları tek bir dosyaya (ör. zip, tar veya başka bir arşiv biçimi) sarmalayabilir.
İşlemlerde tüm girişler listelenmelidir. Kullanılmayan girişlerin girilmesi ancak verimsizdir.
İşlemler tüm çıkışlarını oluşturmalıdır. Başka dosyalar yazabilirler ama Çıktılarda olmayan hiçbir şey tüketicilere sunulmayacaktır. Tanımlanan tüm çıkışlar bir işlem tarafından yazılmalıdır.
Eylemler yalın işlevlerle karşılaştırılabilir: Yalnızca giriş yapmalı ve bilgisayar bilgilerine, kullanıcı adı, saat ve ağ veya G/Ç cihazları (okuma girişleri ve yazma çıkışları hariç) Bu önemlidir. Çünkü çıktı, önbelleğe alınıp yeniden kullanılır.
Bağımlılıklar Bazel tarafından çözülür. Bazel, hangi işlemlerin yürütüleceğine karar verir. Bağımlılık grafiğinde döngü varsa bu bir hatadır. Bir işlemin oluşturulması, işlemin yürütüleceğini garanti etmez. Bu, işlemin çıktılarının derleme için gerekli olup olmadığına bağlıdır.
Sağlayıcılar
Sağlayıcılar, bir kuralın kendisine bağlı diğer kurallara gösterdiği bilgi parçalarıdır. Bu veriler arasında çıkış dosyaları, kitaplıklar, bir aracın komut satırında iletilecek parametreler veya hedefin tüketicilerinin bilmesi gereken başka herhangi bir şey bulunabilir.
Bir kuralın uygulama işlevi yalnızca örneklendirilmiş hedefin doğrudan bağımlılıklarındaki sağlayıcıları okuyabildiğinden, kuralların hedefin tüketicileri tarafından bilinmesi gereken tüm bilgileri, genellikle bir depset
içinde toplayarak hedefin bağımlılıklarından iletmesi gerekir.
Bir hedefin sağlayıcıları, tarafından döndürülen Provider
nesnelerin listesi ile belirtilir
işlevi görür.
Eski uygulama işlevleri,
uygulama işlevi struct
sağlayıcı nesneleridir. Bu stilin kullanılması önerilmez ve kurallar bu stilde taşınmamalıdır.
Varsayılan çıkışlar
Bir hedefin varsayılan çıkışları, aşağıdaki durumlarda varsayılan olarak istenen çıkışlardır:
komut satırında derleme için hedef istenir. Örneğin,
java_library
hedefi //pkg:foo
için varsayılan çıkış olarak foo.jar
kullanılıyor.
bazel build //pkg:foo
komutu tarafından oluşturulur.
Varsayılan çıkışlar şu parametrenin files
parametresiyle belirtilir:
DefaultInfo
:
def _example_library_impl(ctx):
...
return [
DefaultInfo(files = depset([output_file]), ...),
...
]
DefaultInfo
, bir kural uygulaması veya files
tarafından döndürülmezse
parametresi belirtilmemiş, DefaultInfo.files
varsayılan olarak tümü
önceden bildirilmiş çıkışlar (genellikle çıkış
özellikleri).
İşlem gerçekleştiren kurallar, bu çıktıların doğrudan kullanılması beklenmese bile varsayılan çıktılar sağlamalıdır. Grafikte bulunmayan işlemler istenen çıkışlar kısaltılır. Bir çıktı yalnızca hedefin tüketicileri tarafından kullanılıyorsa hedef ayrı olarak oluşturulduğunda bu işlemler gerçekleştirilmez. Yalnızca başarısız hedefi yeniden oluşturmak hatayı yeniden oluşturmayacağından bu durum, hata ayıklamayı daha zor hale getirir.
Çalışma dosyaları
Çalıştırma dosyaları, bir hedef tarafından çalışma zamanında kullanılan bir dosya kümesidir. süre) ekleyebilirsiniz. Bazel, yürütme aşamasında çalışma dosyalarına işaret eden sembolik bağlantılar içeren bir dizin ağacı oluşturur. Bu aşama ortamına ekleyebilirsiniz.
Çalıştırma dosyaları, kural oluşturma sırasında manuel olarak eklenebilir.
runfiles
nesneleri, kural bağlamındaki runfiles
yöntemi tarafından ctx.runfiles
oluşturulabilir ve DefaultInfo
'deki runfiles
parametresine iletilebilir. Yürütülebilir çıktısı:
executable rules (yürütülebilir kurallar), çalıştırma dosyalarına dolaylı olarak eklenir.
Bazı kurallar, genellikle
data
; çıkışları
bir hedef runfiles. Runfile'ler, data
'ten ve genellikle srcs
(ilişkili data
'ye sahip filegroup
hedefler içerebilir) ve deps
'tan da birleştirilmelidir.
def _example_library_impl(ctx):
...
runfiles = ctx.runfiles(files = ctx.files.data)
transitive_runfiles = []
for runfiles_attr in (
ctx.attr.srcs,
ctx.attr.hdrs,
ctx.attr.deps,
ctx.attr.data,
):
for target in runfiles_attr:
transitive_runfiles.append(target[DefaultInfo].default_runfiles)
runfiles = runfiles.merge_all(transitive_runfiles)
return [
DefaultInfo(..., runfiles = runfiles),
...
]
Özel sağlayıcılar
Sağlayıcılar, provider
kullanılarak tanımlanabilir.
işlevini kullanın:
ExampleInfo = provider(
"Info needed to compile/link Example code.",
fields={
"headers": "depset of header Files from transitive dependencies.",
"files_to_link": "depset of Files from compilation.",
})
Kural uygulama işlevleri daha sonra sağlayıcı örneklerini oluşturup döndürebilir:
def _example_library_impl(ctx):
...
return [
...
ExampleInfo(
headers = headers,
files_to_link = depset(
[output_file],
transitive = [
dep[ExampleInfo].files_to_link for dep in ctx.attr.deps
],
),
)
]
Sağlayıcıların özel olarak başlatılması
Özel ön işleme ve doğrulama mantığıyla bir sağlayıcının oluşturulmasını korumak mümkündür. Bu, tüm iletişim türlerinin belirli değişkenliklere uyum sağlar veya kullanıcılara örnek alınıyor.
Bu işlem, provider
işlevine bir init
geri çağırma işlevi geçirilerek yapılır. Bu geri çağırma işlevi sağlanırsa provider()
'ün döndürülen türü, iki değerden oluşan bir tuple olarak değişir: init
kullanılmadığında normal döndürülen değer olan sağlayıcı simgesi ve "ham kurucu".
Bu durumda, sağlayıcı sembolü çağrıldığında doğrudan yeni bir örnek döndürmek yerine bağımsız değişkenleri init
geri çağırma işlevine iletir. Geri çağırma işlevinin döndürdüğü değer, alan adlarını (dizeleri) değerlerle eşleyen bir sözlük olmalıdır. Bu, yeni örneğin alanlarını başlatmak için kullanılır. Geri çağırma işlevinin herhangi bir imzaya sahip olabileceğini ve bağımsız değişkenler imzayla eşleşmezse geri çağırma işlevi doğrudan çağrılmış gibi bir hata bildirildiğini unutmayın.
Buna karşılık, ham oluşturucu init
geri çağırmasını atlar.
Aşağıdaki örnekte, bağımsız değişkenlerini önceden işlemek ve doğrulamak için init
kullanılmaktadır:
# //pkg:exampleinfo.bzl
_core_headers = [...] # private constant representing standard library files
# It's possible to define an init accepting positional arguments, but
# keyword-only arguments are preferred.
def _exampleinfo_init(*, files_to_link, headers = None, allow_empty_files_to_link = False):
if not files_to_link and not allow_empty_files_to_link:
fail("files_to_link may not be empty")
all_headers = depset(_core_headers, transitive = headers)
return {'files_to_link': files_to_link, 'headers': all_headers}
ExampleInfo, _new_exampleinfo = provider(
...
init = _exampleinfo_init)
export ExampleInfo
Ardından, kural uygulaması sağlayıcıyı aşağıdaki gibi örneklendirebilir:
ExampleInfo(
files_to_link=my_files_to_link, # may not be empty
headers = my_headers, # will automatically include the core headers
)
Ham oluşturucu, alternatif kamu fabrikası işlevlerini tanımlamak için kullanılabilir
init
mantığına uygun değildir. Örneğin, exampleinfo.bzl dosyasında şunları tanımlayabiliriz:
def make_barebones_exampleinfo(headers):
"""Returns an ExampleInfo with no files_to_link and only the specified headers."""
return _new_exampleinfo(files_to_link = depset(), headers = all_headers)
Ham kurucu genellikle adı alt çizgiyle başlayan bir değişkene (yukarıdaki _new_exampleinfo
) bağlanır. Böylece kullanıcı kodu, kurucuyu yükleyemez ve rastgele sağlayıcı örnekleri oluşturamaz.
init
'ün başka bir kullanımı, kullanıcının sağlayıcı simgesini tamamen çağırmasını engellemek ve bunun yerine kullanıcıyı fabrika işlevini kullanmaya zorlamaktır:
def _exampleinfo_init_banned(*args, **kwargs):
fail("Do not call ExampleInfo(). Use make_exampleinfo() instead.")
ExampleInfo, _new_exampleinfo = provider(
...
init = _exampleinfo_init_banned)
def make_exampleinfo(...):
...
return _new_exampleinfo(...)
Yürütülebilir kurallar ve test kuralları
Yürütülebilir kurallar, bazel run
komutu tarafından çağrılabilecek hedefleri tanımlar.
Test kuralları, yürütülebilir özel bir tür yürütülebilir kuraldır. Yürütülebilir kurallar; hedefler de
bazel test
komutuyla çağrılır. Yürütülebilir ve test kuralları,
ilgili executable
veya
rule
çağrısında True
adlı kullanıcıya yönelik test
bağımsız değişkeni:
example_binary = rule(
implementation = _example_binary_impl,
executable = True,
...
)
example_test = rule(
implementation = _example_binary_impl,
test = True,
...
)
Test kurallarının adları _test
ile biten adlara sahip olmalıdır. (Test hedef adları da genellikle kural gereği _test
ile biter ancak bu zorunlu değildir.) Test dışı kurallarda bu son ek bulunmamalıdır.
Her iki kural türü de run
veya test
komutları tarafından çağrılacak, yürütülebilir bir çıkış dosyası (önceden bildirilmiş olabilir veya bildirilmemiş olabilir) oluşturmalıdır. Anlatmak için
Bir kural çıkışlarından hangisinin bu yürütülebilir olarak kullanılacağını Bazel, bunu
Döndürülen DefaultInfo
işlevinin executable
bağımsız değişkeni
sağlar. Bu executable
, kuralın varsayılan çıkışlarına eklenir (böylece
hem executable
hem de files
adlı cihaza iletmesi gerekmez). Aynı zamanda,
runfiles eklenir:
def _example_binary_impl(ctx):
executable = ctx.actions.declare_file(ctx.label.name)
...
return [
DefaultInfo(executable = executable, ...),
...
]
Bu dosyayı oluşturan işlem, dosyadaki yürütülebilir biti ayarlamalıdır. Örneğin,
ctx.actions.run
veya
Bunun yapılması gereken ctx.actions.run_shell
işlemi
işlem tarafından çağrılan temel araç tarafından uygulanır. ctx.actions.write
işlemi için is_executable=True
değerini iletin.
Eski davranış olarak, yürütülebilir kurallarda
önceden tanımlanmış özel ctx.outputs.executable
çıkışı. Bu dosya,
DefaultInfo
kullanarak bir uygulama belirtmezseniz varsayılan olarak yürütülebilir; olmaması gerekir
geri alınamaz. Bu çıkış mekanizması, analiz sırasında yürütülebilir dosyanın adını özelleştirmeyi desteklemediği için desteği sonlandırılmıştır.
Örneklere bakın yürütülebilir kural ve test kuralını inceleyin.
Yürütülebilir kurallar ve test kurallarının doğrudan tanımlanmış özellikleri vardır. tüm kurallara uymalıdır. Varsayılan dolaylı olarak eklenen özellikler değiştirilemez ancak özel bir kuralı Starlark makrosu içine sarmalayarak varsayılan:
def example_test(size="small", **kwargs):
_example_test(size=size, **kwargs)
_example_test = rule(
...
)
Runfiles konumu
Yürütülebilir bir hedef bazel run
(veya test
) ile çalıştırıldığında,
Runfiles dizini yürütülebilir dosyanın bitişiğindedir. Yollar aşağıdaki gibi ilişkilidir:
# Given launcher_path and runfile_file:
runfiles_root = launcher_path.path + ".runfiles"
workspace_name = ctx.workspace_name
runfile_path = runfile_file.short_path
execution_root_relative_path = "%s/%s/%s" % (
runfiles_root, workspace_name, runfile_path)
Runfiles dizininin altındaki File
yolu şuna karşılık gelir:
File.short_path
Doğrudan bazel
tarafından yürütülen ikili program, kök dizesine bitişik
runfiles
dizini. Ancak çalışma dosyalarından from adlı ikili dosyalar aynı varsayımı yapamaz. Bu sorunu azaltmak için her ikili, bir ortam veya komut satırı bağımsız değişkeni/işareti kullanarak çalıştırma dosyası kökünü parametre olarak kabul etmenin bir yolunu sağlamalıdır. Bu, ikili programların doğru standart çalıştırma dosyası kökünü iletmesine olanak tanır
içine koymamız gereken bir durumdur. Bu ayar yapılmazsa bir ikili, çağrılan ilk ikili olduğunu tahmin edebilir ve bitişik bir çalıştırma dosyası dizini arayabilir.
İleri düzey konular
Çıkış dosyaları isteğinde bulunma
Tek bir hedefin birden fazla çıkış dosyası olabilir. Bir bazel build
komutu çalıştırıldığında, komuta verilen hedeflerin bazılarının istendiği kabul edilir. Bazel yalnızca istenen bu dosyaları ve doğrudan veya dolaylı olarak bu dosyalara bağlı olan dosyaları derleyebilir. (İşlem grafiği açısından Bazel yalnızca istenen dosyaların geçişli bağımlılıkları olarak erişilebilen işlemleri yürütür.)
Varsayılan çıkışlara ek olarak, komut satırında açıkça istenebilecek herhangi bir önceden bildirilmiş çıkış vardır. Kurallar, çıktı özellikleri aracılığıyla önceden tanımlanmış çıkışları belirtebilir. Bu durumda kullanıcı, kuralı örneklendirirken çıkışlar için etiketleri açıkça seçer. Çıkış özellikleri için File
nesneleri elde etmek üzere ctx.outputs
'in ilgili özelliğini kullanın. Kurallar, hedef ada göre önceden bildirilmiş çıkışları dolaylı olarak tanımlayabilir ancak bu özelliğin desteği sonlandırılmıştır.
Varsayılan çıkışlara ek olarak, birlikte istenebilecek çıkış dosyası koleksiyonları olan çıkış grupları da vardır. Bu istekler
--output_groups
. Örneğin,
Örneğin, //pkg:mytarget
hedefi debug_files
içeren bir kural türündeyse
bu dosyalar bazel build //pkg:mytarget
--output_groups=debug_files
çalıştırılarak oluşturulabilir. Önceden tanımlanmamış çıkışların etiketi olmadığından yalnızca varsayılan çıkışlarda veya bir çıkış grubunda görünerek istenebilirler.
Çıkış grupları, OutputGroupInfo
sağlayıcısıyla belirtilebilir. Birçok yerleşik sağlayıcının aksine OutputGroupInfo
'ün, çıkış gruplarını tanımlamak için rastgele adlara sahip parametreler alabileceğini unutmayın:
def _example_library_impl(ctx):
...
debug_file = ctx.actions.declare_file(name + ".pdb")
...
return [
DefaultInfo(files = depset([output_file]), ...),
OutputGroupInfo(
debug_files = depset([debug_file]),
all_files = depset([output_file, debug_file]),
),
...
]
Ayrıca çoğu sağlayıcının aksine OutputGroupInfo
, hem
aspect ve bu özelliğin uygulandığı kural hedefi,
ancak aynı çıkış gruplarını tanımlamazlar. Bu durumda, ortaya çıkan sağlayıcılar birleştirilir.
OutputGroupInfo
değerinin genellikle bir hedeften tüketicilerinin işlemlerine belirli dosya türlerini iletmek için kullanılmaması gerektiğini unutmayın. Tanımla
kurallara özel sağlayıcılar kullanabilirsiniz.
Yapılandırmalar
Farklı bir mimari için C++ ikili programı derlemek istediğinizi düşünün. Derleme karmaşık olabilir ve birden fazla adım içerebilir. Derleyiciler ve kod oluşturucular gibi bazı ara ikili dosyaların yürütme platformunda (barındırma sunucunuz veya uzak bir yürütücü olabilir) çalıştırılması gerekir. Nihai çıkış gibi bazı ikili dosyalar, hedef mimari için derlenmelidir.
Bu nedenle, Bazel'in "yapılandırmalar" daha fazla bilgi edineceksiniz. İlgili içeriği oluşturmak için kullanılan en üstteki hedefler (komut satırında istenenler) "target" yürütme platformunda çalışması gereken araçlar ise "exec" içinde yerleşik olarak yapılandırma. Kurallar, yapılandırmaya bağlı olarak farklı işlemler oluşturabilir (ör. derleyiciye iletilen CPU mimarisini değiştirmek için). Bazı durumlarda, farklı cihazlar için aynı kitaplık yapılandırmanın üç yolu vardır. Bu durumda, analiz edilir ve muhtemelen birden çok kez oluşturulur.
Varsayılan olarak Bazel, hedefin kendisi, başka bir deyişle geçişler olmadan. Bağımlılık hedefin oluşturulması için gereken özel bir araç varsa, exec yapılandırmasına geçiş olduğunu belirtir. Bu, aracın ve onun tüm özelliklerini bağımlılıkları belirlemenize yardımcı olur.
Her bir bağımlılık özelliğinde, bağımlılıkların olup olmadığına karar vermek için cfg
kullanabilirsiniz.
aynı yapılandırmada derlemesi veya bir yönetici yapılandırmasına geçiş yapması gerekir.
Bir bağımlılık özelliğinde executable=True
işareti varsa cfg
açıkça ayarlanmalıdır. Bu, hatalı kullanım için yanlışlıkla bir araç oluşturulmasını önlemek amacıyla
yapılandırma.
Örneği inceleyin
Genel olarak, çalışma zamanında ihtiyaç duyulacak kaynaklar, bağımlı kitaplıklar ve yürütülebilir dosyalar aynı yapılandırmayı kullanabilir.
Derlemenin bir parçası olarak yürütülen araçlar (derleyiciler veya kod oluşturucular gibi)
yürütülmelidir. Bu durumda, özellikte cfg="exec"
değerini belirtin.
Aksi takdirde, çalışma zamanında kullanılan yürütülebilir dosyalar (örneğin bir testin parçası olarak)
oluşturulmalıdır. Bu durumda, özellikte cfg="target"
değerini belirtin.
cfg="target"
aslında herhangi bir şey yapmaz. Tam anlamıyla kullanıcıların
kural tasarımcılarının amaçlarını
açıkça belirtmelerine yardımcı olur. executable=False
olduğunda (yani cfg
isteğe bağlıdır), bunu yalnızca okunabilirliğe gerçekten yardımcı olduğunda ayarlayın.
Ayrıca, şunu kullanmak için cfg=my_transition
kullanabilirsiniz:
geçişlere izin veren kullanıcı tanımlı geçişleri
yapılandırma değiştirme konusunda çok daha fazla esneklikle
dezavantajı
yapı grafiğini daha geniş ve daha az anlaşılır hale getirir.
Not: Geçmişte Bazel'in yürütme platformu kavramı yoktu. Bunun yerine tüm derleme işlemlerinin ana makinede çalıştırıldığı kabul ediliyordu. 6.0'dan önceki Bazel sürümleri bunu temsil etmek için farklı bir "ana makine" yapılandırması oluşturuyordu. "Ana makine" ifadeleri görüyorsanız eski belgeler de böyledir. bahsetmek istiyorum. Kavramsal olan bu ekstradan kaçınmak için Bazel 6.0 veya daha yeni bir sürüm kullanmanızı öneririz. yardımcı olabilir.
Yapılandırma parçaları
Kurallar cpp
, java
ve jvm
gibi yapılandırma parçalarına erişebilir. Ancak erişim hatalarını önlemek için gerekli tüm parçalar bildirilmelidir:
def _impl(ctx):
# Using ctx.fragments.cpp leads to an error since it was not declared.
x = ctx.fragments.java
...
my_rule = rule(
implementation = _impl,
fragments = ["java"], # Required fragments of the target configuration
host_fragments = ["java"], # Required fragments of the host configuration
...
)
Runfiles sembolik bağlantıları
Normalde, bir dosyanın runfiles ağacındaki göreli yolu, söz konusu dosyanın kaynak ağaç veya oluşturulan çıkış ağacındaki göreli yolu ile aynıdır. Bu değerlerin bir nedenle farklı olması gerekiyorsa root_symlinks
veya symlinks
bağımsız değişkenlerini belirtebilirsiniz. root_symlinks
, yolları dosyalarla eşleyen bir sözlüktür. Bu yolların referans noktası, runfiles dizininin köküdür. İlgili içeriği oluşturmak için kullanılan
symlinks
sözlüğü aynı ancak yolların başında dolaylı olarak
depolandığı yerin adını değil, depolandığı yerin adını
hedef) ekleyebilirsiniz.
...
runfiles = ctx.runfiles(
root_symlinks = {"some/path/here.foo": ctx.file.some_data_file2}
symlinks = {"some/path/here.bar": ctx.file.some_data_file3}
)
# Creates something like:
# sometarget.runfiles/
# some/
# path/
# here.foo -> some_data_file2
# <workspace_name>/
# some/
# path/
# here.bar -> some_data_file3
symlinks
veya root_symlinks
kullanılıyorsa iki farklı eşleme yapmamaya dikkat edin
dosyalarını çalıştırma ağacında aynı yola yönlendirir. Bu, derlemenin çakışmayı açıklayan bir hatayla başarısız olmasına neden olur. Bu sorunu düzeltmek için
Çakışmayı kaldırmak için ctx.runfiles
bağımsız değişken. Bu kontrol,
kurallarınızı kullanan tüm hedeflerin yanı sıra bu kurallara bağlı olan her türlü hedef
belirler. Bu durum, özellikle aracınızın geçişli olarak kullanılması ihtimali varsa risklidir.
başka bir araçla; sembolik bağlantı adları bir aracın çalışma dosyalarında benzersiz olmalıdır ve
tüm bağımlılıklarını
fark edebilirsiniz.
Kod kapsamı
coverage
komutu çalıştırıldığında,
derlemenin belirli hedefler için kapsam araçları eklemesi gerekebilir. İlgili içeriği oluşturmak için kullanılan
derleme, gerekli araçları içeren kaynak dosyaların listesini de toplar. Alt kümesi
bayrakla kontrol edilen, ancak bayrakla kontrol edilen
--instrumentation_filter
.
Test hedefleri hariç tutulmadığı sürece
--instrument_test_targets
belirtilir.
Bir kural uygulaması, derleme sırasında kapsam araçları eklerse bunu uygulama işlevinde hesaba katmalıdır. ctx.coverage_instrumented, "true" değerini döndürür. kapsam modunu uygular:
# Are this rule's sources instrumented?
if ctx.coverage_instrumented():
# Do something to turn on coverage for this compile action
Kapsam modunda her zaman açık olması gereken mantık (hedefin kaynaklarının gerekli olup olmadığına) bağlı olarak, ctx.configuration.coverage_enabled.
Kural, derlemeden önce doğrudan bağımlılıklarından kaynak içeriyorsa (ör. başlık dosyaları) bağımlılıkların kaynaklarının da enstrümante edilmesi gerekiyorsa derleme zamanı enstrümantasyonunu da etkinleştirmesi gerekebilir:
# Are this rule's sources or any of the sources for its direct dependencies
# in deps instrumented?
if (ctx.configuration.coverage_enabled and
(ctx.coverage_instrumented() or
any([ctx.coverage_instrumented(dep) for dep in ctx.attr.deps]))):
# Do something to turn on coverage for this compile action
Kurallar, aynı zamanda hangi özelliklerin
InstrumentedFilesInfo
sağlayıcısıyla oluşturulan kapsam,
coverage_common.instrumented_files_info
instrumented_files_info
öğesinin dependency_attributes
parametresi, deps
gibi kod bağımlılıkları ve data
gibi veri bağımlılıkları da dahil olmak üzere tüm çalışma zamanı bağımlılık özelliklerini listelemelidir. source_attributes
parametresi,
kuralın kaynak dosya özellikleri:
def _example_library_impl(ctx):
...
return [
...
coverage_common.instrumented_files_info(
ctx,
dependency_attributes = ["deps", "data"],
# Omitted if coverage is not supported for this rule:
source_attributes = ["srcs", "hdrs"],
)
...
]
InstrumentedFilesInfo
döndürülmezse dependency_attributes
içinde, cfg
özelliği "host"
veya "exec"
olarak ayarlanmayan her araç dışı bağımlılık özelliği ile varsayılan bir özellik oluşturulur. (srcs
gibi özellikleri source_attributes
yerine dependency_attributes
içine yerleştirdiği için bu ideal bir davranış değildir ancak bağımlılık zincirindeki tüm kurallar için açık kapsam yapılandırması gerekmesini önler.)
Doğrulama İşlemleri
Bazen derleme hakkında bir şeyler doğrulamanız gerekir bu doğrulamayı yapmak için gereken bilgiler yalnızca yapılarda mevcuttur (kaynak dosyalar veya oluşturulan dosyalar). Bu bilgiler yapılarda bulunduğundan kurallar dosyaları okuyamadığı için analiz sırasında bu doğrulamayı yapamaz. Bunun yerine, işlemlerin bu doğrulamayı yürütme sırasında yapması gerekir. Zaman işlem başarısız olursa işlem ve dolayısıyla derleme de başarısız olur.
Çalıştırılabilecek doğrulamalara örnek olarak statik analiz, hata analizi, bağımlılık ve tutarlılık kontrolleri ile stil kontrolleri.
Doğrulama işlemleri, parçaları hareket ettirerek derleme performansının iyileştirilmesine de yardımcı olabilir birçok işlem bulunur. Örneğin, derleme ve linting yapan tek bir işlem, derleme işlemi ve linting işlemi olarak ayrılabilirse linting işlemi, doğrulama işlemi olarak ve diğer işlemlerle paralel olarak çalıştırılabilir.
Bu "doğrulama işlemleri" genellikle başka bir yerde kullanılan hiçbir şey üretmez. çünkü yalnızca girdileriyle ilgili birtakım iddialarda bulunmaları gerekiyor. Bu bir soruna işaret eder: Doğrulama işlemi gerçekten bir kural, derlemenin başka bir yerinde kullanılırsa işlemin çalıştırılmasını nasıl sağlar? Geçmişte, doğrulama işleminin boş bir dosya oluşturması ve bu çıktıyı derlemedeki diğer önemli işlemlerin girişlerine yapay olarak eklemesi yaklaşımı benimseniyordu:
Bu yöntem işe yarar çünkü Bazel, derleme işlemi sırasında her zaman doğrulama işlemini ancak bunun önemli dezavantajları vardır:
Doğrulama işlemi, derlemenin kritik yolundadır. Bazel, derleme işlemini çalıştırmak için boş çıktının gerekli olduğunu düşündüğü için derleme işlemi girişi yoksayacak olsa bile önce doğrulama işlemini çalıştırır. Bu, paralelliği azaltır ve derlemeleri yavaşlatır.
Derleme işlemi yerine derlemedeki diğer işlemler çalışabilirse doğrulama işlemlerinin boş çıkışlarının bu işlemlere de eklenmesi gerekir (örneğin,
java_library
'nin kaynak jar çıkışı). Bu derleme işlemi yerine çalıştırılabilecek yeni eylemlerin sonradan eklenir ve boş doğrulama çıkışı yanlışlıkla bırakılır.
Bu sorunların çözümü Doğrulamalar Çıktı Grubu'nu kullanmaktır.
Doğrulamalar Çıkış Grubu
Doğrulamalar Çıkış Grubu, diğer doğrulama işlemlerinin kullanılmayan çıktılarını oluşturur; böylece bunların yapay olarak girişlerine eklenir.
Bu grup, --output_groups
işaretinin değerinden ve hedefin nasıl bağımlı olduğundan (örneğin, komut satırında, bağımlılık olarak veya hedefin gizli çıkışları aracılığıyla) bağımsız olarak çıkışlarının her zaman istenmesi açısından özeldir. Normal önbelleğe alma ve artımlılığın
hâlâ geçerlidir: doğrulama işlemine yapılan girişler değişmediyse ve
doğrulama işlemi başarıyla tamamlandıysa doğrulama işlemi
gerekir.
Bu çıkış grubunun kullanılması için doğrulama işlemlerinin bir dosya çıkarması gerekir. boş bir alan olabilir. Bu, normal koşullarda çalışmayan bazı araçların çıkışlar oluşturacaksınız.
Bir hedefin doğrulama işlemleri üç durumda çalıştırılmaz:
- Hedefe bir araç olarak ihtiyaç duyulduğunda
- Hedefe dolaylı bir bağımlılık olarak dayanıldığında (örneğin, "_" ile başlayan özellik)
- Hedef, ana makine veya yürütme yapılandırmasında oluşturulduğunda.
Bu hedeflerin kendine ait olduğu varsayılır. doğrulama hatalarını ortaya çıkaracak ayrı derlemeler ve testler oluşturun.
Doğrulamalar Çıkış Grubunu Kullanma
Doğrulamalar Çıktı Grubu _validation
olarak adlandırılır ve diğer herhangi bir grup gibi kullanılır.
çıkış grubu:
def _rule_with_validation_impl(ctx):
ctx.actions.write(ctx.outputs.main, "main output\n")
ctx.actions.write(ctx.outputs.implicit, "implicit output\n")
validation_output = ctx.actions.declare_file(ctx.attr.name + ".validation")
ctx.actions.run(
outputs = [validation_output],
executable = ctx.executable._validation_tool,
arguments = [validation_output.path])
return [
DefaultInfo(files = depset([ctx.outputs.main])),
OutputGroupInfo(_validation = depset([validation_output])),
]
rule_with_validation = rule(
implementation = _rule_with_validation_impl,
outputs = {
"main": "%{name}.main",
"implicit": "%{name}.implicit",
},
attrs = {
"_validation_tool": attr.label(
default = Label("//validation_actions:validation_tool"),
executable = True,
cfg = "exec"),
}
)
Doğrulama çıkış dosyasının DefaultInfo
veya
girdiler. Bu tür bir kuralın hedefi için doğrulama işlemi, hedef etikete bağlıysa veya hedefin herhangi bir gizli çıkışına doğrudan ya da dolaylı olarak bağlıysa yine de çalışır.
Genellikle doğrulama işlemlerinin sonuçlarının yalnızca emin olun ve diğer işlemlerin girişlerine eklenmez. paralellik kazançlarını ortadan kaldırabilir. Ancak, Bazel'in şu anda bu özelliği uygulanacak özel denetimler vardır. Bu nedenle, doğrulama işlemi çıkışlarının Starlark kurallarıyla ilgili testlerdeki işlemlerin girişlerine eklenmediğini test etmeniz gerekir. Örneğin:
load("@bazel_skylib//lib:unittest.bzl", "analysistest")
def _validation_outputs_test_impl(ctx):
env = analysistest.begin(ctx)
actions = analysistest.target_actions(env)
target = analysistest.target_under_test(env)
validation_outputs = target.output_groups._validation.to_list()
for action in actions:
for validation_output in validation_outputs:
if validation_output in action.inputs.to_list():
analysistest.fail(env,
"%s is a validation action output, but is an input to action %s" % (
validation_output, action))
return analysistest.end(env)
validation_outputs_test = analysistest.make(_validation_outputs_test_impl)
Doğrulama İşlemleri İşareti
Doğrulama işlemlerinin çalıştırılması --run_validations
komut satırı tarafından kontrol edilir
işaretidir. Bu değer varsayılan olarak "true" (doğru) değerine ayarlanır.
Kullanımdan kaldırılan özellikler
Kullanımdan kaldırılan önceden tanımlanmış çıkışlar
Önceden tanımlanmış çıkışları kullanmanın iki desteği sonlandırılmış yolu vardır:
rule
öğesininoutputs
parametresi, Veri oluşturmak için çıkış özelliği adları ile dize şablonları arasında önceden beyan edilmiş çıkış etiketlerinden oluşur. Önceden bildirilmemiş çıkışları ve çıkışları açıkçaDefaultInfo.files
projesine ekliyor. Kural hedefinin önceden beyan edilmiş yerine çıkışı tüketen kurallar için giriş olarak etiketle çıkışının etiketine daha yakın olabilir.Yürütülebilir kurallar için
ctx.outputs.executable
, kural hedefiyle aynı ada sahip önceden tanımlanmış bir yürütülebilir çıkışa başvurur. Sonucu açıkça belirtmeyi tercih edin, örneğinctx.actions.declare_file(ctx.label.name)
ve komutun , yürütülebilir dosyayı yürütülmesine izin verecek şekilde ayarlar. Açıkça yürütülebilir çıktıyıDefaultInfo
executable
parametresine iletin.
Kaçınılması gereken Runfiles özellikleri
ctx.runfiles
ve runfiles
türü, çoğu eski nedenlerle korunan karmaşık bir özellik grubuna sahiptir.
Aşağıdaki öneriler karmaşıklığı azaltmaya yardımcı olur:
ctx.runfiles
'incollect_data
vecollect_default
modlarını kullanmaktan kaçının. Bu modlar, belirli kodlanmış bağımlılık kenarlarında çalışma dosyalarını dolaylı olarak kafa karıştırıcı şekillerde toplar. Bunun yerine, dosyayı şu öğeninfiles
veyatransitive_files
parametrelerini kullanarak ekleyin:ctx.runfiles
kullanarak veya bağımlılıklardan gelen çalıştırma dosyalarınırunfiles = runfiles.merge(dep[DefaultInfo].default_runfiles)
.DefaultInfo
kurucusunundata_runfiles
vedefault_runfiles
özelliklerini kullanmaktan kaçının. Bunun yerineDefaultInfo(runfiles = ...)
değerini belirtin. "Varsayılan" ve "veri" çalışma dosyaları arasındaki ayrım, eski nedenlerden dolayı korunur. Örneğin, bazı kurallar varsayılan çıkışlarınıdata_runfiles
'e, ancakdefault_runfiles
'e koymaz. Bunun yerinedata_runfiles
, kurallar her ikisi de varsayılan çıkışları içermeli ve Çalıştırma dosyaları sağlayan özelliklerdendefault_runfiles
(genellikledata
).runfiles
'üDefaultInfo
'dan alırken (genellikle yalnızca mevcut kural ile bağımlılıkları arasındaki çalıştırma dosyalarını birleştirmek için)DefaultInfo.data_runfiles
'i değilDefaultInfo.default_runfiles
kullanın.
Eski sağlayıcılardan taşıma
Bazel sağlayıcılar geçmişte Target
nesnesinde basit alanlardı. Onlar
noktaları, nokta operatörü kullanılarak erişilmiş ve
işlevi tarafından döndürülen bir struct'a dönüştürülür.
Bu stil kullanımdan kaldırıldı ve yeni kodda kullanılmamalıdır; için aşağıdaki bilgilere bakın bazı ek bilgilere ulaşabilirsiniz. Yeni sağlayıcı mekanizması, ad çakışmalarını önler. Ayrıca, sağlayıcı örneğine erişen tüm kodların sağlayıcı simgesini kullanarak bu örneği almasını zorunlu kılarak veri gizleme özelliğini de destekler.
Şu an için, eski sağlayıcılar desteklenmektedir. Bir kural, aşağıdaki gibi eski ve modern sağlayıcılar:
def _old_rule_impl(ctx):
...
legacy_data = struct(x="foo", ...)
modern_data = MyInfo(y="bar", ...)
# When any legacy providers are returned, the top-level returned value is a
# struct.
return struct(
# One key = value entry for each legacy provider.
legacy_info = legacy_data,
...
# Additional modern providers:
providers = [modern_data, ...])
dep
, bu kuralın bir örneği için sonuçta elde edilen Target
nesnesiyse
sağlayıcılar ve içerikleri dep.legacy_info.x
ve
dep[MyInfo].y
.
Döndürülen yapı, providers
'e ek olarak özel anlamı olan başka alanlar da alabilir (ve bu nedenle ilgili eski sağlayıcıyı oluşturmaz):
files
,runfiles
,data_runfiles
,default_runfiles
veexecutable
, aynı adlandırılmış alanlara karşılık gelirDefaultInfo
.DefaultInfo
sağlayıcısı döndürürken bu alanlardan herhangi birinin belirtilmesine izin verilmez.output_groups
alanı bir yapı değeri alır ve birOutputGroupInfo
değerine karşılık gelir.
Kuralların provides
bildirimlerinde ve bağımlılık özelliklerinin providers
bildirimlerinde eski sağlayıcılar dize olarak, modern sağlayıcılar ise *Info
sembolleriyle iletilir. Taşıma işlemi sırasında dizelerden sembollere geçtiğinizden emin olun. Güncellemenin zor olduğu karmaşık veya büyük kural kümeleri için
atomik bir yapıya sahip olduğunu fark ederseniz, bu diziyi takip etmeniz durumunda
için şu adımları izleyin:
Eski sağlayıcıyı oluşturan kuralları, hem eski sağlayıcıyı hem de eski sağlayıcıyı oluşturacak şekilde değiştirin ve modern sağlayıcılar için geçerlidir. Eski sağlayıcıyı döndürdüğünü belirten kurallarda, bu beyanı hem eski hem de modern sağlayıcıları içerecek şekilde güncelleyin.
Eski sağlayıcıyı kullanan kuralları, modern sağlayıcıyı kullanacak şekilde değiştirin. Herhangi bir özellik beyanı eski sağlayıcıyı gerektiriyorsa bunları modern sağlayıcıyı gerektirecek şekilde de güncelleyin. İsteğe bağlı olarak: bu çalışmayı, tüketicilerin aşağıdakilerden birini kabul etmesini/zorunlu kılmasını sağlayarak 1. adıma provider: Alan adını kullanarak eski sağlayıcının varlığını test etme
hasattr(target, 'foo')
veyaFooInfo in target
kullanan yeni sağlayıcıEski sağlayıcıyı tüm kurallardan tamamen kaldırın.