Trang này trình bày kiến thức cơ bản về cách sử dụng macro và các trường hợp sử dụng thông thường, gỡ lỗi và quy ước.
Macro là một hàm được gọi từ tệp BUILD
có thể tạo thực thể cho các quy tắc.
Macro chủ yếu được dùng để đóng gói và sử dụng lại mã của các quy tắc hiện có
và các macro khác. Đến cuối
giai đoạn tải, macro không còn tồn tại nữa
và Bazel chỉ thấy một tập hợp cụ thể các quy tắc được tạo thực thể.
Cách sử dụng
Trường hợp sử dụng điển hình cho macro là khi bạn muốn sử dụng lại quy tắc.
Ví dụ: quy tắc gen trong tệp BUILD
sẽ tạo ra một tệp sử dụng
//:generator
với đối số some_arg
được mã hoá cứng trong lệnh:
genrule(
name = "file",
outs = ["file.txt"],
cmd = "$(location //:generator) some_arg > $@",
tools = ["//:generator"],
)
Nếu muốn tạo thêm tệp chứa các đối số khác nhau, bạn có thể cần
trích xuất mã này vào hàm macro. Hãy gọi macro này là file_generator
.
có tham số name
và arg
. Thay thế quy tắc gen bằng quy tắc sau:
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",
)
Ở đây, bạn tải biểu tượng file_generator
từ một tệp .bzl
nằm
trong gói //path
. Bằng cách đặt các định nghĩa hàm macro trong một
.bzl
, bạn sẽ giữ cho các tệp BUILD
của mình luôn gọn gàng và mang tính khai báo, .bzl
có thể tải tệp từ bất kỳ gói nào trong không gian làm việc.
Cuối cùng, trong path/generator.bzl
, hãy ghi định nghĩa của macro vào
đóng gói và tham số hoá định nghĩa quy tắc tạo ban đầu:
def file_generator(name, arg, visibility=None):
native.genrule(
name = name,
outs = [name + ".txt"],
cmd = "$(location //:generator) %s > $@" % arg,
tools = ["//:generator"],
visibility = visibility,
)
Bạn cũng có thể sử dụng macro để liên kết các quy tắc với nhau. Ví dụ này cho thấy chuỗi genrules, trong đó một quy tắc tạo sử dụng dữ liệu đầu ra của một quy tắc tạo trước đó làm dữ liệu đầu vào:
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,
)
Ví dụ này chỉ chỉ định giá trị mức độ hiển thị cho quy tắc tạo sinh thứ hai. Điều này cho phép các tác giả vĩ mô để ẩn kết quả của các quy tắc trung gian khỏi bị phụ thuộc vào theo các mục tiêu khác trong không gian làm việc.
Macro mở rộng
Khi bạn muốn tìm hiểu chức năng của macro, hãy sử dụng lệnh query
với
--output=build
để xem biểu mẫu mở rộng:
$ 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 > $@",
)
Tạo thực thể quy tắc gốc
Các quy tắc gốc (quy tắc không cần câu lệnh load()
) có thể là
được tạo thực thể từ mô-đun gốc:
def my_macro(name, visibility=None):
native.cc_library(
name = name,
srcs = ["main.cc"],
visibility = visibility,
)
Nếu bạn cần biết tên gói (ví dụ: tệp BUILD
nào đang gọi phương thức
macro), hãy sử dụng hàm native.package_name().
Xin lưu ý rằng bạn chỉ có thể dùng native
trong các tệp .bzl
, chứ không thể dùng trong các tệp BUILD
.
Độ phân giải nhãn trong macro
Vì macro được đánh giá trong giai đoạn tải,
chuỗi nhãn, chẳng hạn như "//foo:bar"
xuất hiện trong macro sẽ được diễn giải
so với tệp BUILD
mà macro được sử dụng thay vì so với
.bzl
là tệp được xác định trong đó. Đây thường là hành vi không mong muốn
cho các macro được sử dụng trong các kho lưu trữ khác, chẳng hạn như vì chúng
đều thuộc bộ quy tắc Starlark đã xuất bản.
Để có hành vi tương tự như đối với quy tắc Starlark, hãy gói các chuỗi nhãn bằng
Hàm khởi tạo 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,
)
Gỡ lỗi
bazel query --output=build //my/path:all
sẽ cho bạn biết cách tệpBUILD
chăm sóc khách hàng. Tất cả macro, khối cầu và vòng lặp đều được mở rộng. Người quen giới hạn: biểu thứcselect
hiện không được hiển thị trong kết quả.Bạn có thể lọc kết quả dựa trên
generator_function
(hàm nào đã tạo quy tắc) hoặcgenerator_name
(thuộc tính tên của macro):bash $ bazel query --output=build 'attr(generator_function, my_macro, //my/path:all)'
Để tìm chính xác quy tắc
foo
được tạo ở đâu trong tệpBUILD
, bạn có thể thử thủ thuật sau. Chèn dòng này vào gần đầuBUILD
tệp:cc_library(name = "foo")
. Chạy Bazel. Bạn sẽ nhận được ngoại lệ khi quy tắcfoo
được tạo (do xung đột tên), quy tắc này sẽ hiển thị cho bạn toàn bộ dấu vết ngăn xếp.Bạn cũng có thể sử dụng print để gỡ lỗi. Chiến dịch hiển thị thông báo dưới dạng một dòng nhật ký
DEBUG
trong giai đoạn tải. Ngoại trừ một số ít trường hợp các trường hợp, hãy xoáprint
lệnh gọi hoặc đặt chúng thành có điều kiện trong Tham sốdebugging
mặc định làFalse
trước khi gửi mã đến kho hàng.
Lỗi
Nếu bạn muốn báo cáo lỗi, hãy sử dụng hàm fail (không thành công).
Giải thích rõ cho người dùng về lỗi và cách sửa tệp BUILD
.
Không thể phát hiện lỗi.
def my_macro(name, deps, visibility=None):
if len(deps) < 2:
fail("Expected at least two values in deps")
# ...
Hội nghị
Tất cả hàm công khai (các hàm không bắt đầu bằng dấu gạch dưới) mà tạo thực thể quy tắc phải có đối số
name
. Đối số này không được không bắt buộc (không cung cấp giá trị mặc định).Các hàm công khai phải dùng một chuỗi tài liệu theo Python quy ước.
Trong các tệp
BUILD
, đối sốname
của macro phải là một từ khoá đối số (không phải đối số vị trí).Thuộc tính
name
của quy tắc do macro tạo phải bao gồm tên đối số dưới dạng một tiền tố. Ví dụ:macro(name = "foo")
có thể tạo mộtcc_library
foo
và mộtfoo_gen
quy tắc tạo sinh.Trong hầu hết trường hợp, các tham số không bắt buộc phải có giá trị mặc định là
None
.None
có thể được chuyển trực tiếp đến các quy tắc gốc, các quy tắc này xử lý giống như thể mà bạn chưa truyền vào bất kỳ đối số nào. Do đó, bạn không cần phải thay thế với0
,False
hoặc[]
cho mục đích này. Thay vào đó, macro phải trì hoãn vào các quy tắc mà hệ thống tạo, vì cài đặt mặc định của chúng có thể phức tạp hoặc có thể thay đổi bất cứ lúc nào. Ngoài ra, một thông số được đặt rõ ràng thành giá trị mặc định trông khác với một giao diện không bao giờ được đặt (hoặc được đặt thànhNone
) khi được truy cập thông qua ngôn ngữ truy vấn hoặc thành phần bên trong hệ thống xây dựng.Macro phải có đối số
visibility
không bắt buộc.