Makrolar

Sorun bildirin Kaynağı göster

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ı örneklendirebilen bir işlevdir. Makrolar, çoğunlukla mevcut kurallar ile diğer makroların kapsüllenmesi ve yeniden kullanılması için kullanılır. Yükleme aşamasının sonunda makrolar artık mevcut değildir ve Bazel yalnızca örneklenmiş, somut kurallar kümesini görür.

Kullanım

Makroların tipik kullanım alanı, kuralı yeniden kullanmak istediğiniz durumlardır.

Örneğin, BUILD dosyasındaki genrule, //:generator komutunu kullanarak some_arg bağımsız değişkenini komuta sabitlemiş bir dosya oluşturur:

genrule(
    name = "file",
    outs = ["file.txt"],
    cmd = "$(location //:generator) some_arg > $@",
    tools = ["//:generator"],
)

Farklı bağımsız bağımsız değişkenlere sahip daha fazla dosya oluşturmak istiyorsanız bu kodu bir makro işlevine çıkartmak isteyebilirsiniz. name ve arg parametrelerine sahip olan file_generator makrosuna diyelim. Genrule'ı şununla değiştirin:

load("//path:generator.bzl", "file_generator")

file_generator(
    name = "file",
    arg = "some_arg",
)

file_generator(
    name = "file-two",
    arg = "some_arg_two",
)

file_generator(
    name = "file-three",
    arg = "some_arg_three",
)

Burada, //path paketinde bulunan bir .bzl dosyasından file_generator simgesini yüklersiniz. Makro işlevi tanımlarını ayrı bir .bzl dosyasına koyarak BUILD dosyalarınızın temiz ve bildirim temelli olmasını sağlarsınız. .bzl dosyası, çalışma alanındaki herhangi bir paketten yüklenebilir.

Son olarak, path/generator.bzl dilinde, orijinal genrule tanımını kapsüllemek ve parametreleştirmek için makronun tanımını yazın:

def file_generator(name, arg, visibility=None):
  native.genrule(
    name = name,
    outs = [name + ".txt"],
    cmd = "$(location //:generator) %s > $@" % arg,
    tools = ["//:generator"],
    visibility = visibility,
  )

Makroları, kuralları birbirine bağlamak için de kullanabilirsiniz. Bu örnekte, bir genrule üyesinin önceki bir genrulenin çıkışlarını giriş olarak kullandığı zincirlenmiş genel kurallar gösterilmektedir:

def chained_genrules(name, visibility=None):
  native.genrule(
    name = name + "-one",
    outs = [name + ".one"],
    cmd = "$(location :tool-one) $@",
    tools = [":tool-one"],
    visibility = ["//visibility:private"],
  )

  native.genrule(
    name = name + "-two",
    srcs = [name + ".one"],
    outs = [name + ".two"],
    cmd = "$(location :tool-two) $< $@",
    tools = [":tool-two"],
    visibility = visibility,
  )

Örnek yalnızca ikinci nesile bir görünürlük değeri atar. Bu, makro yazarlarının ara kuralların çıkışlarının çalışma alanındaki diğer hedefler tarafından bağımlı kalmasının engellenmesini sağlar.

Genişletme makroları

Bir makronun işlevini incelemek istediğinizde, genişletilmiş formu görmek için query komutunu --output=build ile birlikte kullanın:

$ bazel query --output=build :file
# /absolute/path/test/ext.bzl:42:3
genrule(
  name = "file",
  tools = ["//:generator"],
  outs = ["//test:file.txt"],
  cmd = "$(location //:generator) some_arg > $@",
)

Yerel kuralları örneklendirme

Yerel kurallar (load() ifadesi gerektirmeyen kurallar) yerel modülünden oluşturulabilir:

def my_macro(name, visibility=None):
  native.cc_library(
    name = name,
    srcs = ["main.cc"],
    visibility = visibility,
  )

Paket adını (örneğin, makroyu hangi BUILD dosyasının çağırdığını) bilmeniz gerekiyorsa native.package_name() işlevini kullanın. native öğesinin yalnızca .bzl dosyalarında kullanılabileceğini, WORKSPACE veya BUILD dosyalarında kullanılamayacağını unutmayın.

Makrolarda etiket çözünürlüğü

