Halaman ini membahas dasar-dasar penggunaan makro dan menyertakan kasus penggunaan, proses debug, dan konvensi umum.
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.
Makro hadir dalam dua ragam: makro simbolis yang dijelaskan di halaman ini, dan makro lama. Jika memungkinkan, sebaiknya gunakan makro simbolis untuk kejelasan kode.
Makro simbolis menawarkan argumen yang diketik (konversi string ke label, relatif terhadap tempat makro dipanggil) dan kemampuan untuk membatasi serta menentukan visibilitas target yang dibuat. Fungsi ini dirancang agar dapat menerima evaluasi
lambat (yang akan ditambahkan dalam rilis Bazel mendatang). Makro simbolis
tersedia secara default di Bazel 8. Jika dokumen ini menyebutkan macros
, dokumen tersebut
mengacu pada makro simbolis.
Penggunaan
Makro ditentukan dalam file .bzl
dengan memanggil fungsi macro()
dengan dua
parameter: attrs
dan implementation
.
Atribut
attrs
menerima kamus nama atribut ke jenis
atribut, yang mewakili
argumen ke makro. Dua atribut umum - nama dan visibilitas - secara implisit ditambahkan ke semua makro dan tidak disertakan dalam kamus yang diteruskan ke
attrs.
# 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,
)
Deklarasi jenis atribut menerima
parameter,
mandatory
, default
, dan doc
. Sebagian besar jenis atribut juga menerima
parameter configurable
, yang menentukan apakah atribut menerima
select
. Jika atribut adalah configurable
, atribut tersebut akan mengurai nilai non-select
sebagai select
yang tidak dapat dikonfigurasi - "foo"
akan menjadi
select({"//conditions:default": "foo"})
. Pelajari lebih lanjut di pilihan.
Penerapan
implementation
menerima fungsi yang berisi logika makro.
Fungsi implementasi sering membuat target dengan memanggil satu atau beberapa aturan, dan
biasanya bersifat pribadi (diberi nama dengan garis bawah di awal). Secara konvensional,
namanya sama dengan makronya, tetapi diawali dengan _
dan diakhiri dengan
_impl
.
Tidak seperti fungsi penerapan aturan, yang menggunakan satu argumen (ctx
) yang
berisi referensi ke atribut, fungsi penerapan makro menerima
parameter untuk setiap argumen.
# 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,
)
Pernyataan
Makro dideklarasikan dengan memuat dan memanggil definisinya dalam file BUILD
.
# pkg/BUILD
my_macro(
name = "macro_instance",
deps = ["src.cc"] + select(
{
"//config_setting:special": ["special_source.cc"],
"//conditions:default": [],
},
),
create_tests = True,
)
Tindakan ini akan membuat target
//pkg:macro_instance_cc_lib
dan//pkg:macro_instance_test
.
Detail
konvensi penamaan untuk target yang dibuat
Nama target atau submakro apa pun yang dibuat oleh makro simbolis harus
cocok dengan parameter name
makro atau harus diawali dengan name
diikuti
dengan _
(lebih disukai), .
, atau -
. Misalnya, my_macro(name = "foo")
hanya boleh
membuat file atau target bernama foo
, atau diawali dengan foo_
, foo-
, atau foo.
,
misalnya, foo_bar
.
Target atau file yang melanggar konvensi penamaan makro dapat dideklarasikan, tetapi tidak dapat di-build dan tidak dapat digunakan sebagai dependensi.
File dan target non-makro dalam paket yang sama seperti instance makro tidak boleh memiliki nama yang bertentangan dengan nama target makro potensial, meskipun eksklusivitas ini tidak diterapkan. Kami sedang dalam proses menerapkan evaluasi lambat sebagai peningkatan performa untuk makro Simbolik, yang akan terganggu dalam paket yang melanggar skema penamaan.
batasan
Makro simbolis memiliki beberapa batasan tambahan dibandingkan dengan makro lama.
Makro simbolis
- harus menggunakan argumen
name
dan argumenvisibility
- harus memiliki fungsi
implementation
- mungkin tidak menampilkan nilai
- tidak boleh memutasi
args
- tidak boleh memanggil
native.existing_rules()
kecuali jika merupakan makrofinalizer
khusus - tidak boleh memanggil
native.package()
- mungkin tidak memanggil
glob()
- mungkin tidak memanggil
native.environment_group()
- harus membuat target yang namanya mematuhi skema penamaan
- tidak dapat merujuk ke file input yang tidak dideklarasikan atau diteruskan sebagai argumen (lihat visibilitas untuk mengetahui detail selengkapnya).
Visibilitas
TODO: Luaskan bagian ini
Visibilitas target
Secara default, target yang dibuat oleh makro simbolis dapat dilihat oleh paket tempat
target tersebut dibuat. Atribut ini juga menerima atribut visibility
, yang dapat
memperluas visibilitas tersebut kepada pemanggil makro (dengan meneruskan atribut visibility
langsung dari panggilan makro ke target yang dibuat) dan ke paket
lain (dengan menentukannya secara eksplisit dalam visibilitas target).
Visibilitas dependensi
Makro harus memiliki visibilitas ke file dan target yang dirujuknya. Mereka dapat melakukannya dengan salah satu cara berikut:
- Ditetapkan secara eksplisit sebagai nilai
attr
ke makro
# pkg/BUILD
my_macro(... deps = ["//other_package:my_tool"] )
- Default implisit dari nilai
attr
# my_macro:macro.bzl
my_macro = macro(
attrs = {"deps" : attr.label_list(default = ["//other_package:my_tool"])} )
- Sudah terlihat oleh definisi makro
# other_package/BUILD
cc_binary(
name = "my_tool",
visibility = "//my_macro:\\__pkg__",
)
Memilih
Jika atribut adalah configurable
, fungsi penerapan makro akan
selalu melihat nilai atribut sebagai nilai select
. Misalnya, pertimbangkan
makro berikut:
my_macro = macro(
attrs = {"deps": attr.label_list()}, # configurable unless specified otherwise
implementation = _my_macro_impl,
)
Jika my_macro
dipanggil dengan deps = ["//a"]
, hal itu akan menyebabkan _my_macro_impl
dipanggil dengan parameter deps
-nya ditetapkan ke select({"//conditions:default":
["//a"]})
.
Target aturan membalikkan transformasi ini, dan menyimpan select
biasa sebagai nilai tanpa syaratnya; dalam contoh ini, jika _my_macro_impl
mendeklarasikan target aturan my_rule(..., deps = deps)
, deps
target aturan tersebut akan disimpan sebagai ["//a"]
.
Finalizer
Penyelesaian aturan adalah makro simbolis khusus yang - terlepas dari posisi leksikalnya dalam file BUILD - dievaluasi pada tahap akhir pemuatan paket, setelah semua target non-finalizer ditentukan. Tidak seperti makro simbolis
biasa, finalisasi dapat memanggil native.existing_rules()
, yang berperilaku
sedikit berbeda dengan makro lama: hanya menampilkan kumpulan
target aturan non-finalisasi. Penyelesaian dapat menyatakan status set tersebut atau menentukan target baru.
Untuk mendeklarasikan finaler, panggil macro()
dengan finalizer = True
:
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,
)
Kemalasan
PENTING: Kami sedang dalam proses menerapkan perluasan dan evaluasi makro lambat. Fitur ini belum tersedia.
Saat ini, semua makro dievaluasi segera setelah file BUILD dimuat, yang dapat berdampak negatif pada performa untuk target dalam paket yang juga memiliki makro yang tidak terkait dan mahal. Ke depannya, makro simbolis non-finalizer hanya akan dievaluasi jika diperlukan untuk build. Skema penamaan awalan membantu Bazel menentukan makro mana yang akan diperluas berdasarkan target yang diminta.
Pemecahan masalah migrasi
Berikut adalah beberapa masalah umum terkait migrasi dan cara memperbaikinya.
- Panggilan makro lama
glob()
Pindahkan panggilan glob()
ke file BUILD Anda (atau ke makro lama yang dipanggil dari
file BUILD), dan teruskan nilai glob()
ke makro simbolis menggunakan
atribut daftar label:
# BUILD file
my_macro(
...,
deps = glob(...),
)
- Makro lama memiliki parameter yang bukan jenis
attr
starlark yang valid.
Tarik sebanyak mungkin logika ke dalam makro simbolik bertingkat, tetapi pertahankan makro tingkat atas sebagai makro lama.
- Makro lama memanggil aturan yang membuat target yang melanggar skema penamaan
Tidak apa-apa, jangan bergantung pada target "yang menyinggung". Pemeriksaan penamaan akan diabaikan secara diam-diam.