Özellikler

Sorun bildir Kaynağı görüntüle Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

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:

Grafik oluşturma

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:

Aspect ile Grafik Oluşturma

Ş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ılabilen ctx 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.

Referanslar