Bu sayfada, özellikler kullanımının temelleri ve faydaları açıklanmakta ve basit ve gelişmiş örnekler sağlanmaktadır.
Yönler, ek bilgi ve işlemlerle derleme bağımlılığı grafiklerinin genişletilmesine olanak tanır. Özelliklerin yararlı olabileceği bazı yaygın senaryolar:
- Bazel'ı entegre eden IDE'ler, proje hakkında bilgi toplamak için çeşitli boyutları kullanabilir.
- Kod oluşturma araçları, girdilerini hedeften bağımsız bir şekilde yürütmek için yönlerden yararlanabilir. Örneğin,
BUILD
dosyaları protobuf kitaplık tanımlarının bir hiyerarşisini belirtebilir ve dile özgü kurallar, belirli bir dil için protobuf destek kodu oluşturan eylemler eklemek üzere yönler kullanabilir.
En boy ile ilgili temel bilgiler
BUILD
dosyaları, projenin kaynak kodu için bir açıklama sağlar: Projenin parçası olan kaynak dosyaları, bu dosyalardan hangi yapıların (hedefler) derlenmesi gerektiği, bu dosyalar arasındaki bağımlılıkların ne olduğu gibi. Bazel, bu bilgileri kullanarak derleme gerçekleştirir. Bir başka deyişle, yapıları (derleyici veya bağlayıcıyı çalıştıran işlemler gibi) üretmek için gereken işlem kümesini belirler. Bazel, bunu hedefler arasında bir bağımlılık grafiği oluşturarak ve bu işlemleri toplamak için bu grafiği ziyaret ederek yapar.
Şu BUILD
dosyasını inceleyin:
java_library(name = 'W', ...)
java_library(name = 'Y', deps = [':W'], ...)
java_library(name = 'Z', deps = [':W'], ...)
java_library(name = 'Q', ...)
java_library(name = 'T', deps = [':Q'], ...)
java_library(name = 'X', deps = [':Y',':Z'], runtime_deps = [':T'], ...)
Bu BUILD
dosyası, aşağıdaki şekilde gösterilen bir bağımlılık grafiğini tanımlar:
Şekil 1. BUILD
dosya bağımlılık grafiği.
Bazel, yukarıdaki örnekte bulunan her hedef için karşılık gelen kuralın (bu örnekte "java_library") uygulama işlevini çağırarak bu bağımlılık grafiğini analiz eder. Kural uygulama işlevleri, .jar
dosyaları gibi yapılar oluşturan işlemler oluşturur ve bu yapıların konumları ile adları gibi bilgileri sağlayıcılardaki hedeflerin tersine bağımlılıklarına iletir.
Yönler, işlem oluşturan ve sağlayıcı döndüren bir uygulama işlevine sahip olması bakımından kurallara benzer. Fakat gücün kaynağı, bağımlılık grafiğinin onlar için oluşturulma şeklidir. Bir unsurun bir uygulaması ve yaydığı tüm özelliklerin listesi vardır. "deps" adlı öznitelikler boyunca yayılan bir A yönünü düşünün. Bu özellik, bir hedef X'e uygulanarak bir en boy uygulama düğümü A(X) elde edilir. A yönü, uygulama sırasında X'in "deps" özelliğinde (A'nın yayılım listesindeki tüm özellikler) atıfta bulunduğu tüm hedeflere yinelemeli olarak uygulanır.
Dolayısıyla, A özelliğini bir hedef X'e uygulamak için yapılan tek bir işlem, aşağıdaki şekilde gösterilen hedeflerin orijinal bağımlılık grafiğinin bir "gölge grafiğini" verir:
2. Şekil. Farklı yönleriyle grafik oluşturun.
Gölgelendirilen tek kenarlar, yayılım kümesindeki özellikler boyunca olan kenarlardır. Dolayısıyla, bu örnekte runtime_deps
kenarı gölgelendirilmez. Daha sonra, kural uygulamalarının orijinal grafiğin düğümlerinde çağrılmasına benzer şekilde, gölge grafikteki tüm düğümlerde bir en boy uygulama işlevi çağrılır.
Basit örnek
Bu örnekte, bir kural için kaynak dosyaların ve deps
özelliğine sahip tüm bağımlılıklarının yinelemeli olarak nasıl yazdırılacağı gösterilmektedir. Bir en boy uygulaması, en boy tanımı ve söz konusu özelliğin Bazel komut satırından nasıl çağrılacağı gösterilmiştir.
def _print_aspect_impl(target, ctx):
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the files that make up the sources and
# print their paths.
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
print(f.path)
return []
print_aspect = aspect(
implementation = _print_aspect_impl,
attr_aspects = ['deps'],
)
Örneği bölümlere ayıralım ve her birini ayrı ayrı inceleyelim.
En boy tanımı
print_aspect = aspect(
implementation = _print_aspect_impl,
attr_aspects = ['deps'],
)
En boy tanımları, kural tanımlarına benzer ve aspect
işlevi kullanılarak tanımlanır.
Kurallarda olduğu gibi, bir unsurun da bir uygulama işlevi vardır. Bu uygulama işlevi şudur:
_print_aspect_impl
.
attr_aspects
, en boy öğesinin yayıldığı kural özelliklerinin listesidir.
Bu durumda, en boy öğesi, uygulandığı kuralların deps
özelliği boyunca yayılır.
attr_aspects
için yaygın olarak kullanılan bir başka bağımsız değişken de ['*']
kuralıdır. Bu bağımsız değişken, bir kuralın tüm özelliklerine yayılır.
En boy uygulaması
def _print_aspect_impl(target, ctx):
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the files that make up the sources and
# print their paths.
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
print(f.path)
return []
En boy uygulama işlevleri, kural uygulama işlevlerine benzer. Bunlar sağlayıcılar döndürür, eylemler oluşturabilir ve iki bağımsız değişken alabilir:
target
: Özelliğin uygulandığı hedef.ctx
: Özelliklere erişmek ve çıkışlar ile işlemler oluşturmak için kullanılabilecekctx
nesnesi.
Uygulama işlevi, hedef kuralın özelliklerine ctx.rule.attr
üzerinden erişebilir. Bu uzantı, uygulandığı hedef tarafından sağlanan sağlayıcıları inceleyebilir (target
bağımsız değişkeni aracılığıyla).
Sağlayıcıların listesini döndürmek için bu özelliklerin özellikleri gereklidir. Bu örnekte, en boy hiçbir şey sağlamadığından boş bir liste döndürür.
Komut satırını kullanarak öğe çağırma
Bir özelliği uygulamanın en basit yolu, --aspects
bağımsız değişkenini kullanarak komut satırından yararlanmaktır. Yukarıdaki özelliğin print.bzl
adlı bir dosyada tanımlandığını varsayarsak:
bazel build //MyExample:example --aspects print.bzl%print_aspect
print_aspect
öğesini example
hedefine ve deps
özelliği aracılığıyla yinelemeli olarak erişilebilen tüm hedef kurallara uygular.
--aspects
işareti bir bağımsız değişken alır. Bu, en boy özelliğinin <extension file label>%<aspect top-level name>
biçimindeki spesifikasyonudur.
Gelişmiş örnek
Aşağıdaki örnek, hedeflerde dosyaları sayan ve bunları uzantıya göre filtreleyen bir hedef kuraldan en boy özelliğinin kullanımını göstermektedir. Bu kılavuzda, değerleri döndürmek için sağlayıcının nasıl kullanılacağı, bir en boy uygulamasına bir bağımsız değişkeni aktarmak için parametrelerin nasıl kullanılacağı ve bir özelliğin bir kuraldan nasıl çağrılacağı gösterilmektedir.
file_count.bzl
dosyası:
FileCountInfo = provider(
fields = {
'count' : 'number of files'
}
)
def _file_count_aspect_impl(target, ctx):
count = 0
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the sources counting files
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if ctx.attr.extension == '*' or ctx.attr.extension == f.extension:
count = count + 1
# Get the counts from our dependencies.
for dep in ctx.rule.attr.deps:
count = count + dep[FileCountInfo].count
return [FileCountInfo(count = count)]
file_count_aspect = aspect(
implementation = _file_count_aspect_impl,
attr_aspects = ['deps'],
attrs = {
'extension' : attr.string(values = ['*', 'h', 'cc']),
}
)
def _file_count_rule_impl(ctx):
for dep in ctx.attr.deps:
print(dep[FileCountInfo].count)
file_count_rule = rule(
implementation = _file_count_rule_impl,
attrs = {
'deps' : attr.label_list(aspects = [file_count_aspect]),
'extension' : attr.string(default = '*'),
},
)
BUILD.bazel
dosyası:
load('//:file_count.bzl', 'file_count_rule')
cc_library(
name = 'lib',
srcs = [
'lib.h',
'lib.cc',
],
)
cc_binary(
name = 'app',
srcs = [
'app.h',
'app.cc',
'main.cc',
],
deps = ['lib'],
)
file_count_rule(
name = 'file_count',
deps = ['app'],
extension = 'h',
)
En boy tanımı
file_count_aspect = aspect(
implementation = _file_count_aspect_impl,
attr_aspects = ['deps'],
attrs = {
'extension' : attr.string(values = ['*', 'h', 'cc']),
}
)
Bu örnekte, en boy değerinin deps
özelliği aracılığıyla nasıl yayıldığı gösterilmektedir.
attrs
, bir özellik grubunu tanımlar. Herkese açık özellik özellikleri string
türündedir ve parametre olarak adlandırılır. Parametreler üzerinde birvalues
özelliği belirtilmelidir. Bu örnekte, "*
", "h
" veya "cc
" değerine sahip olmasına izin verilen extension
adlı bir parametre bulunmaktadır.
En boy için parametre değerleri, özelliği isteyen kuralın adıyla aynı ada sahip dize özelliğinden alınır (file_count_rule
tanımına bakın).
Parametreleri tanımlamak için söz dizimi bulunmadığından, parametre içeren özellikler komut satırı üzerinden kullanılamaz.
Özelliklerin label
veya label_list
türünde özel özelliklere de sahip olmasına izin verilir. Özel etiket özellikleri, yönler tarafından oluşturulan işlemler için gereken araçlara veya kitaplıklara olan bağımlılıkları belirtmek için kullanılabilir. Bu örnekte tanımlanmış gizli bir özellik yoktur, ancak aşağıdaki kod snippet'i bir aracı bir özelliğe nasıl geçirebileceğinizi göstermektedir:
...
attrs = {
'_protoc' : attr.label(
default = Label('//tools:protoc'),
executable = True,
cfg = "exec"
)
}
...
En boy uygulaması
FileCountInfo = provider(
fields = {
'count' : 'number of files'
}
)
def _file_count_aspect_impl(target, ctx):
count = 0
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the sources counting files
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if ctx.attr.extension == '*' or ctx.attr.extension == f.extension:
count = count + 1
# Get the counts from our dependencies.
for dep in ctx.rule.attr.deps:
count = count + dep[FileCountInfo].count
return [FileCountInfo(count = count)]
Kural uygulama işlevinde olduğu gibi, özellik uygulama işlevi de bağımlılıkları tarafından erişilebilen bir sağlayıcı yapısı döndürür.
Bu örnekte FileCountInfo
, bir adet count
alanına sahip bir sağlayıcı olarak tanımlanmıştır. En iyi uygulama, fields
özelliğini kullanarak sağlayıcının alanlarını açıkça tanımlamaktır.
Bir en boy uygulaması A(X) için sağlayıcılar grubu, hedef X için bir kuralın uygulanmasından ve A öğesinin uygulanmasından gelen sağlayıcıların birleşimidir. Bir kural uygulamasının yaydığı sağlayıcılar, özellikler uygulanmadan önce oluşturulur ve dondurulur ve belirli bir açıdan değiştirilemez. OutputGroupInfo
(kural ve en boy farklı çıkış grupları belirttiği sürece birleştirilir) ve InstrumentedFilesInfo
(bu öğeden alınır) hariç olmak üzere, her bir hedef ve ona uygulanan bir özelliğin her biri aynı türe sahip bir sağlayıcı sağlarsa hatadır. Yani, özellik uygulamaları hiçbir zaman DefaultInfo
döndürmeyebilir.
Parametreler ve özel özellikler, ctx
özelliklerinde iletilir. Bu örnekte extension
parametresine referansta bulunulur ve hangi dosyaların sayılacağı belirlenir.
Geri gelen sağlayıcılarda, en boy öğesinin yayıldığı özelliklerin değerleri (attr_aspects
listesinden), söz konusu özelliğin uygulamasının sonuçlarıyla değiştirilir. Örneğin, X hedefinin dikey çizgilerinde Y ve Z varsa A(X) için ctx.rule.attr.deps
değeri [A(Y); A(Z)] olur.
Bu örnekte ctx.rule.attr.deps
, en boy özelliğinin uygulandığı orijinal hedefin "dep'lerine" uygulanmasının sonuçları olan Hedef nesnelerdir.
Bu örnekte, en boy oranı, toplam geçişli dosya sayısını toplamak için hedefin bağımlılıklarından FileCountInfo
sağlayıcısına erişir.
Bir kuraldan öğe çağırma
def _file_count_rule_impl(ctx):
for dep in ctx.attr.deps:
print(dep[FileCountInfo].count)
file_count_rule = rule(
implementation = _file_count_rule_impl,
attrs = {
'deps' : attr.label_list(aspects = [file_count_aspect]),
'extension' : attr.string(default = '*'),
},
)
Kural uygulama, ctx.attr.deps
aracılığıyla FileCountInfo
öğesine nasıl erişileceğini gösterir.
Kural tanımı, bir parametrenin (extension
) nasıl tanımlanacağını ve bu parametreye nasıl varsayılan değer (*
) verileceğini gösterir. "cc
", "h
" veya "*
" dışındaki bir varsayılan değerin, en boy tanımında parametreye uygulanan kısıtlamalar nedeniyle hata olabileceğini unutmayın.
Hedef kuralı aracılığıyla bir özelliği çağırma
load('//:file_count.bzl', 'file_count_rule')
cc_binary(
name = 'app',
...
)
file_count_rule(
name = 'file_count',
deps = ['app'],
extension = 'h',
)
Bu görsel, kural aracılığıyla extension
parametresinin ilgili öğeye nasıl iletileceğini göstermektedir. Kural uygulamasında extension
parametresi varsayılan bir değere sahip olduğundan extension
isteğe bağlı bir parametre olarak kabul edilir.
file_count
hedefi oluşturulduğunda, özelliğimiz kendi başına değerlendirilir ve tüm hedefler, deps
üzerinden tekrar tekrar erişilebilir.