Makrolar

Bu sayfada, makroların kullanımıyla ilgili temel bilgiler, tipik kullanım alanları, hata ayıklama ve kurallar ele alınmaktadır.

Makro, BUILD dosyasından çağrılan ve kuralları örnekleyebilen bir işlevdir. Makrolar, temel olarak mevcut kuralların ve diğer makroların sarmalanması ve kodlarının yeniden kullanılması için kullanılır.

Makrolar iki şekilde sunulur: Bu sayfada açıklanan sembolik makrolar ve eski makrolar. Mümkün olduğunda kod netliği için sembolik makrolar kullanmanızı öneririz.

Sembolik makrolar, yazılmış bağımsız değişkenler (makronun çağrıldığı yere göre dize etiketi dönüşümü) ve oluşturulan hedeflerin görünürlüğünü kısıtlama ve belirtme olanağı sunar. Bunlar, tembel değerlendirmeye uygun olacak şekilde tasarlanmıştır (gelecekteki bir Bazel sürümünde eklenecektir). Sembolik makrolar, Bazel 8'de varsayılan olarak kullanılabilir. Bu belgede macros ifadesi, sembolik makrolar anlamına gelir.

Kullanım

Makrolar, macro() işlevi iki parametreyle (attrs ve implementation) çağrılarak .bzl dosyalarında tanımlanır.

Özellikler

attrs, makronun bağımsız değişkenlerini temsil eden özellik adı ile özellik türleri arasındaki bir sözlük kabul eder. İki ortak özellik (ad ve görünürlük), tüm makrolara dolaylı olarak eklenir ve katılımcılara iletilen sözlüğe dahil edilmez.

# macro/macro.bzl
my_macro = macro(
    attrs = {
        "deps": attr.label_list(mandatory = True, doc = "The dependencies passed to the inner cc_binary and cc_test targets"),
        "create_test": attr.bool(default = False, configurable = False, doc = "If true, creates a test target"),
    },
    implementation = _my_macro_impl,
)

Özellik türü bildirimleri mandatory, default ve doc parametrelerini kabul eder. Çoğu özellik türü, özelliğin select kabul edip etmediğini belirleyen configurable parametresini de kabul eder. Bir özellik configurable ise select olmayan değerler, yapılandırılabilir olmayan bir select olarak ayrıştırılır. "foo", select({"//conditions:default": "foo"}) olur. Daha fazla bilgiyi seçimler bölümünde bulabilirsiniz.

Uygulama

implementation, makronun mantığını içeren bir işlevi kabul eder. Uygulama işlevleri genellikle bir veya daha fazla kuralı çağırarak hedef oluşturur ve genellikle özeldir (başında alt çizgiyle adlandırılır). Geleneksel olarak, makrolarıyla aynı ada sahiptirler ancak önlerine _, sonlarına ise _impl eklenir.

Özelliklere başvuru içeren tek bir bağımsız değişken (ctx) alan kural uygulama işlevlerinin aksine, makro uygulama işlevleri her bağımsız değişken için bir parametreyi kabul eder.

# macro/macro.bzl
def _my_macro_impl(name, deps, create_test):
    cc_library(
        name = name + "_cc_lib",
        deps = deps,
    )

    if create_test:
        cc_test(
            name = name + "_test",
            srcs = ["my_test.cc"],
            deps = deps,
        )

Bildirim

Makrolar, tanımları bir BUILD dosyasına yükleyerek ve çağırarak bildirilir.


# pkg/BUILD

my_macro(
    name = "macro_instance",
    deps = ["src.cc"] + select(
        {
            "//config_setting:special": ["special_source.cc"],
            "//conditions:default": [],
        },
    ),
    create_tests = True,
)

Bu işlem, //pkg:macro_instance_cc_lib ve//pkg:macro_instance_test hedeflerini oluşturur.

Ayrıntılar

Oluşturulan hedefler için adlandırma kuralları

Sembolik bir makro tarafından oluşturulan hedeflerin veya alt makroların adları, makronun name parametresiyle eşleşmeli ya da name ile başlamalı ve ardından _ (tercih edilen), . veya - gelmelidir. Örneğin, my_macro(name = "foo") yalnızca foo adlı veya foo_, foo- ya da foo. ön ekiyle başlayan dosyalar veya hedefler (ör. foo_bar) oluşturabilir.

Makro adlandırma kuralını ihlal eden hedefler veya dosyalar tanımlanabilir ancak derlenemez ve bağımlılık olarak kullanılamaz.

Makro örneğiyle aynı paketteki makro dışı dosya ve hedeflerin adları, olası makro hedef adlarıyla çakışmamalıdır ancak bu münhasırlık zorunlu kılınmaz. Sembolik makrolar için performans iyileştirmesi olarak tembel değerlendirme özelliğini uygulama sürecindeyiz. Bu özellik, adlandırma şemasını ihlal eden paketlerde bozulacaktır.

kısıtlamalar

Sembolik makrolar, eski makrolara kıyasla bazı ek kısıtlamalara sahiptir.

Sembolik makrolar

  • bir name bağımsız değişkeni ve bir visibility bağımsız değişkeni almalıdır
  • implementation işlevi olmalıdır
  • değer döndürmeyebilir
  • args
  • özel finalizer makroları değilse native.existing_rules() işlevini çağıramazlar
  • native.package() araması yapılamaz
  • glob()'yi arayamaz
  • native.environment_group()'yi arayamaz
  • Adları adlandırma şemasına uygun olan hedefler oluşturmalıdır.
  • Tanımlanmamış veya bağımsız değişken olarak iletilmemiş giriş dosyalarına referans veremez (daha fazla bilgi için görünürlük bölümüne bakın).

