Eski Makrolar

Eski makrolar, BUILD dosyalarından çağrılan ve hedef oluşturabilen yapılandırılmamış işlevlerdir. Yükleme aşamasının sonunda eski makrolar artık mevcut değildir ve Bazel yalnızca somut olarak oluşturulmuş kurallar grubunu görür.

Eski makroları neden kullanmamalısınız (ve bunun yerine sembolik makroları neden kullanmalısınız)?

Mümkün olduğunda simge makroları kullanmalısınız.

Sembolik makrolar

  • Uzaktan işlem yapılmasını engelleme
  • Ayrıntılı görünürlük sayesinde uygulama ayrıntılarını gizleme olanağı sunma
  • Yazılı özellikleri kullanın. Bu, otomatik etiket ve dönüşüm seçmek anlamına gelir.
  • Daha okunaklı olmalıdır.
  • Yakında tembel değerlendirme özelliği eklenecek

Kullanım

Makroların tipik kullanım alanı, bir kuralı yeniden kullanmak istediğinizdedir.

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

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

Farklı bağımsız değişkenlerle daha fazla dosya oluşturmak istiyorsanız bu kodu bir makro işlevine ayıklamak isteyebilirsiniz. name ve arg parametrelerine sahip file_generator adlı bir makro oluşturmak için genrule'yi aşağıdakiyle değiştirebiliriz:

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, file_generator simgesini //path paketinde bulunan bir .bzl dosyasından yüklersiniz. Makro işlev tanımlarını ayrı bir .bzl dosyasına yerleştirerek BUILD dosyalarınızı temiz ve açıklayıcı tutarsınız. .bzl dosyası, çalışma alanındaki herhangi bir paketten yüklenebilir.

Son olarak, path/generator.bzl içinde orijinal genrule tanımını kapsayacak ve parametrelendirecek makro 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,
  )

Kuralları birbirine bağlamak için makroları da kullanabilirsiniz. Bu örnekte, bir genrule'un önceki bir genrule'ün çıkışlarını giriş olarak kullandığı zincirlenmiş genrule'ler 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,
  )

Örnekte yalnızca ikinci genrule için bir visibility değeri atanır. Bu sayede makro yazarları, ara kuralların çıktılarını çalışma alanındaki diğer hedeflerin bağımlı olduğu bir öğe olmaktan gizleyebilir.

Genişletilmiş makrolar

Bir makronun ne yaptığını incelemek istediğinizde genişletilmiş biçimini 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

Doğal kurallar (load() beyanı gerektirmeyen kurallar), native 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 işlevinin yalnızca .bzl dosyalarında kullanılabileceğini, BUILD dosyalarında kullanılamayacağını unutmayın.

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

Eski makrolar yükleme aşamasında değerlendirildiğinden, eski bir makroda bulunan "//foo:bar" gibi etiket dizeleri, tanımlandığı .bzl dosyasına göre değil, makronun kullanıldığı BUILD dosyasına göre yorumlanır. Bu davranış, yayınlanmış bir Starlark kural kümesinin parçası oldukları için diğer depolarda kullanılması amaçlanan makrolar için genellikle istenmez.

Starlark kurallarıyla aynı davranışı elde etmek için etiket dizelerini Label kurucusuyla 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 repo, 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, BUILD dosyasının değerlendirmeden sonra nasıl göründüğünü gösterir. Tüm eski makrolar, glob'lar ve döngüler genişletilir. Bilinen sınırlama: select ifadeleri çıktıda gösterilmez.

  • Çıktıyı generator_function (kuralları hangi işlevin oluşturduğu) veya generator_name'a (makronun ad özelliği) göre filtreleyebilirsiniz: bash $ bazel query --output=build 'attr(generator_function, my_macro, //my/path:all)'

  • foo kuralının bir BUILD dosyasında tam olarak nerede oluşturulduğunu öğrenmek için aşağıdaki numarayı deneyebilirsiniz. Aşağıdaki 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) tam yığın izlemeyi gösteren bir istisna alırsınız.

  • Hata ayıklama için print komutunu da kullanabilirsiniz. Yükleme aşamasında mesajı DEBUG günlük satırı olarak gösterir. Nadir durumlar hariç, kodu depoya göndermeden önce print çağrılarını kaldırın veya varsayılan olarak False olan bir debugging parametresi altında koşullu hale getirin.

Hatalar

Hata atmak istiyorsanız fail işlevini kullanın. Kullanıcıya neyin yanlış gittiğini ve BUILD dosyasını nasıl düzelteceğini açıklayın. Hata yakalamak mümkün değildir.

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

Kongreler

  • Kuralları örnekleyen tüm herkese açık işlevler (alt çizgiyle başlamayan işlevler) bir name bağımsız değişkenine sahip 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 açıklama metni kullanmalıdır.

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

  • 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 genrule foo_gen oluşturabilir.

  • Çoğu durumda, isteğe bağlı parametrelerin varsayılan değeri None olmalıdır. None doğrudan yerel kurallara iletilebilir. Bu durumda, herhangi bir bağımsız değişken iletmemişsiniz gibi değerlendirilir. Bu nedenle, bu amaç için 0, False veya [] ile değiştirmeniz gerekmez. Bunun yerine, varsayılan değerleri karmaşık olabileceği veya zaman içinde değişebileceği için makro, oluşturduğu kurallara göre işlem yapmalıdır. Ayrıca, varsayılan değerine açıkça ayarlanmış bir parametre, sorgu dili veya derleme sistemi dahili aracılığıyla erişildiğinde hiç ayarlanmamış (veya None olarak ayarlanmış) bir parametreden farklı görünür.

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