Eski makrolar, hedef oluşturabilen BUILD dosyalarından çağrılan yapılandırılmamış işlevlerdir. Yükleme aşamasının sonunda eski makrolar artık mevcut değildir ve Bazel yalnızca oluşturulan kuralların somut kümesini görür.
Neden eski makroları kullanmamalı (ve bunun yerine sembolik makroları kullanmalısınız)
Mümkün olduğunda sembolik 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ılan özellikleri alır. Bu da otomatik etiketleme ve dönüşüm seçimi anlamına gelir.
- Daha okunabilir olmalıdır.
- Yakında tembel değerlendirme özelliği eklenecek.
Kullanım
Makroların tipik kullanım alanı, bir kuralı yeniden kullanmak istediğiniz durumlardır.
Örneğin, BUILD dosyasındaki genrule, komuta sabit kodlanmış bir some_arg bağımsız değişkeniyle //: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şkenlere sahip daha fazla dosya oluşturmak istiyorsanız bu kodu bir makro işlevine ayıklayabilirsiniz. file_generator adlı bir makro oluşturmak için name ve arg parametrelerini kullanabiliriz. Bu durumda, genrule'u 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, //path paketinde bulunan bir .bzl dosyasından file_generator simgesini yüklersiniz. Makro işlevi tanımlarını ayrı bir .bzl
dosyaya yerleştirerek BUILD dosyalarınızı temiz ve bildirimsel tutarsınız. .bzl dosyası, çalışma alanındaki herhangi bir paketten yüklenebilir.
Son olarak, path/generator.bzl bölümünde, orijinal genrule tanımını kapsayacak ve parametrelendirecek şekilde 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,
)
Kuralları birbirine bağlamak için makroları da kullanabilirsiniz. Bu örnekte, bir genrule'un önceki bir genrule'un çıkışlarını giriş olarak kullandığı zincirlenmiş genrule'lar 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 nesil kurala görünürlük değeri atanır. Bu, makro yazarların ara kuralların çıkışlarını, çalışma alanındaki diğer hedefler tarafından kullanılmaktan gizlemesine olanak tanır.
Genişletme makroları
Bir makronun ne yaptığını araştırmak istediğinizde genişletilmiş biçimi 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ı başlatma
Yerel kurallar (load() ifadesi gerektirmeyen kurallar) native modülünden başlatılabilir:
def my_macro(name, visibility=None):
native.cc_library(
name = name,
srcs = ["main.cc"],
visibility = visibility,
)
Paket adını (ör. hangi BUILD dosyasının makroyu çağırdığını) bilmeniz gerekiyorsa native.package_name() işlevini kullanın. native yalnızca .bzl dosyalarında kullanılabilir, BUILD dosyalarında kullanılamaz.
Makrolarda etiket çözümü
Eski makrolar yükleme aşamasında değerlendirildiğinden, eski bir makroda bulunan "//foo:bar" gibi etiket dizeleri, makronun 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ı olmaları gibi nedenlerle diğer depolarda kullanılmak üzere tasarlanan makrolar için genellikle istenmeyen bir durumdur.
Starlark kurallarında olduğu gibi 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 repo, such as due to repo mappings.
Label("@dep_of_my_ruleset//tools:foo"),
],
"//conditions:default": [],
}),
**kwargs,
)
--incompatible_resolve_select_keys_eagerly işareti etkinleştirildiğinde, etiket dizeleri olan tüm anahtarlar, select çağrısını içeren dosyanın paketine göre otomatik olarak Label nesnelerine dönüştürülür. Bu seçenek belirlenmezse etiket dizesini native.package_relative_label() ile sarmalayın.
Hata ayıklama
bazel query --output=build //my/path:all,BUILDdosyasının değerlendirmeden sonra nasıl göründüğünü gösterir. Tüm eski makrolar, globlar ve döngüler genişletilir. Bilinen sınırlama:selectifadeleri çıkışta gösterilmez.Çıkışı
generator_function(kuralları hangi işlevin oluşturduğu) veyagenerator_name(makronun ad özelliği) temelinde filtreleyebilirsiniz:bash $ bazel query --output=build 'attr(generator_function, my_macro, //my/path:all)'fookuralınınBUILDdosyasında tam olarak nerede oluşturulduğunu öğrenmek için aşağıdaki yöntemi deneyebilirsiniz. Bu satırıBUILDdosyasının üst kısmına yakın bir yere ekleyin:cc_library(name = "foo"). Bazel'i çalıştırın. Kuralfoooluşturulduğunda (ad çakışması nedeniyle) tam yığın izini gösteren bir istisna alırsınız.Hata ayıklama için print işlevini de kullanabilirsiniz. Yükleme aşamasında iletiyi
DEBUGgünlük satırı olarak gösterir. Nadiren görülen durumlar dışında, kodu depoya göndermeden önceprintçağrılarını kaldırın veyaFalsevarsayılan değerine sahip birdebuggingparametresi altında koşullu hale getirin.
Hatalar
Hata oluşturmak istiyorsanız fail işlevini kullanın. Kullanıcıya neyin yanlış gittiğini ve dosyasını nasıl düzelteceğini net bir şekilde açıklayın.BUILD 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 genel işlevler (alt çizgiyle başlamayan işlevler) bir
namebağı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 docstring kullanmalıdır.
BUILDdosyalarında, makrolarınnamebağımsız değişkeni bir anahtar kelime bağımsız değişkeni (konum bağımsız değişkeni değil) olmalıdır.Makro tarafından oluşturulan kuralların
nameözelliği, ad bağımsız değişkenini önek olarak içermelidir. Örneğin,macro(name = "foo"),cc_libraryfoove genrulefoo_genoluşturabilir.Çoğu durumda, isteğe bağlı parametrelerin varsayılan değeri
Noneolmalıdır.None, herhangi bir bağımsız değişken iletmemişsiniz gibi davranan yerel kurallara doğrudan iletilebilir. Bu nedenle, bu amaçla0,Falseveya[]ile değiştirmenize gerek yoktur. Bunun yerine, varsayılan değerleri karmaşık olabileceğinden veya zaman içinde değişebileceğinden makro, oluşturduğu kurallara uymalıdır. Ayrıca, varsayılan değerine açıkça ayarlanmış bir parametre, sorgu dili veya derleme sistemi iç kısımları üzerinden erişildiğinde hiç ayarlanmamış (veyaNoneolarak ayarlanmış) bir parametreden farklı görünür.Makrolarda isteğe bağlı bir
visibilitybağımsız değişkeni olmalıdır.