Bu sayfada, görünümleri kullanmanın temelleri ve avantajları açıklanmakta ve basit ve gelişmiş örnekler sağlanmaktadır.
Özellikler, ek bilgi ve işlemlerle bağımlılık grafiklerinin geliştirilmesini sağlar. Özelliklerin yararlı olabileceği bazı yaygın senaryolar:
- Bazel'i entegre eden IDE'ler, proje hakkında bilgi toplamak için unsurları kullanabilir.
- Kod oluşturma araçları, girdilerini hedeften bağımsız ş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 işlemler eklemek üzere yönleri kullanabilir.
En boy oranıyla ilgili temel bilgiler
BUILD
dosyaları, bir projenin kaynak kodunun açıklamasını sağlar: Hangi kaynak dosyaların projenin parçası olduğunu, bu dosyalardan hangi yapıların (hedefler) oluşturulması gerektiği, bu dosyalar arasındaki bağımlılıkların neler olduğu vb. Bazel, bir derleme gerçekleştirmek için bu bilgileri kullanır. Bazel, yapıları (ör. derleyici veya bağlayıcıyı çalıştıran) üretmek için gereken işlem kümesini belirler. Bazel, hedefler arasında bir bağımlılık grafiği oluşturarak ve bu işlemleri toplamak için bu grafiği ziyaret ederek bunu 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ımlıyor:
Şekil 1. BUILD
dosyası bağımlılık grafiği.
Bazel, yukarıdaki örnekte yer alan 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ı ve adları gibi bilgileri sağlayıcılardaki bu hedeflerin ters bağımlılıklarına iletir.
Özellikler, işlem oluşturan ve sağlayıcı döndüren bir uygulama işlevine sahip olması açısından kurallara benzer. Ancak güç, bağımlılık grafiğinin onlar için oluşturulma biçiminden kaynaklanır. Bir özelliğin bir uygulaması ve birlikte yaydığı tüm özelliklerin bir listesi vardır. "Deps" adlı öznitelikler boyunca yayılan bir A yönünü düşünün. Bu özellik, hedef X'e uygulanabilir ve böylece bir en boy uygulama düğümü A(X) elde edilir. A yönü, A yönü, X'in "deps" özelliğinde atıfta bulunduğu tüm hedeflere (A'nın yayılım listesindeki tüm özellikler) yinelemeli olarak uygulanır.
Dolayısıyla, A yönünün bir hedef X'e uygulanmasıyla ilgili 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 grubundaki özellikler boyunca uzanan kenarlardır. Dolayısıyla runtime_deps
kenarı bu örnekte 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 yinelemeli olarak nasıl yazdırılacağı ve deps
özelliğine sahip tüm bağımlılıklarının nasıl yazdırılacağı gösterilmektedir. Burada 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österilmektedir.
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 parçalara 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.
Kuralda olduğu gibi, bir yönün uygulama işlevi şu şekildedir: _print_aspect_impl
.
attr_aspects
, en boy özelliğinin yayıldığı kural özelliklerinin listesidir.
Bu durumda en boy, uygulandığı kuralların deps
özelliği boyunca yayılır.
attr_aspects
için bir diğer yaygın bağımsız değişken de ['*']
, 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
: En boy özelliğinin 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 sorgu, uygulandığı hedef tarafından sağlanan sağlayıcıları inceleyebilir (target
bağımsız değişkeni aracılığıyla).
Sağlayıcı listesi döndürülmesi için özellikler gereklidir. Bu örnekte, en boy oranı hiçbir şey sağlamadığından boş bir liste döndürür.
Komut satırını kullanarak öğe çağırın
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 şu şekilde print.bzl
adlı bir dosyada tanımlandığı varsayıldığında:
bazel build //MyExample:example --aspects print.bzl%print_aspect
print_aspect
öğesini hedef example
öğesine 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şkeni alır. Bu, <extension file label>%<aspect top-level name>
biçimindeki en boy özelliğinin spesifikasyonudur.
Gelişmiş örnek
Aşağıdaki örnek, hedeflerdeki dosyaları sayan ve bunları uzantıya göre filtreleyen bir hedef kuraldan özelliğin kullanımını göstermektedir. Değer döndürmek için sağlayıcının nasıl kullanılacağını, bir bağımsız değişkeni en boy uygulamasına geçirmek için parametrelerin nasıl kullanılacağını ve bir kuraldan bir özelliğin nasıl çağrılacağını gösterir.
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 örnek, en boy oranının deps
özelliği aracılığıyla nasıl yayıldığını gösterir.
attrs
, bir özellik grubunu tanımlar. Herkese açık en boy özellikleri, parametreleri tanımlar ve yalnızca bool
, int
veya string
türlerinde olabilir.
Kuralla çoğaltılan yönler için int
ve string
parametrelerinin üzerinde values
belirtilmiş olmalıdır. Bu örnekte extension
adlı bir parametrenin değer olarak "*
", "h
" veya "cc
" olmasına izin veriliyor.
Kuralla çoğaltılan yönler için parametre değerleri, aynı ada ve türe sahip kuralın özelliği kullanılarak, en boy bilgisini isteyen kuraldan alınır.
(file_count_rule
tanımına bakın).
Komut satırı özellikleri için parametre değerleri --aspects_parameters
işareti kullanılarak iletilebilir. int
ve string
parametreleriyle ilgili values
kısıtlaması atlanabilir.
Ayrıca, boyutların label
veya label_list
türünde gizli özelliklere sahip olmasına da izin verilir. Özel etiket özellikleri, yönler tarafından oluşturulan işlemler için gereken araçlar veya kitaplıklardaki bağımlılıkları belirtmek için kullanılabilir. Bu örnekte tanımlı özel 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, en boy uygulama işlevi de bağımlılıkları tarafından erişilebilen sağlayıcıların bir struct'ını döndürür.
Bu örnekte FileCountInfo
, tek alanı count
olan bir sağlayıcı olarak tanımlanmıştır. fields
özelliğini kullanarak bir sağlayıcının alanlarını açıkça tanımlamak en iyi uygulamadır.
Bir boy uygulaması A(X) için sağlayıcılar grubu, hedef X için bir kuralın uygulanmasından ve A yönünün uygulanmasından gelen sağlayıcıların birleşimidir. Bir kural uygulamasının yaydığı sağlayıcılar, en boy oranları uygulanmadan önce oluşturulup dondurulur ve belirli bir açıdan değiştirilemez. Bir hedef ve ona uygulanan bir özelliğin her biri aynı türde bir sağlayıcı sağlarsa OutputGroupInfo
(kural ve en boy farklı çıkış grupları belirttiği sürece birleştirilir) ve InstrumentedFilesInfo
(bu öğeden alınır) istisnaları olması hatadır. Bu, yön uygulamalarının hiçbir zaman DefaultInfo
döndürmeyebileceği anlamına gelir.
Parametreler ve gizli özellikler, ctx
özelliklerinde iletilir. Bu örnekte extension
parametresine referansta bulunulur ve hangi dosyaların sayılacağı belirlenir.
Geri gelen sağlayıcılar için, en boy özelliğinin yayıldığı özelliklerin değerleri (attr_aspects
listesinden), ilgili özelliğin kendilerine uygulandığı bir uygulamanın sonuçlarıyla değiştirilir. Örneğin, X hedefinin atamasında Y ve Z varsa A(X) için ctx.rule.attr.deps
[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 nesneleridir.
Bu örnekte en boy, 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ğırın
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 uygulaması, 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 varsayılan değerin (*
) nasıl verileceğini gösterir. "cc
", "h
" veya "*
" değerlerinden biri olmayan bir varsayılan değere sahip olmanın, en boy tanımında parametreye yerleştirilen kısıtlamalar nedeniyle hata olabileceğini unutmayın.
Hedef kuralı aracılığıyla bir özellik çağırma
load('//:file_count.bzl', 'file_count_rule')
cc_binary(
name = 'app',
...
)
file_count_rule(
name = 'file_count',
deps = ['app'],
extension = 'h',
)
Bu şekilde, extension
parametresinin kural aracılığıyla ilgili öğeye nasıl iletileceği gösterilmektedir. 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 yinelemeli olarak erişilebilir.