Halaman ini membahas dasar-dasar penggunaan makro dan mencakup kasus penggunaan umum, {i>debugging<i}, dan konvensi.
Makro adalah fungsi yang dipanggil dari file BUILD
yang dapat membuat instance aturan.
Makro terutama digunakan untuk enkapsulasi dan penggunaan kembali kode dari aturan yang ada
dan makro lainnya. Pada akhir
fase pemuatan, makro tidak ada lagi,
dan Bazel hanya melihat seperangkat
konkret aturan yang dibuat instance-nya.
Penggunaan
Kasus penggunaan umum untuk makro adalah saat Anda ingin menggunakan kembali aturan.
Misalnya, genrule di file BUILD
menghasilkan file menggunakan
//:generator
dengan argumen some_arg
yang di-hardcode dalam perintah:
genrule(
name = "file",
outs = ["file.txt"],
cmd = "$(location //:generator) some_arg > $@",
tools = ["//:generator"],
)
Jika Anda ingin membuat lebih banyak file dengan argumen yang berbeda, Anda mungkin perlu
mengekstrak kode ini ke fungsi makro. Sebut saja makro file_generator
, yang
memiliki parameter name
dan arg
. Ganti genrule dengan kode berikut:
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",
)
Di sini, Anda memuat simbol file_generator
dari file .bzl
yang berada
dalam paket //path
. Dengan menempatkan definisi fungsi makro secara terpisah
.bzl
, Anda akan menjaga file BUILD
tetap bersih dan deklaratif, .bzl
file dapat dimuat dari paket
apa pun di ruang kerja.
Terakhir, di path/generator.bzl
, tulis definisi makro ke
mengenkapsulasi dan membuat parameter definisi genrule asli:
def file_generator(name, arg, visibility=None):
native.genrule(
name = name,
outs = [name + ".txt"],
cmd = "$(location //:generator) %s > $@" % arg,
tools = ["//:generator"],
visibility = visibility,
)
Anda juga dapat menggunakan makro untuk merangkai aturan bersama-sama. Contoh ini menunjukkan model genrules, di mana genrule menggunakan output dari genrule sebelumnya sebagai input:
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,
)
Contoh ini hanya menetapkan nilai visibilitas ke genrule kedua. Hal ini memungkinkan penulis makro untuk menyembunyikan output aturan perantara agar tidak diandalkan oleh target lain di ruang kerja.
Makro yang diperluas
Jika Anda ingin menyelidiki fungsi makro, gunakan perintah query
dengan
--output=build
untuk melihat formulir yang diperluas:
$ 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 > $@",
)
Membuat instance aturan native
Aturan native (aturan yang tidak memerlukan pernyataan load()
) dapat
dibuat instance-nya dari modul native:
def my_macro(name, visibility=None):
native.cc_library(
name = name,
srcs = ["main.cc"],
visibility = visibility,
)
Jika Anda perlu mengetahui nama paket (misalnya, file BUILD
mana yang memanggil
makro), gunakan fungsi native.package_name().
Perhatikan bahwa native
hanya dapat digunakan dalam file .bzl
, bukan dalam file BUILD
.
Resolusi label dalam makro
Karena makro dievaluasi pada fase pemuatan,
string label seperti "//foo:bar"
yang terjadi dalam makro ditafsirkan
relatif terhadap file BUILD
tempat makro digunakan, bukan relatif
file .bzl
tempat file ditentukan. Perilaku ini umumnya tidak diinginkan
untuk makro yang dimaksudkan untuk digunakan di repositori lain, seperti karena
merupakan bagian dari seperangkat aturan Starlark yang diterbitkan.
Untuk mendapatkan perilaku yang sama seperti aturan Starlark, gabungkan string label dengan
Konstruktor Label
:
# @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,
)
Proses Debug
bazel query --output=build //my/path:all
akan menunjukkan bagaimana fileBUILD
memperhatikan evaluasi. Semua makro, glob, loop diperluas. Diketahui batasan: ekspresiselect
saat ini tidak ditampilkan dalam output.Anda dapat memfilter output berdasarkan
generator_function
(fungsi yang membuat aturan) ataugenerator_name
(atribut nama makro):bash $ bazel query --output=build 'attr(generator_function, my_macro, //my/path:all)'
Untuk mengetahui di mana tepatnya aturan
foo
dibuat dalam fileBUILD
, Anda dapat mencoba trik berikut. Sisipkan baris ini di dekat bagian atasBUILD
file:cc_library(name = "foo")
. Jalankan Bazel. Anda akan mendapatkan pengecualian jika aturanfoo
dibuat (karena konflik nama), yang akan menunjukkan kepada Anda pelacakan tumpukan penuh.Anda juga dapat menggunakan print untuk proses debug. Menampilkan pesan sebagai baris log
DEBUG
selama fase pemuatan. Kecuali jarang kasus, baik menghapus panggilanprint
, atau menjadikannya kondisional dalam Parameterdebugging
yang ditetapkan secara default keFalse
sebelum mengirimkan kode ke ke depot.
Error
Jika Anda ingin menampilkan error, gunakan fungsi fail.
Jelaskan dengan jelas kepada pengguna apa yang salah dan cara memperbaiki file BUILD
mereka.
Error tidak dapat ditemukan.
def my_macro(name, deps, visibility=None):
if len(deps) < 2:
fail("Expected at least two values in deps")
# ...
Konvensi
Semua fungsi publik (fungsi yang tidak dimulai dengan garis bawah) yang Aturan pembuatan instance harus memiliki argumen
name
. Argumen ini tidak boleh opsional (jangan berikan nilai default).Fungsi publik harus menggunakan docstring setelah Python yang sesuai.
Dalam file
BUILD
, argumenname
dari makro harus berupa kata kunci (bukan argumen posisi).Atribut
name
aturan yang dihasilkan oleh makro harus menyertakan nama sebagai awalan. Misalnya,macro(name = "foo")
dapat membuatcc_library
foo
dan genrulefoo_gen
.Pada umumnya, parameter opsional harus memiliki nilai default
None
.None
dapat diteruskan langsung ke aturan native, yang memperlakukannya sama seperti jika Anda tidak menyampaikan argumen apa pun. Dengan demikian, tidak perlu menggantinya dengan0
,False
, atau[]
untuk tujuan ini. Sebaliknya, makro harus menunda pada aturan yang dibuatnya, karena nilai defaultnya mungkin rumit atau dapat berubah baik. Selain itu, parameter yang secara eksplisit ditetapkan ke nilai defaultnya terlihat berbeda dari yang tidak pernah ditetapkan (atau ditetapkan keNone
) saat diakses melalui bahasa kueri atau {i>build-system internal<i}.Makro harus memiliki argumen
visibility
opsional.