Özellikler

Sorun bildirin Kaynağı göster Gece · 7,4 , 7.3 · 7,2 · 7.1 · 7,0 · 6,5

Bu sayfada, Çevik yaklaşımın temellerini göz önünde bulundurur ve hem basit hem de örnekler.

En boy oranları, ek bilgi içeren bağımlılık grafiklerinin artırılmasına olanak tanır ve işlemler. Yönlerin yararlı olabileceği bazı tipik senaryolar:

  • Bazel'i entegre eden entegre geliştirme ortamları, Google Haritalar'daki belirler.
  • 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 koduyla ilgili bir açıklama sağlar: Hangi kaynak? hangi yapıların (hedefler) oluşturulması gerektiğine, ve bu dosyalar arasındaki bağımlılıkların neler olduğu gibi konuları ele alacağız. Bazel, yani bir derleme işlemi için gereken işlemleri yapıları oluşturmak için gerekli olan (örneğin, derleyici veya bağlayıcı çalıştırma) ve bu işlemleri yürütür. Bazel bunu başarmak için bir bağımlılık grafiği ziyaret edin.

Ş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:

Derleme grafiği

Şekil 1. BUILD dosya bağımlılığı grafiği.

Bazel, bu bağımlılık grafiğini analiz etmek için her biri için karşılık gelen kural (bu örnekte "java_library") hedef. Kural uygulama işlevleri, .jar dosyaları gibi yapıları oluşturan ve bu yapıların konumları ve adları gibi bilgileri sağlayıcılar içindeki bu hedeflerin ters bağımlılıklarına ileten işlemler oluşturur.

Yönler kurallara benzerdir. Kurallara benzer olan bu özellikler, işlem ve iade sağlayıcıları oluşturur. Ancak bu modellerin gücü, bağımlılıkları için oluşturulan bağımlılıklar grafiğinden gelir. Bir yöne göre uygulama mevcut ve yayıldığı tüm özelliklerin listesini içerir. "deps" adlı özelliklerde dağıtılan bir A yönü olduğunu varsayalım. Bu görünüm, X hedefi için uygulanarak A(X) görünümü uygulama düğümü oluşturulur. A yönü, uygulanması sırasında X'in "deps" özelliğinde atıfta bulunduğu tüm hedeflere (A'nın dağıtım listesindeki tüm özellikler) yinelemeli olarak uygulanır.

Bu yüzden, A niteliğini bir hedef X'e uygularken tek bir işlem bir "gölge grafiği" üretir / aşağıda gösterilen hedeflerin orijinal bağımlılık grafiğidir:

En boy oranıyla grafik oluşturma

Şekil 2. Yönleri olan bir grafik oluşturun.

Gölgelendirilen yalnızca kenarlar, yayılım seti olduğundan runtime_deps kenarı bu örneğine bakalım. Ardından, tablodaki tüm düğümlerde bir en boy uygulama işlevi Düğümlerde kural uygulamalarının çağrılmasına benzer şekilde gölge grafik farklı olabilir.

Basit örnek

Bu örnekte, bir kuralı ve tüm bağımlılıkları deps özelliğine sahiptir. Bu sonuçta özellik uygulaması, en boy tanımı ve hususun nasıl çağrılacağı komutunu çalıştırın.

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 küçük parçalara ayırarak her birini ayrı ayrı inceleyelim.

Aspect tanımı

print_aspect = aspect(
    implementation = _print_aspect_impl,
    attr_aspects = ['deps'],
)

Yönetmelik tanımları, kural tanımlarına benzer ve aspect işlevi kullanılarak tanımlanır.

Kural gibi, bir özelliğin de bir uygulama işlevi vardır. Bu örnekte _print_aspect_impl

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 yaygın olarak kullanılan bir diğer bağımsız değişken de ['*'] bağımsız değişkenidir. Bu bağımsız değişken özelliğini nasıl kullanacağınızı göstereceğim.

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 uygulamasına benzer işlevlerine dahildir. Sağlayıcılar döndürürler, işlem yapın ve iki bağımsız değişken alın:

  • target: Özelliğin uygulandığı hedef.
  • ctx: Özelliklere erişmek, çıkışlar ve işlemler oluşturmak için kullanılabilen ctx nesnesi.

Uygulama işlevi, şununla ilgili hedef kuralın özelliklerine erişebilir: ctx.rule.attr. Uygulandığı hedef tarafından sağlanan sağlayıcıları (target bağımsız değişkeni aracılığıyla) inceleyebilir.

Sağlayıcı listesini döndürmek için özellikler gerekir. Bu örnekte, yön hiçbir şey sağlamadığından boş bir liste döndürülür.

Komut satırını kullanarak detayı çağırma

Bir yönü uygulamanın en kolay yolu, komut satırında --aspects bağımsız değişkenini kullanmaktır. Yukarıdaki özelliğin print.bzl adlı bir dosyada tanımlandığı varsayıldığında bu:

bazel build //MyExample:example --aspects print.bzl%print_aspect

print_aspect özelliğini, example hedefine ve deps özelliği aracılığıyla yinelemeli 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.

İleri düzey ö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',
)

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, görünümün deps özelliği aracılığıyla nasıl dağıtıldığı gösterilmektedir.

attrs, bir yönle ilgili özellik grubunu tanımlar. Herkese açık yön özellikleri parametreleri tanımlar ve yalnızca bool, int veya string türünde olabilir. Kural yayılımlı unsurlar için int ve string parametrelerinde Bu öğelerde values belirtilmiş. Bu örnekte extension adlı bir parametre var '*', 'h' veya 'cc' içermesine izin verilen siteler girin.

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 kelimesinin 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.

Ayrıca, label veya label_list türünde özel özelliklere sahip olmalarına da 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 özel bir özellik tanımlanmamıştır ancak aşağıdaki kod snippet'inde bir aracı bir görünüme 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 ö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, benzersiz bir hizmet sağlayıcısı olarak tanımlanmış bir sağlayıcı count alanı. 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 yaydığı sağlayıcılar öğeler uygulanmadan önce oluşturulur ve dondurulamaz ve emin olun. 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, hedef X'in bağımlılıkları arasında Y ve Z varsa A(X) için ctx.rule.attr.deps [A(Y), A(Z)] olur. Bu örnekte ctx.rule.attr.deps, özelliğin uygulandığı orijinal hedefin "deps"ine özelliğin uygulanmasının sonucu olan 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, ctx.attr.deps üzerinden FileCountInfo'e nasıl erişileceği gösterilmektedir.

Kural tanımı, bir parametrenin (extension) nasıl tanımlanacağını gösterir. ve varsayılan bir değer (*) belirleyin. Projenin gidişatı boyunca 'cc', 'h' veya '*' değerlerinden biri değildi en boy tanımındaki parametreye uygulanan kısıtlamalar.

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 parametresinin kuralının uygulanması yerine, 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.

Referanslar