Bu sayfada, yönleri kullanmanın temel özellikleri ve avantajları açıklanmakta, basit ve ileri düzey örnekler sunulmaktadır.
Yönler, derleme bağımlılık graflarını ek bilgiler ve işlemlerle genişletmenize olanak tanır. Yönleri kullanabileceğiniz 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şlerinde hedeften bağımsız bir ş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.
En boy oranları hakkında temel bilgiler
BUILD
dosyaları, bir projenin kaynak kodunun açıklamasını sağlar: Projenin parçası olan kaynak dosyalar, bu dosyalardan hangi yapıların (hedefler) oluşturulması gerektiği, bu dosyalar arasındaki bağımlılıklar vb. Bazel, derleme yapmak için bu bilgileri kullanır. Yani yapıları oluşturmak için gereken işlem grubunu (ör. derleyici veya bağlayıcı çalıştırma) belirler ve bu işlemleri yürütür. Bazel bunu, hedefler arasında bir bağlılık grafiği oluşturarak ve bu işlemleri toplamak için bu grafiği ziyaret ederek yapar.
Şu BUILD
dosyasını göz önünde bulundurun:
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 örnekteki her hedef için ilgili kuralın (bu durumda "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 bu yapıların konumları ve adları gibi bilgileri sağlayıcılardaki hedeflerin ters bağımlılıklarına ileten işlemler oluşturur.
Yönleri, işlemler oluşturan ve sağlayıcıları döndüren bir uygulama işlevine sahip olmaları açısından kurallara benzer. Ancak bu modellerin gücü, bağımlılıkları için oluşturulan bağımlılıklar grafiğinden gelir. Bir görünümün bir uygulaması ve dağıttığı tüm özelliklerin listesi vardır. "deps" adlı özelliklerde dağıtılan bir A yönü olduğunu varsayalım. Bu yön, hedef X'e uygulanarak bir en boy uygulama düğümü A(X) elde edilir. Uygulama sırasında A noktası, X'in "deps" özelliğinde (A'nın yayılım listesindeki tüm özellikler) belirttiği tüm hedeflere yinelemeli olarak uygulanır.
Bu nedenle, A yönü X hedefine tek bir kez uygulandığında, aşağıdaki şekilde gösterilen hedeflerin orijinal bağımlılık grafiğinin "gölge grafiği" elde edilir:
Şekil 2. Boyutlarla grafik oluşturma.
Gölgelendirilen tek kenarlar, yayılım kümesindeki özellikler boyunca kenarlar olduğundan, bu örnekte runtime_deps
kenarı gölgelendirilmez. Daha sonra, orijinal grafiğin düğümlerinde kural uygulamalarının çağrılmasına benzer şekilde, gölge grafiğindeki tüm düğümlerde bir en boy uygulama işlevi çağrılır.
Basit örnek
Bu örnekte, bir kuralın ve deps
özelliğine sahip tüm bağımlılarının kaynak dosyalarının nasıl yinelemeli olarak yazdırılacağını gösterilmektedir. Bu örnekte, bir özellik uygulaması, bir özellik tanımı ve Bazel komut satırından özelliğin 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çalarına ayırıp her birini ayrı ayrı inceleyelim.
Aspect 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.
Bir kural gibi, bir boyutun da bir uygulama işlevi vardır. Bu durumda işlev _print_aspect_impl
'tür.
attr_aspects
, görünümün yayıldığı kural özelliklerinin listesidir.
Bu durumda, görünüm uygulandığı kuralların deps
özelliği boyunca yayılır.
attr_aspects
için kullanılan diğer bir yaygın bağımsız değişken ['*']
'tır. Bu bağımsız değişken, yönü bir kuralın tüm özelliklerine dağıtır.
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 []
Aspect uygulama işlevleri, kural uygulama işlevlerine benzer. Sağlayıcılar döndürürler, işlemler oluşturabilirler ve iki bağımsız değişken alırlar:
target
: Boyutun uygulandığı hedef.ctx
: Özelliklere erişmek, çıkışlar ve işlemler oluşturmak için kullanılabilenctx
nesnesi.
Uygulama işlevi, ctx.rule.attr
aracılığıyla hedef kuralın özelliklerine erişebilir. Uygulandığı hedef tarafından sağlanan sağlayıcıları (target
bağımsız değişkeni aracılığıyla) inceleyebilir.
Servis sağlayıcıların listesini 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 özelliği uygulamanın en basit yolu, --aspects
bağımsız değişkenini kullanarak komut satırını kullanmaktır. Yukarıdaki en boy oranının print.bzl
adlı bir dosyada tanımlandığını varsayalım. Bu durumda:
bazel build //MyExample:example --aspects print.bzl%print_aspect
print_aspect
öğesini, example
hedefine ve deps
özelliği aracılığıyla yinelenen olarak erişilebilen tüm hedef kurallarına uygular.
--aspects
işareti, <extension file label>%<aspect top-level name>
biçiminde boyutun bir spesifikasyonu olan bir bağımsız değişken alır.
Gelişmiş örnek
Aşağıdaki örnekte, hedef kuraldaki bir özelliğin kullanılması gösterilmektedir. Bu özellik, hedeflerdeki dosyaları sayar ve bunları uzantıya göre filtreleyebilir. Bu örnekte, değerleri döndürmek için sağlayıcının nasıl kullanılacağı, bir bağımsız değişkeni bir özellik uygulamasına iletmek için parametrelerin nasıl kullanılacağı ve bir özelliği kuraldan nasıl çağıracağınız 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, görünümün deps
özelliği aracılığıyla nasıl dağıtıldığı gösterilmektedir.
attrs
, bir özellik 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 dağıtılan özellikler için int
ve string
parametrelerinde values
belirtilmelidir. Bu örnekte, değeri "*
", "h
" veya "cc
" olan extension
adlı bir parametre vardır.
Kuralla dağıtılan görünümler için parametre değerleri, görünümü isteyen kuraldan alınır. Bu işlemde, kuralın aynı ada ve türe sahip özelliği kullanılı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
parametrelerinin values
kısıtlaması atlanabilir.
Boyların label
veya label_list
türünde gizli ö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ış bir gizli özellik yoktur ancak aşağıdaki kod snippet'i, bir araçta belirli bir unsura nasıl iletebileceğiniz gösterilmektedir:
...
attrs = {
'_protoc' : attr.label(
default = Label('//tools:protoc'),
executable = True,
cfg = "exec"
)
}
...
Aspect uygulama
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 özellik uygulama işlevi de bağımlılıklarına erişilebilen bir sağlayıcı yapısı döndürür.
Bu örnekte, FileCountInfo
tek bir alanı count
olan bir sağlayıcı olarak tanımlanmıştır. Sağlayıcı alanlarının fields
özelliğini kullanarak açıkça tanımlanması en iyi uygulamadır.
Bir özellik uygulaması A(X) için sağlayıcı grubu, hedef X için bir kuralın uygulanması ve özellik A'nın uygulanması sonucunda ortaya çıkan sağlayıcıların birleşimidir. Bir kural uygulamasının dağıttığı sağlayıcılar, yönler uygulanmadan önce oluşturulur ve dondurulur ve bir yönden değiştirilemez. Bir hedef ve ona uygulanan bir özellik, OutputGroupInfo
(kural ve özellik farklı çıkış grupları belirttiği sürece birleştirilir) ve InstrumentedFilesInfo
(özellikten alınır) hariç olmak üzere her biri aynı türde bir sağlayıcı sağlıyorsa bu bir hatadır. Bu, yön uygulamalarının hiçbir zaman DefaultInfo
döndürmeyeceği anlamına gelir.
Parametreler ve gizli özellikler, ctx
öğesinin özelliklerinde iletilir. Bu örnekte extension
parametresine referans verilerek hangi dosyaların sayılacağına karar verilir.
Döndürülen sağlayıcılar için, özelliğin dağıtıldığı özelliklerin (attr_aspects
listesinden) değerleri, özelliğin bunlara uygulanmasının sonuçlarıyla değiştirilir. Örneğin, X hedefinin noktalarında 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
, özelliğin uygulandığı orijinal hedefin "dep'lerine" özelliğin uygulanması sonucunda ortaya çıkan hedef nesnelerdir.
Örnekte, görünüm, 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 görünümü ç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ında, FileCountInfo
öğesine ctx.attr.deps
aracılığıyla nasıl erişileceği gösterilmektedir.
Kural tanımında, bir parametrenin (extension
) nasıl tanımlanacağı ve parametreye nasıl varsayılan değer (*
) verileceği gösterilmektedir. Boyut tanımında parametreye uygulanan kısıtlamalar nedeniyle "cc
", "h
" veya "*
" dışında bir varsayılan değer kullanılmasının hata olacağını unutmayın.
Hedef kural aracılığıyla bir yönü ç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, extension
parametresinin kural aracılığıyla görünüme nasıl geçirileceği gösterilmektedir. extension
parametresi kural uygulamasında varsayılan bir değere sahip 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
aracılığıyla yinelemeli olarak erişilebilen tüm hedefler için değerlendirilir.