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:
.cpp
kaynak dosyası (giriş) alın.- Kaynak dosyalarda
g++
'ü çalıştırın (işlem). - Yürütülebilir çıkışı ve diğer dosyaları içeren
DefaultInfo
sağlayıcıyı, çalışma zamanında kullanılabilir hale getirmek için döndürün. CcInfo
sağlayıcısını, ve bağımlılıklarını konuşacağız.
Bazel'in bakış açısından g++
ve standart C++ kitaplıkları da bu kuralın girişleridir. Kural yazarı olarak, yalnızca kullanıcı tarafından sağlanan
aynı zamanda yürütülmesi için gereken tüm araçlar ve kitaplıkların
işlemlerdir.
Herhangi bir kural oluşturmadan veya değiştirmeden önce Bazel'in derleme aşamalarını inceleyin. Derlemenin üç aşamasını (yükleme, analiz ve yürütme) anlamanız önemlidir. Proje zaman çizelgesini kurallar ve makrolar arasındaki farkı anlamak için makrolar hakkında bilgi edinin makrolarında da yer alır. Başlamak için önce Kurallar Eğitimi'ni inceleyin. Ardından, bu sayfayı referans olarak kullanın.
Bazel'in kendisine yerleştirilmiş birkaç kural vardır. Bu yerel kurallar, örneğin
cc_library
ve java_binary
, belirli diller için temel destek sağlar.
Kendi kurallarınızı tanımlayarak dil ve araçlar için de benzer destek özellikleri ekleyebilirsiniz.
yerel olarak desteklemediğini unutmayın.
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ından erişilebilir. Bu işlev,
harici komutlar verebilirsiniz. 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 yüklenebilir ve BUILD
dosyalarında ç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 oluşturulması denir. Bu, Hedefin özellikleri için yeni hedef ve değerler girin.
Kurallar, Starlark işlevlerinden de çağrılabilir ve .bzl
dosyalarına yüklenebilir.
Kuralları çağıran Starlark işlevleri Starlark makroları olarak adlandırılır.
Starlark makroları sonuçta BUILD
dosyalarından çağrılmalıdır ve yalnızca
BUILD
olduğunda yükleme aşamasında çağrılır
dosyaları, hedefleri örneklendirmek için değerlendirilir.
Ö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 bilgiler
özelliklerinin dolaylı olarak
yürütülebilir ve test kurallarını uygulayın. Şu özellikte olan özellikler:
dolaylı olarak eklenmiş olan kelimeler,
attrs
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. Çoğu zaman özellik şeması, sıralama için hangi dosya uzantılarının beklendiğini belirtir kuralının işlediği kaynak dosyayı oluşturur. 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 hedefin kod bağımlılıklarını belirtir. Özellik şeması, bu bağımlılıkların hangi sağlayıcılar tarafından sağlanacağını belirtmelidir. (Örneğin,cc_library
,CcInfo
sağlar.)data
, çalışma zamanında yürütülebilir herhangi bir dosya için kullanıma sunulacak dosyaları belirtir Bu da hedefe bağlıdır. Bu, rastgele dosyaların belirtiliyor.
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. Giriş etiketini belirten tüm özellikler (attr.label_list
, attr.label
veya attr.label_keyed_string_dict
ile tanımlananlar), hedef tanımlanırken etiketleri (veya ilgili Label
nesneleri) bu özellikte listelenen hedefler ile hedef arasında belirli bir türde bağımlılıkları belirtir. Bu etiketlerin depo ve muhtemelen yolu çözümlendi
ve tanımlanan hedefe göre belirlenir.
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.
Özel özellikler ve örtülü bağımlılıklar
Varsayılan değere sahip bir bağımlılık özelliği dolaylı bağımlılık oluşturur. Kullanıcının BUILD
dosyasında belirtmediği hedef grafiğin bir parçası olduğu için gizlidir. 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
aynı olduğunu göreceksiniz.
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. Gizli özellikleri kullanmak genellikle
ve bildirmeyi konuştuk.
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. _compiler
özel bir özellik olduğundan ctx.attr._compiler
, bu kural türünün tüm hedeflerinde her zaman //tools:example_compiler
değerini işaret eder. Alternatif olarak, özelliği alt çizgi olmadan compiler
olarak adlandırabilir ve varsayılan değeri koruyabilirsiniz. Bu, kullanıcıların farklı bir yerine
farklı bir derleyici içerir, ancak derleyicinin kodu ile ilgili bilgi sahibi değildir
etiket.
Örtük bağımlılıklar genellikle kural uygulamasıyla aynı depoda bulunan araçlar için kullanılır. Araç çalışma platformundan veya farklı bir depodan geliyorsa kural, bu aracı bir araç zincirinden almalıdır.
Çıkış özellikleri
attr.output
ve attr.output_list
gibi çıkış özellikleri, hedefin oluşturduğu bir çıkış dosyasını belirtir. 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, bunun tam tersi yerine oluşturulan kural hedefine bağlıdır.
Genellikle çıkış özellikleri yalnızca bir kuralın çıkış oluşturması gerektiğinde kullanılır
hedef ada dayalı olamayan kullanıcı tanımlı adlara sahip olmalıdır. Bir kural
bir çıkış özelliği olarak adlandırılıyor. Bu özellik 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 listesini döndürür:
return [ExampleInfo(headers = depset(...))]
Bunlara, sağlayıcı türü anahtar olarak kullanılarak dizin gösterimi ([]
) ile erişilebilir. 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, başlık dosyalarını hdrs
özelliği aracılığıyla alıyor ve
derleme işlemleri ile bağlantılı olarak, hedefin ve tüketicilerinin
toplayabilirsiniz:
def _example_library_impl(ctx):
...
transitive_headers = [hdr[ExampleInfo].headers for hdr in ctx.attr.hdrs]
Bir struct
öğesinin
hedefin uygulama işlevini çağırın:
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 stil kesinlikle önerilmez ve kurallar taşınması gerekir.
Dosyalar
Dosyalar File
nesneleriyle temsil edilir. Bazel
sırasında dosya G/Ç işlemleri gerçekleştirdiğinde, bu nesneler
doğrudan okuma veya yazma imkanı sunar. Bunun yerine, geri bildirim veren
(bkz. ctx.actions
) işlevlerini kullanarak
ve Eylem grafiği.
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 bağımlılık özelliği için ctx.files
'un ilgili alanı, bu özellik aracılığıyla tüm bağımlılıkların varsayılan çıkışlarının bir listesini içerir:
def _example_library_impl(ctx):
...
headers = depset(ctx.files.hdrs, transitive=transitive_headers)
srcs = ctx.files.srcs
...
ctx.file
, özellikleri allow_single_file=True
olarak ayarlanan bağımlılık özellikleri için tek bir File
veya None
içerir.
ctx.executable
, ctx.file
ile aynı şekilde çalışır ancak yalnızca spesifikasyonları executable=True
ayarlayan bağımlılık özelliklerinin alanlarını 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
nesneleri ctx.actions.declare_file
ve ctx.actions.declare_directory
kullanılarak oluşturulabilir. Çı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". Bazel, bir işlem oluşturulduğunda komutu hemen çalıştırmaz. Bir işlem başka bir işlemin çıktısına bağlı olabileceğinden, işlemi bağımlılık grafiğine kaydeder. Ö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 çalıştırmak için komutunu kullanın.ctx.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. Yok sayılana kadar
yürütme süresi:
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 alt kümesini alır ve şunları içeren (boş olmayan) bir liste oluşturur: çıkış dosyası olarak da kullanabilirsiniz. Giriş ve çıkış dosyaları grubu, analiz aşamasından geçti. Bu, teslim tarihinin bağımlılıklarından gelen sağlayıcılar dahil olmak üzere bir sonucudur. Örneğin, işleminizde unzip komutu çalıştırılıyorsa hangi dosyaların şifresinin çözülmesini beklediğinizi belirtmeniz gerekir (unzip komutunu çalıştırmadan önce). Dahili olarak değişken sayıda dosya oluşturan işlemler, bunları bir tek dosya (zip, tar veya başka bir arşiv biçimi gibi) desteklemez.
İşlemler, tüm girişlerini listelemelidir. Kullanılmayan girişlerin girilmesi ancak verimsizdir.
İşlemler tüm çıkışlarını oluşturmalıdır. Diğer dosyaları yazabilirler ancak çıktılarda olmayan hiçbir şey tüketicilere sunulmaz. 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ç) Çıktı önbelleğe alınıp yeniden kullanılacağı için bu önemlidir.
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 bir 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 diğer kurallara açıkladığı ona güvenir. 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ı, uygulama işlevi tarafından döndürülen Provider
nesnelerinin listesi ile belirtilir.
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, DefaultInfo
öğesinin files
parametresi tarafından belirtilir:
def _example_library_impl(ctx):
...
return [
DefaultInfo(files = depset([output_file]), ...),
...
]
DefaultInfo
bir kural uygulaması tarafından döndürülmezse veya files
parametresi belirtilmezse DefaultInfo.files
varsayılan olarak tüm önceden tanımlanmış çıkışlara (genellikle çıktı özellikleri tarafından oluşturulanlar) ayarlanır.
İş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. Bu yalnızca başarısız olan hedefi yeniden oluşturmak, hata ayıklamayı zorlaştıracağından, yeniden üretmemelidir.
Çalışma dosyaları
Çalışma dosyaları, bir hedefin çalışma zamanında (derleme zamanı yerine) kullandığı bir dosya grubudur. Yürütme aşamasında Bazel, çalıştırma dosyalarını işaret eden sembolik bağlantılar içeren bir dizin ağacı. 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 kuralların yürütülebilir çıkışı, çalışma dosyalarına dolaylı olarak eklenir.
Bazı kurallar, genellikle data
olarak adlandırılan ve çıkışları hedeflerin çalışma dosyalarına eklenen özellikleri belirtir. 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.",
})
Daha sonra kural uygulama işlevleri, 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 sağlayıcı örneklerinin belirli değişmezlik kurallarına uymasını sağlamak veya kullanıcılara örnek elde etmek için daha temiz bir API sunmak için kullanılabilir.
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. İlgili içeriği oluşturmak için kullanılan
geri çağırmanın döndürülen değeri, değerler ile alan adları (dizeler) arasında bir dikt eşleme alanı olmalıdır;
bu, yeni örneğin alanlarını başlatmak için kullanılır. Lütfen
geri çağırmanın herhangi bir imzası olabilir ve bağımsız değişkenler imzayla eşleşmiyorsa
doğrudan geri çağırma işlemi çağrılmış gibi bir hata bildirilir.
Buna karşılık, ham oluşturucu init
geri çağırma işlevini atlar.
Aşağıdaki örnekte, bağımsız değişkenlerini ön işleme almak ve doğrulamak için init
kullanılı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
Daha sonra bir kural uygulaması, sağlayıcıyı şu şekilde örneklendirebilir:
ExampleInfo(
files_to_link=my_files_to_link, # may not be empty
headers = my_headers, # will automatically include the core headers
)
Ham kurucu, init
mantığından geçmeyen alternatif herkese açık fabrika işlevleri tanımlamak için kullanılabilir. Örneğin, exampleinfo.bzl'de
tanımlanabilir:
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)
Genellikle, ham kurucu, adı
alt çizgi (yukarıda _new_exampleinfo
) olduğundan kullanıcı kodu yüklenemez ve
rastgele sağlayıcı örnekleri oluşturabilirsiniz.
init
için başka bir kullanım da kullanıcının sağlayıcıyı aramasını engellemektir.
ve bunun yerine bir fabrika işlevi kullanmaya zorlama:
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ı, hedefleri bazel test
komutuyla da çağrılabilecek özel bir tür çalıştırılabilir kuraldır. Yürütülebilir ve test kuralları, rule
çağrısında ilgili executable
veya test
bağımsız değişkenini True
olarak ayarlayarak oluşturulur:
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 bitmelidir. (Hedef adlarını da sık sık test edin
kurallara göre _test
ile biter, ancak bu zorunlu değildir.) Test dışı kurallar
kullanabilirsiniz.
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, dosyada yürütülebilir bitini ayarlamalıdır. ctx.actions.run
veya ctx.actions.run_shell
işlemleri için bu işlem, işlem tarafından çağrılan temel araç tarafından yapılmalıdır. ctx.actions.write
işlemi için is_executable=True
değerini iletin.
Eski davranış olarak, yürütülebilir kuralların özel bir ctx.outputs.executable
önceden tanımlanmış çıkışı vardır. Bu dosya,
DefaultInfo
kullanarak bir uygulama belirtmezseniz varsayılan olarak yürütülebilir; olmaması gerekir
geri alınamaz. Bu çıkış mekanizması şunları desteklemediği için kullanımdan kaldırıldı:
yürütülebilir dosyanın adını analiz sırasında özelleştirme.
Yürütülebilir kural ve test kuralı örneklerini 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
Bir yürütülebilir hedef bazel run
(veya test
) ile çalıştırıldığında, runfiles dizininin kökü yürütülebilir dosyanın yanındadır. 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 dizini altındaki bir File
'nin yolu File.short_path
'ye karşılık gelir.
Doğrudan bazel
tarafından yürütülen ikili program, kök dizesine bitişik
runfiles
dizini. Ancak çalıştırma dosyalarından from adlı ikili programlar
aynı varsayıma sahiptir. 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 sayede ikili dosyalar, çağırdığı ikili dosyalara doğru standart çalışma dosyası kökünü iletebilir. 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 seviye konular
Çıkış dosyalarını isteme
Tek bir hedefin birden fazla çıkış dosyası olabilir. bazel build
komutu
çalıştırıldığında, komuta verilen hedeflerin bazı çıktılarının, makine öğreniminin
istenebilir. Bazel, yalnızca istenen bu dosyaları ve bunların
bağımlılığın doğrudan veya dolaylı olarak değişmesidir. (İş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
önceden beyan edilmiş çıkışları dolaylı yoldan tanımlayabilirsiniz.
eklemiştir; ancak bu özellik kullanımdan kaldırılmıştır.
Varsayılan çıkışların yanı sıra koleksiyonlar olan çıkış grupları da vardır.
bir dizi çıkış dosyası ekleyebilirsiniz. Bu bilgiler --output_groups
ile istenebilir. Örneğin, bir hedef //pkg:mytarget
, debug_files
çıkış grubuna sahip bir kural türüne sahipse 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. Çoğu modelin aksine
yerleşik sağlayıcılar, OutputGroupInfo
rastgele adlara sahip parametreler alabilir
şu ada sahip çıkış grupları tanımlamak için kullanılır:
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
, aynı çıkış gruplarını tanımlamadıkları sürece hem bir yön hem de bu yönün uygulandığı kural hedefi tarafından döndürülebilir. Bu durumda, ortaya çıkan sağlayıcılar birleştirilir.
OutputGroupInfo
işlevinin genellikle belirli sıralamaları aktarmak için kullanılmaması gerektiğini unutmayın.
tüketicilerin eylemlerine kadar çeşitli dosyalar sunar. 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. Bazı orta düzey derleyici ve kod oluşturucu gibi ikili programların yürütme platformu (barındırıcınız, veya uzaktaki bir yürütücü). Nihai çıkış gibi bazı ikili dosyalar, hedef mimari için derlenmelidir.
Bu nedenle, Bazel'in "yapılandırmalar" daha fazla bilgi edineceksiniz. En üstteki hedefler ("target" yapılandırmasında oluşturulan, komut satırında istenen hedefler) "target" yapılandırmasında, yürütme platformunda çalıştırılması gereken araçlar ise "exec" yapılandırmasında oluşturulur. Kurallar, uygulamanıza bağlı olarak (ör. iletilen CPU mimarisini değiştirmek için) ekler. Bazı durumlarda, farklı yapılandırmalar için aynı kitaplığa ihtiyaç duyulabilir. Bu durumda, analiz edilir ve muhtemelen birden çok kez oluşturulur.
Bazel, varsayılan olarak bir hedefin bağımlılarını hedefin kendisiyle aynı yapılandırmada, yani geçişler olmadan oluşturur. 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 bağımlılık özelliği için, bağımlılıkların aynı yapılandırmada mı yoksa bir yürütme yapılandırmasına mı geçirileceğine karar vermek üzere cfg
değerini kullanabilirsiniz.
Bir bağımlılık özelliği executable=True
bayrağına sahipse cfg
ayarlanmalıdır
açık bir şekilde belirtmelisiniz. 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, aynı yapılandırmayı kullanabilir.
Derleme işleminin bir parçası olarak çalıştırılan araçlar (ör. derleyiciler veya kod oluşturucular) bir exec yapılandırması için derlenmelidir. Bu durumda, cfg="exec"
öğesini
belirtir.
Aksi takdirde, çalışma zamanında kullanılan yürütülebilir dosyalar (ör. bir testin parçası olarak) hedef yapılandırma için derlenmelidir. Bu durumda, cfg="target"
öğesini
belirtir.
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.
cfg=my_transition
simgesini kullanarak kullanıcı tanımlı geçişler de kullanabilirsiniz. Bu geçişler, kural yazarlarına yapılandırmaları değiştirme konusunda çok fazla esneklik sağlar. Bunun dezavantajı ise derleme grafiğinin daha büyük ve daha az anlaşılır hale gelmesidir.
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. Bazel 6.0'dan önceki sürümler ayrı bir "ana makine" oluşturuyordu yapılandıracağım. Kodda veya eski dokümanlarda "ana makine"ye yapılan referanslar görürseniz bu terim bu bağlamda kullanılmaktadır. Bu ek kavramsal yükü önlemek için Bazel 6.0 veya daha yeni bir sürümü kullanmanızı öneririz.
Yapılandırma parçaları
Kurallar erişebilir
yapılandırma parçalarını
cpp
, java
ve jvm
. Ancak, gerekli tüm parçalar şurada tanımlanmalıdır:
için şu adımları izleyin:
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
...
)
Runfile 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
,
dosyalarını içermelidir. Bu dizindeki yollar, runfiles dizininin köküne göre belirlenir. İ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ı dosyayı, çalıştırma dosyaları ağacında aynı yola eşlememeye dikkat edin. Bu, derlemenin başarısız olmasına neden olur
bir hata mesajı alır. Sorunu düzeltmek için çakışma olmaması amacıyla ctx.runfiles
bağımsız değişkenlerinizi değiştirmeniz gerekir. 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 (bir hedefin kaynaklarının özel olarak enstrümante edilip edilmediği), ctx.configuration.coverage_enabled değerine göre koşullandırılabilir.
Kural, derlemeden önce bağımlılıklarından gelen kaynakları doğrudan içeriyorsa (başlık dosyaları gibi) kullanıyorsanız, ve bağımlılıkların hangi kaynaklara yer verilmelidir:
# 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. (Bu ideal bir davranış değildir çünkü
Örneğin, source_attributes
yerine dependency_attributes
içinde srcs
, ancak bu
tüm kurallar için açık kapsam yapılandırılması ihtiyacını ortadan kaldırır.
bağımlılık zinciri olabilir.)
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, yürütme sırasında bu doğrulamayı yapması gerekir. Doğrulama başarısız olduğunda işlem de başarısız olur 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. Ancak bu durum bir sorun teşkil eder: Bir doğrulama işlemi, derlemede başka bir yerde kullanılan bir şey üretmiyorsa kural, işlemi nasıl çalıştırır? 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:
Bazel, derleme işlemi çalıştırıldığında doğrulama işlemini her zaman çalıştıracağı için bu yöntem işe yarar. Ancak bu yöntemin önemli dezavantajları vardır:
Doğrulama işlemi, derlemenin kritik yolundadır. Çünkü Bazel derleme işlemini çalıştırmak için boş çıkış gerektiğini düşünürse önce doğrulama işlemine tabi tutulur. Ancak, derleme işlemi girişi yoksayar. 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 Çıkış 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, hangi bağımsız değişkene bakılmaksızın çıkışlarının her zaman istenmesi
--output_groups
işaretinin değerine ve hedefin nasıl
(örneğin, komut satırında, bağımlılık olarak veya
(hedefin örtülü çıktıları). 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 işlem, normalde çıkış oluşturmayan bazı araçları sarmalayarak dosya oluşturmayı gerektirebilir.
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önetici 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.
Paralellik kazançlarının ortadan kalkmasına neden olabileceğinden, doğrulama işlemlerinin çıktılarının genellikle yalnızca doğrulama çıkış grubuna gitmesi ve diğer işlemlerin girişlerine eklenmemesi önemlidir. Ancak, Bazel'in şu anda bu özelliği uygulanacak özel denetimler vardır. Bu nedenle, doğrulama işlemi çıkışlarının testlerinden yararlanırız. Ö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ı, varsayılan olarak doğru olan --run_validations
komut satırı işaretçisi tarafından kontrol edilir.
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
'ınoutputs
parametresi, önceden tanımlanmış çıkış etiketleri oluşturmak için çıkış özellik adları ile dize şablonları arasında bir eşleme belirtir. Önceden tanımlanmamış çıkışları kullanmayı ve çıkışlarıDefaultInfo.files
'e açıkça eklemeyi tercih edin. Önceden tanımlanmış bir çıktının etiketi yerine, çıktıyı kullanan kurallar için kural hedefinin etiketini giriş olarak kullanın.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. Çıktıyı açıkça belirtmeyi tercih edin (ör.ctx.actions.declare_file(ctx.label.name)
ile) ve yürütülebilir dosyayı oluşturan komutun izinlerini yürütmeye izin verecek şekilde ayarladığından emin olun. Yürütülebilir çıkışıDefaultInfo
işlevininexecutable
parametresine açıkça iletin.
Kullanılmaması gereken Runfile ö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, dosyaları kafa karıştırıcı şekilde, sabit kodlu belirli bağımlılık kenarlarında çalıştırmasına yardımcı olur. 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)
.Şunlardan kaçının:
data_runfiles
vedefault_runfiles
DefaultInfo
oluşturucu. Bunun yerineDefaultInfo(runfiles = ...)
değerini belirtin. "Varsayılan" arasındaki fark ve "data" Runfiles'i yalnızca eski nedenler. Örneğin, bazı kurallar varsayılan çıkışlarınıdata_runfiles
, ancakdefault_runfiles
değil. 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
Geçmişte Bazel sağlayıcıları Target
nesnesindeki basit alanlardı. Nokta operatörü kullanılarak erişilen bu alanlar, alanın kuralın uygulama işlevi tarafından döndürülen bir yapıya yerleştirilmesiyle oluşturulmuştur.
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ı, addan kaçınıyor oluşturur. Ayrıca, bir sunucuya herhangi bir koda erişilmesini zorunlu kılarak sağlayıcı sembolü kullanarak almak için sağlayıcı örneği kullanabilirsiniz.
Ş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. Tüm kuralları atomik olarak güncellemenin zor olduğu karmaşık veya büyük kural kümeleri için aşağıdaki adımları uygulayarak daha kolay bir deneyim elde edebilirsiniz:
Yukarıdaki söz dizimini kullanarak eski sağlayıcıyı oluşturan kuralları, hem eski hem de modern sağlayıcıları oluşturacak şekilde değiştirin. 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ı, bunun yerine modern bir sağlayıcı. Herhangi bir özellik beyanı eski sağlayıcıyı gerektiriyorsa bunları modern sağlayıcıyı gerektirecek şekilde de güncelleyin. İsterseniz bu çalışmayı 1. adımla birlikte yürütebilirsiniz. Bunun için tüketicilerin sağlayıcılardan birini kabul etmesini/zorunlu tutmasını sağlayın:
hasattr(target, 'foo')
kullanarak eski sağlayıcının varlığını veyaFooInfo in target
kullanarak yeni sağlayıcının varlığını test edin.Eski sağlayıcıyı tüm kurallardan tamamen kaldırın.