Makrolar yükleme aşamasında değerlendirildiğinden, bir makroda oluşan "//foo:bar" gibi etiket dizeleri, makronun tanımlandığı .bzl dosyasına göre değil, makronun içinde kullanıldığı BUILD dosyasına göre yorumlanır. Bu davranış genellikle diğer depolarda kullanılması amaçlanan makrolar için (örneğin, yayınlanan bir Starlark kural grubunun parçası olmaları gibi) istenmeyen bir davranıştır.

Starlark kurallarıyla aynı davranışı elde etmek için etiket dizelerini Label oluşturucuyla sarmalayın:

# @my_ruleset//rules:defs.bzl
def my_cc_wrapper(name, deps = [], **kwargs):
  native.cc_library(
    name = name,
    deps = deps + select({
      # Due to the use of Label, this label is resolved within @my_ruleset,
      # regardless of its site of use.
      Label("//config:needs_foo"): [
        # Due to the use of Label, this label will resolve to the correct target
        # even if the canonical name of @dep_of_my_ruleset should be different
        # in the main workspace, such as due to repo mappings.
        Label("@dep_of_my_ruleset//tools:foo"),
      ],
      "//conditions:default": [],
    }),
    **kwargs,
  )

Hata ayıklama

  • bazel query --output=build //my/path:all, değerlendirmeden sonra BUILD dosyasının nasıl göründüğünü gösterir. Tüm makrolar, glob'lar, döngüler genişletilir. Bilinen sınırlama: Şu anda select ifadeleri çıkışta gösterilmemektedir.

  • Sonucu, kuralları oluşturan generator_function işlevine veya generator_name özelliğine (makronun ad özelliği) göre filtreleyebilirsiniz: bash $ bazel query --output=build 'attr(generator_function, my_macro, //my/path:all)'

  • foo kuralının BUILD dosyasında tam olarak nerede oluşturulduğunu öğrenmek için aşağıdaki işlemi deneyebilirsiniz. Bu satırı BUILD dosyasının üst kısmına yakın bir yere ekleyin: cc_library(name = "foo"). Bazel'i çalıştırın. foo kuralı oluşturulduğunda (ad çakışması nedeniyle) bir istisna alırsınız. Bu istisna size tam yığın izlemeyi gösterir.

  • Hata ayıklama için yazdırma yöntemini de kullanabilirsiniz. Yükleme aşamasında bu mesajı bir DEBUG günlük satırı olarak gösterir. Nadir durumlar dışında, print çağrılarını kaldırın veya kodu depoya göndermeden önce varsayılan olarak False değerine sahip bir debugging parametresi altında koşullu hale getirin.

Hatalar

Hata vermek istiyorsanız fail işlevini kullanın. Kullanıcıya sorunun ne olduğunu ve BUILD dosyasının nasıl düzeltileceğini net bir şekilde açıklayın. Hata yakalanamaz.

def my_macro(name, deps, visibility=None):
  if len(deps) < 2:
    fail("Expected at least two values in deps")
  # ...

Kongreler

  • Kural başlatan tüm herkese açık işlevler (alt çizgi ile başlamayan işlevler) için name bağımsız değişkeni olmalıdır. Bu bağımsız değişken isteğe bağlı olmamalıdır (varsayılan değer vermeyin).

  • Herkese açık işlevler, Python kurallarına uygun bir docstring kullanmalıdır.

  • BUILD dosyalarında, makroların name bağımsız değişkeni bir anahtar kelime bağımsız değişkeni olmalıdır (konumsal bağımsız değişken değil).

  • Bir makro tarafından oluşturulan kuralların name özelliği, ad bağımsız değişkenini ön ek olarak içermelidir. Örneğin, macro(name = "foo"), bir cc_library foo ve bir genel foo_gen oluşturabilir.

  • Çoğu durumda, isteğe bağlı parametreler için varsayılan değer None olmalıdır. None doğrudan yerel kurallara iletilebilir. Bu kurallar, herhangi bir bağımsız değişkeni geçmemişsiniz gibi davranır. Dolayısıyla, bu amaç için bu değeri 0, False veya [] ile değiştirmenize gerek yoktur. Varsayılan değerleri karmaşık olabileceğinden veya zaman içinde değişebileceğinden, makro bunun yerine oluşturduğu kurallara uyar. Ayrıca, açıkça varsayılan değerine ayarlanmış bir parametre, sorgu dili veya derleme sistemi dahili ayarlarından erişildiğinde hiçbir zaman ayarlanmayan (veya None olarak ayarlanmayan) bir parametreden farklı görünür.

  • Makroların isteğe bağlı bir visibility bağımsız değişkeni olmalıdır.