Bu sayfada, yönlerin kullanımıyla ilgili temel bilgiler ve avantajlar açıklanmakta, ayrıca basit ve gelişmiş örnekler verilmektedir.
Aspect'ler, derleme bağımlılığı grafiklerinin ek bilgiler ve işlemlerle zenginleştirilmesine olanak tanır. Özelliklerin yararlı olabileceği bazı tipik senaryolar:
- Bazel'i entegre eden IDE'ler, proje hakkında bilgi toplamak için yönleri kullanabilir.
- Kod oluşturma araçları, girişlerini hedef bağımsız şekilde yürütmek için yönlerden yararlanabilir. Örneğin,
BUILD
dosyaları protobuf kitaplığı tanımlarının hiyerarşisini belirtebilir ve dile özgü kurallar, belirli bir dil için protobuf destek kodu oluşturan işlemleri eklemek üzere yönleri kullanabilir.
Aspect ile ilgili temel bilgiler
BUILD
dosyaları, bir projenin kaynak kodunu açıklar: hangi kaynak dosyaları projede yer alır, bu dosyalardan hangi yapılar (hedefler) oluşturulmalıdır, bu dosyalar arasındaki bağımlılıklar nelerdir vb. Bazel, bu bilgileri derleme işlemi gerçekleştirmek için kullanır. Yani, yapıları oluşturmak için gereken işlem grubunu (ör. derleyiciyi veya bağlayıcıyı çalıştırma) belirler ve bu işlemleri yürütür. Bazel, hedefler arasında bir bağımlılık grafiği oluşturarak ve bu grafiği ziyaret ederek bu işlemleri toplar.
Aşağıdaki 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:
1.şekil BUILD
dosya bağımlılığı grafiği.
Bazel, yukarıdaki örnekteki her hedef için karşılık gelen kuralın (bu örnekte "java_library") bir 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 ve konumlar ile bu yapıların adları gibi bilgileri sağlayıcılardaki bu hedeflerin ters bağımlılıklarına ileten işlemler oluşturur.
Yönler, işlem oluşturan ve sağlayıcıları döndüren bir uygulama işlevine sahip olmaları bakımından kurallara benzer. Ancak güçlerini, bağımlılık grafiğinin kendileri için oluşturulma şeklinden alırlar. Bir yönün uygulaması ve birlikte yayıldığı tüm özelliklerin listesi vardır. "deps" adlı özellikler boyunca yayılan bir A yönünü ele alalım. Bu yön, bir hedef X'e uygulanarak A(X) yön uygulama düğümü elde edilebilir. Uygulama sırasında, A yönü, X'in "deps" özelliğinde (A'nın yayılma listesindeki tüm özellikler) referans verdiği tüm hedeflere yinelemeli olarak uygulanır.
Bu nedenle, A yönünü X hedefine uygulama işlemi, aşağıdaki şekilde gösterilen hedeflerin orijinal bağımlılık grafiğinin "gölge grafiğini" oluşturur:
Şekil 2. Yönlere göre grafik oluşturun.
Yalnızca yayma kümesindeki özellikler boyunca olan kenarlar gölgelendirilir. Bu nedenle, bu örnekte runtime_deps
kenarı gölgelendirilmez. Ardından, gölge grafikteki tüm düğümlerde, kural uygulamalarının orijinal grafiğin düğümlerinde çağrılmasına benzer şekilde bir yön uygulama işlevi çağrılır.
Basit örnek
Bu örnekte, bir kuralın kaynak dosyalarının ve deps
özelliği olan tüm bağımlılıklarının nasıl yinelemeli olarak yazdırılacağı gösterilmektedir. Bu örnekte, bir yön uygulaması, bir yön tanımı ve yönün 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ırıp her birini ayrı ayrı inceleyelim.
Aspect tanımı
print_aspect = aspect(
implementation = _print_aspect_impl,
attr_aspects = ['deps'],
)
Görünüm tanımları, kural tanımlarına benzer ve aspect
işlevi kullanılarak tanımlanır.
Bir kural gibi, bir yönün de uygulama işlevi vardır. Bu örnekte uygulama işlevi _print_aspect_impl
'dır.
attr_aspects
, yönün yayıldığı kural özelliklerinin listesidir.
Bu durumda, yön, uygulandığı kuralların deps
özelliği boyunca yayılır.
attr_aspects
için yaygın bir diğer argüman da ['*']
'dir. Bu, yönü bir kuralın tüm özelliklerine yayar.
Aspect 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 []
Yön uygulama işlevleri, kural uygulama işlevlerine benzer. Sağlayıcıları döndürür, işlemler oluşturabilir ve iki bağımsız değişken alır:
target
: yönün uygulandığı hedef.ctx
: Özelliklere erişmek, çıkışlar ve işlemler oluşturmak için kullanılabilenctx
nesnesi.
Uygulama işlevi, hedef kuralın özelliklerine ctx.rule.attr
üzerinden erişebilir. Bu işlev, uygulandığı hedef tarafından sağlanan sağlayıcıları (target
bağımsız değişkeni aracılığıyla) inceleyebilir.
Sağlayıcı listesi döndürmek için yönler gereklidir. Bu örnekte, yön hiçbir şey sağlamadığından boş bir liste döndürülür.
Komut satırını kullanarak yönü çağırma
Bir görünümü uygulamanın en basit yolu, komut satırından --aspects
bağımsız değişkenini kullanmaktır. Yukarıdaki yönlerin print.bzl
adlı bir dosyada tanımlandığını varsayarsak:
this:
bazel build //MyExample:example --aspects print.bzl%print_aspect
print_aspect
, hedef example
ve deps
özelliği aracılığıyla yinelemeli olarak erişilebilen tüm hedef kurallara uygulanır.
--aspects
işareti, <extension file label>%<aspect top-level name>
biçiminde en boy oranının belirtildiği bir bağımsız değişken alır.
İleri düzey örnek
Aşağıdaki örnekte, hedeflerdeki dosyaları sayan ve bunları uzantıya göre filtreleyebilen bir hedef kuralından yönün nasıl kullanılacağı gösterilmektedir. Bu dokümanda, değer döndürmek için sağlayıcının nasıl kullanılacağı, bir bağımsız değişkeni yön uygulamasına aktarmak için parametrelerin nasıl kullanılacağı ve bir yönün 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',
)
Aspect tanımı
file_count_aspect = aspect(
implementation = _file_count_aspect_impl,
attr_aspects = ['deps'],
attrs = {
'extension' : attr.string(values = ['*', 'h', 'cc']),
}
)
Bu örnekte, yönün deps
özelliği aracılığıyla nasıl yayıldığı gösterilmektedir.
attrs
, bir yön için bir özellik grubu tanımlar. Herkese açık yön özellikleri parametreleri tanımlar ve yalnızca bool
, int
veya string
türünde olabilir.
Kural tarafından yayılan yönler için int
ve string
parametrelerinde values
belirtilmelidir. Bu örnekte, extension
adlı bir parametre var ve bu parametrenin değeri "*
", "h
" veya "cc
" olabilir.
Kural tarafından yayılan yönler için parametre değerleri, aynı ada ve türe sahip kuralın özelliği kullanılarak yönü isteyen kuraldan alınır.
(file_count_rule
tanımına bakın).
Komut satırı yönleri için parametre değerleri --aspects_parameters
işaretini kullanarak iletilebilir. values
ve int
parametrelerinin string
kısıtlaması atlanabilir.
Yönlerin label
veya label_list
türlerinde özel özellikleri de olabilir. Özel etiket özellikleri, yönler tarafından oluşturulan işlemler için gereken araçlara veya kitaplıklara yönelik bağımlılıkları belirtmek için kullanılabilir. Bu örnekte özel bir özellik tanımlanmamıştır ancak aşağıdaki kod snippet'inde bir aracı bir yönüne nasıl iletebileceğiniz gösterilmektedir:
...
attrs = {
'_protoc' : attr.label(
default = Label('//tools:protoc'),
executable = True,
cfg = "exec"
)
}
...
Aspect 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)]
Bir kural uygulama işlevi gibi, bir yön uygulama işlevi de bağımlılıklarına erişilebilen sağlayıcıların yapısını döndürür.
Bu örnekte, FileCountInfo
, bir alanı count
olan bir sağlayıcı olarak tanımlanır. fields
özelliğini kullanarak bir sağlayıcının alanlarını açıkça tanımlamak en iyi uygulamadır.
Bir A(X) yönü uygulamasının sağlayıcılar kümesi, X hedefi 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, yönler uygulanmadan önce oluşturulur ve dondurulur. Bu sağlayıcılar, bir yön aracılığıyla değiştirilemez. Bir hedef ve ona uygulanan bir yönün her ikisi de bir sağlayıcıya aynı türü sağlıyorsa (OutputGroupInfo
ve InstrumentedFilesInfo
hariç) bu bir hatadır. OutputGroupInfo
, kural ve yön farklı çıkış grupları belirttiği sürece birleştirilir. InstrumentedFilesInfo
ise yönden alınır. Bu, yön uygulamalarının hiçbir zaman DefaultInfo
döndürmeyebileceği anlamına gelir.
Parametreler ve özel özellikler, ctx
özelliklerinde iletilir. Bu örnekte, extension
parametresine referans verilmekte ve hangi dosyaların sayılacağı belirlenmektedir.
Geri dönen sağlayıcılar için, yönün yayıldığı özelliklerin değerleri (attr_aspects
listesinden) yönün uygulanmasıyla elde edilen sonuçlarla değiştirilir. Örneğin, hedef
X'in bağımlılıklarında Y ve Z varsa A(X) için ctx.rule.attr.deps
[A(Y), A(Z)] olur.
Bu örnekte, ctx.rule.attr.deps
, yönün uygulandığı orijinal hedefin "deps" öğesine yönün uygulanması sonucunda elde edilen hedef nesnelerdir.
Örnekte, yön, dosyaların toplam geçişli sayısını biriktirmek için hedef bağımlılıklarından FileCountInfo
sağlayıcısına erişir.
Bir kuraldan yön ç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 uygulaması, FileCountInfo
öğesine ctx.attr.deps
üzerinden 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 "*
" değerlerinden biri olmayan bir varsayılan değerin, yön tanımında parametreye getirilen kısıtlamalar nedeniyle hata olacağını unutmayın.
Bir yönü hedef kural aracılığıyla çağırma
load('//:file_count.bzl', 'file_count_rule')
cc_binary(
name = 'app',
...
)
file_count_rule(
name = 'file_count',
deps = ['app'],
extension = 'h',
)
Bu örnekte, kural aracılığıyla extension
parametresinin yönüne nasıl geçirileceği gösterilmektedir. extension
parametresinin kural uygulamasında varsayılan bir değeri olduğundan extension
, isteğe bağlı bir parametre olarak kabul edilir.
file_count
hedefi oluşturulduğunda, yönümüz kendi başına ve deps
üzerinden yinelemeli olarak erişilebilen tüm hedefler için değerlendirilir.