Görünürlük

TODO: Bu bölümü genişletin

Hedef görünürlük

Varsayılan olarak, sembolik makrolar tarafından oluşturulan hedefler oluşturuldukları paket tarafından görülebilir. Ayrıca, bu görünürlüğü makroyu çağıran kullanıcıya (visibility özelliğini doğrudan makro çağrısından oluşturulan hedefe ileterek) ve diğer paketlere (hedefin görünürlüğünde açıkça belirterek) genişletebilecek bir visibility özelliği de kabul ederler.

Bağımlılık görünürlüğü

Makrolar, ifade ettikleri dosyaları ve hedefleri kolayca görebilmelidir. Bunu aşağıdaki yöntemlerden biriyle yapabilir:

  • Açıkça makroya attr değeri olarak aktarıldı

# pkg/BUILD
my_macro(... deps = ["//other_package:my_tool"] )
  • attr değerinin dolaylı varsayılan değeri
# my_macro:macro.bzl
my_macro = macro(
  attrs = {"deps" : attr.label_list(default = ["//other_package:my_tool"])} )
  • Makro tanımında zaten görünür
# other_package/BUILD
cc_binary(
    name = "my_tool",
    visibility = "//my_macro:\\__pkg__",
)

Seçimler

Özellik configurable ise makro uygulama işlevi özellik değerini her zaman select değerli olarak görür. Örneğin, aşağıdaki makroyu inceleyin:

my_macro = macro(
    attrs = {"deps": attr.label_list()},  # configurable unless specified otherwise
    implementation = _my_macro_impl,
)

my_macro, deps = ["//a"] ile çağrılırsa _my_macro_impl, deps parametresi select({"//conditions:default": ["//a"]}) olarak ayarlanmış şekilde çağrılır.

Kural hedefleri bu dönüşümü tersine çevirir ve önemsiz select'leri koşulsuz değerleri olarak depolar. Bu örnekte, _my_macro_impl bir kural hedefi my_rule(..., deps = deps) tanımlarsa bu kural hedefinin deps değeri ["//a"] olarak depolanır.

Sonlandırıcılar

Kural sonlandırıcı, özel bir sembolik makrodur. BUILD dosyasındaki sözlük konumu ne olursa olsun, sonlandırıcı olmayan tüm hedefler tanımlandıktan sonra paket yüklemenin son aşamasında değerlendirilir. Sıradan sembolik makrolardan farklı olarak, sonlandırıcı native.existing_rules() öğesini çağırabilir. Burada, eski makrolardan biraz farklı davranır: Yalnızca nihai olmayan kural hedefleri grubunu döndürür. Sonlandırıcı, bu kümenin durumu hakkında iddiada bulunabilir veya yeni hedefler tanımlayabilir.

Bir sonlandırıcıyı beyan etmek için finalizer = True ile macro()'ü çağırın:

def _my_finalizer_impl(name, visibility, tags_filter):
    for r in native.existing_rules().values():
        for tag in r.get("tags", []):
            if tag in tags_filter:
                my_test(
                    name = name + "_" + r["name"] + "_finalizer_test",
                    deps = [r["name"]],
                    data = r["srcs"],
                    ...
                )
                continue

my_finalizer = macro(
    attrs = {"tags_filter": attr.string_list(configurable = False)},
    implementation = _impl,
    finalizer = True,
)

Tembellik

ÖNEMLİ: Tembel makro genişletmeyi ve değerlendirmeyi uygulama sürecindeyiz. Bu özellik henüz kullanıma sunulmadı.

Şu anda tüm makrolar, BUILD dosyası yüklendikten hemen sonra değerlendirilir. Bu durum, maliyetli ve alakasız makroların da bulunduğu paketlerdeki hedeflerin performansını olumsuz yönde etkileyebilir. Gelecekte, nihaileştirici olmayan sembolik makrolar yalnızca derleme için gerekliyse değerlendirilecektir. Önek adlandırma şeması, istenen bir hedef verildiğinde Basel'in hangi makronun genişletileceğini belirlemesine yardımcı olur.

Taşımayla ilgili sorunları giderme

Taşımayla ilgili bazı yaygın sorunlar ve bunların nasıl düzeltileceği aşağıda açıklanmıştır.

  • Eski makro çağrıları glob()

glob() çağrısını BUILD dosyanıza (veya BUILD dosyasından çağrılan eski bir makroya) taşıyın ve glob() değerini bir etiket listesi özelliği kullanarak sembolik makroya iletin:

# BUILD file
my_macro(
    ...,
    deps = glob(...),
)
  • Eski makroda, geçerli bir starlark attr türü olmayan bir parametre var.

İç içe yerleştirilmiş sembolik bir makroya mümkün olduğunca fazla mantık çekin ancak üst düzey makroyu eski bir makroda tutun.

  • Eski makro, adlandırma şemasını ihlal eden bir hedef oluşturan bir kural çağırıyor

Sorun değil, "rahatsız edici" hedefe güvenmeyin. Adlandırma denetimi sessizce yoksayılır.