Trang này trình bày các lợi ích cũng như cách sử dụng cơ bản cấu hình Starlark, API của Bazel để tuỳ chỉnh cách tạo dự án. Tài liệu này bao gồm cách xác định tạo bản dựng và cung cấp ví dụ.
Điều này giúp bạn có thể:
- xác định cờ tuỳ chỉnh cho dự án của mình, làm lỗi đó không cần đến
--define
- ghi
Transitions (quá trình chuyển đổi) để định cấu hình phần phụ thuộc trong
cấu hình khác với cấu hình của nhà xuất bản mẹ
(chẳng hạn như
--compilation_mode=opt
hoặc--cpu=arm
) - tích hợp các giá trị mặc định hiệu quả hơn vào các quy tắc (chẳng hạn như tự động tạo
//my:android_app
với một SDK được chỉ định)
và nhiều tính năng khác, tất cả hoàn toàn được tạo từ các tệp .bzl (không cần phát hành Bazel). Xem
Kho lưu trữ bazelbuild/examples
cho
ví dụ.
Chế độ cài đặt bản dựng do người dùng xác định
Cài đặt bản dựng là một phần
cấu hình
của bạn. Hãy xem cấu hình là một bản đồ khoá/giá trị. Đang cài đặt --cpu=ppc
và --copt="-DFoo"
tạo ra một cấu hình giống như
{cpu: ppc, copt: "-DFoo"}
. Mỗi mục nhập là một chế độ cài đặt bản dựng.
Cờ truyền thống như cpu
và copt
là chế độ cài đặt gốc —
khoá của chúng được xác định và giá trị của chúng được đặt bên trong mã java bazel gốc.
Người dùng Bazel chỉ có thể đọc và ghi thông qua dòng lệnh
và các API khác được duy trì tự nhiên. Thay đổi cờ gốc và API
để hiển thị chúng, đòi hỏi bạn phải phát hành bazel. Bản dựng do người dùng xác định
các chế độ cài đặt được xác định trong các tệp .bzl
(và do đó, bạn không cần bản phát hành bazel để
đăng ký). Bạn cũng có thể thiết lập thông qua dòng lệnh
(nếu chúng được chỉ định là flags
, hãy xem thêm thông tin bên dưới), nhưng cũng có thể
được đặt thông qua chuyển đổi do người dùng xác định.
Xác định chế độ cài đặt bản dựng
Tham số rule()
build_setting
Cài đặt bản dựng là các quy tắc giống như bất kỳ quy tắc nào khác và được phân biệt bằng cách sử dụng
build_setting
của hàm rule()
Starlark
thuộc tính.
# example/buildsettings/build_settings.bzl
string_flag = rule(
implementation = _impl,
build_setting = config.string(flag = True)
)
Thuộc tính build_setting
nhận một hàm chỉ định loại của
cài đặt bản dựng. Loại này được giới hạn ở một tập hợp các loại Starlark cơ bản như
bool
và string
. Xem mô-đun config
tài liệu để biết thông tin chi tiết. Việc nhập văn bản phức tạp hơn có thể là
thực hiện trong chức năng triển khai của quy tắc. Tìm hiểu thêm về nội dung này ở bên dưới.
Các hàm của mô-đun config
sẽ nhận tham số boolean không bắt buộc là flag
,
được đặt thành false theo mặc định. nếu bạn đặt flag
thành true, thì chế độ cài đặt bản dựng
có thể được đặt trên dòng lệnh bởi người dùng cũng như nội bộ bởi người viết quy tắc
thông qua các giá trị mặc định và hiệu ứng chuyển đổi.
Không phải người dùng nào cũng có thể đặt được tất cả các chế độ cài đặt. Ví dụ: nếu bạn với tư cách là một quy tắc
người viết có một số chế độ gỡ lỗi mà bạn muốn bật bên trong quy tắc kiểm thử,
bạn không muốn tạo điều kiện để người dùng bật ứng dụng đó một cách bừa bãi
bên trong các quy tắc không kiểm thử khác.
Sử dụng ctx.build_setting_value
Giống như tất cả các quy tắc, quy tắc cài đặt bản dựng cũng có hàm triển khai.
Bạn có thể truy cập giá trị kiểu Starlark cơ bản của chế độ cài đặt bản dựng qua
ctx.build_setting_value
. Phương thức này chỉ dành cho
Đối tượng ctx
của quy tắc cài đặt bản dựng. Các cách triển khai này
có thể chuyển tiếp trực tiếp giá trị cài đặt bản dựng hoặc thực hiện thêm thao tác trên
chẳng hạn như kiểm tra loại hoặc tạo cấu trúc phức tạp hơn. Sau đây là cách
triển khai chế độ cài đặt bản dựng có kiểu enum
:
# example/buildsettings/build_settings.bzl
TemperatureProvider = provider(fields = ['type'])
temperatures = ["HOT", "LUKEWARM", "ICED"]
def _impl(ctx):
raw_temperature = ctx.build_setting_value
if raw_temperature not in temperatures:
fail(str(ctx.label) + " build setting allowed to take values {"
+ ", ".join(temperatures) + "} but was set to unallowed value "
+ raw_temperature)
return TemperatureProvider(type = raw_temperature)
temperature = rule(
implementation = _impl,
build_setting = config.string(flag = True)
)
Xác định cờ chuỗi nhiều tập hợp
Chế độ cài đặt chuỗi có thêm tham số allow_multiple
cho phép phương thức
cờ để được đặt nhiều lần trên dòng lệnh hoặc trong bazelrcs. Mặc định
giá trị vẫn được đặt bằng thuộc tính kiểu chuỗi:
# example/buildsettings/build_settings.bzl
allow_multiple_flag = rule(
implementation = _impl,
build_setting = config.string(flag = True, allow_multiple = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "allow_multiple_flag")
allow_multiple_flag(
name = "roasts",
build_setting_default = "medium"
)
Mỗi chế độ cài đặt của cờ này được coi là một giá trị duy nhất:
$ bazel build //my/target --//example:roasts=blonde \
--//example:roasts=medium,dark
Dữ liệu ở trên được phân tích cú pháp thành {"//example:roasts": ["blonde", "medium,dark"]}
và
ctx.build_setting_value
trả về danh sách ["blonde", "medium,dark"]
.
Tạo thực thể cho chế độ cài đặt bản dựng
Các quy tắc được xác định bằng tham số build_setting
có một giá trị bắt buộc ngầm ẩn
Thuộc tính build_setting_default
. Thuộc tính này lấy cùng một loại với
được khai báo bởi tham số build_setting
.
# example/buildsettings/build_settings.bzl
FlavorProvider = provider(fields = ['type'])
def _impl(ctx):
return FlavorProvider(type = ctx.build_setting_value)
flavor = rule(
implementation = _impl,
build_setting = config.string(flag = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
name = "favorite_flavor",
build_setting_default = "APPLE"
)
Chế độ cài đặt định sẵn
Chiến lược phát hành đĩa đơn Skylib bao gồm một tập hợp các chế độ cài đặt được xác định trước mà bạn có thể tạo thực thể mà không cần để ghi Starlark tuỳ chỉnh.
Ví dụ: để xác định một chế độ cài đặt chấp nhận một nhóm giá trị chuỗi có giới hạn, hãy làm như sau:
# example/BUILD
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
string_flag(
name = "myflag",
values = ["a", "b", "c"],
build_setting_default = "a",
)
Để xem danh sách đầy đủ, hãy xem Các quy tắc cài đặt phổ biến cho bản dựng.
Sử dụng chế độ cài đặt bản dựng
Tuỳ thuộc vào chế độ cài đặt bản dựng
Nếu muốn đọc một phần thông tin cấu hình, mục tiêu có thể phụ thuộc trực tiếp vào chế độ cài đặt bản dựng thông qua phần phụ thuộc thuộc tính thông thường.
# example/rules.bzl
load("//example/buildsettings:build_settings.bzl", "FlavorProvider")
def _rule_impl(ctx):
if ctx.attr.flavor[FlavorProvider].type == "ORANGE":
...
drink_rule = rule(
implementation = _rule_impl,
attrs = {
"flavor": attr.label()
}
)
# example/BUILD
load("//example:rules.bzl", "drink_rule")
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
name = "favorite_flavor",
build_setting_default = "APPLE"
)
drink_rule(
name = "my_drink",
flavor = ":favorite_flavor",
)
Ngôn ngữ nên tạo một bộ cài đặt bản dựng chuẩn mà tất cả các quy tắc
cho ngôn ngữ đó phụ thuộc. Mặc dù khái niệm gốc của fragments
không còn nữa
tồn tại dưới dạng đối tượng được cố định giá trị trong mã trong thế giới cấu hình Starlark, có một cách để
dịch khái niệm này sẽ là sử dụng tập hợp các thuộc tính ngầm ẩn phổ biến. Ví dụ:
# kotlin/rules.bzl
_KOTLIN_CONFIG = {
"_compiler": attr.label(default = "//kotlin/config:compiler-flag"),
"_mode": attr.label(default = "//kotlin/config:mode-flag"),
...
}
...
kotlin_library = rule(
implementation = _rule_impl,
attrs = dicts.add({
"library-attr": attr.string()
}, _KOTLIN_CONFIG)
)
kotlin_binary = rule(
implementation = _binary_impl,
attrs = dicts.add({
"binary-attr": attr.label()
}, _KOTLIN_CONFIG)
Sử dụng chế độ cài đặt bản dựng trên dòng lệnh
Tương tự như hầu hết cờ gốc, bạn có thể sử dụng dòng lệnh để thiết lập chế độ cài đặt bản dựng
được đánh dấu là cờ. Bản dựng
tên của chế độ cài đặt là đường dẫn mục tiêu đầy đủ bằng cú pháp name=value
:
$ bazel build //my/target --//example:string_flag=some-value # allowed
$ bazel build //my/target --//example:string_flag some-value # not allowed
Cú pháp boolean đặc biệt được hỗ trợ:
$ bazel build //my/target --//example:boolean_flag
$ bazel build //my/target --no//example:boolean_flag
Sử dụng bí danh của chế độ cài đặt bản dựng
Bạn có thể đặt bí danh cho đường dẫn mục tiêu của chế độ cài đặt bản dựng để dễ đọc hơn trên dòng lệnh. Bí danh hoạt động tương tự như cờ gốc và cũng tận dụng của cú pháp dấu gạch ngang kép.
Đặt biệt hiệu bằng cách thêm --flag_alias=ALIAS_NAME=TARGET_PATH
vào .bazelrc
của bạn . Ví dụ: để đặt bí danh là coffee
:
# .bazelrc
build --flag_alias=coffee=//experimental/user/starlark_configurations/basic_build_setting:coffee-temp
Phương pháp hay nhất: Việc đặt bí danh nhiều lần sẽ dẫn đến kết quả gần đây nhất một chiến dịch sẽ được ưu tiên. Hãy sử dụng các tên đại diện duy nhất để tránh kết quả phân tích cú pháp ngoài ý muốn.
Để sử dụng bí danh, hãy nhập bí danh thay cho đường dẫn mục tiêu của chế độ cài đặt bản dựng.
Với ví dụ ở trên về coffee
được đặt trong .bazelrc
của người dùng:
$ bazel build //my/target --coffee=ICED
thay vì
$ bazel build //my/target --//experimental/user/starlark_configurations/basic_build_setting:coffee-temp=ICED
Phương pháp hay nhất: Mặc dù có thể đặt các biệt hiệu trên dòng lệnh, nhưng để các bí danh đó
trong .bazelrc
sẽ giảm sự lộn xộn của dòng lệnh.
Chế độ cài đặt bản dựng đã nhập nhãn
Không giống như các chế độ cài đặt khác của bản dựng, bạn không thể xác định chế độ cài đặt có dạng nhãn bằng cách sử dụng
Tham số quy tắc build_setting
. Thay vào đó, bazel có 2 quy tắc tích hợp sẵn:
label_flag
và label_setting
. Các quy tắc này chuyển tiếp các nhà cung cấp
mục tiêu thực tế mà chế độ cài đặt bản dựng được đặt. label_flag
và
label_setting
có thể được đọc/ghi bằng hiệu ứng chuyển đổi và label_flag
có thể được thiết lập
giống như các quy tắc build_setting
khác. Điểm khác biệt duy nhất là
không thể xác định thường xuyên.
Các chế độ cài đặt theo nhãn sẽ thay thế chức năng của thẻ ràng buộc trễ
mặc định. Thuộc tính mặc định giới hạn trễ là các thuộc tính theo loại Nhãn có
giá trị cuối cùng có thể bị ảnh hưởng bởi cấu hình. Trong Starlark, mục này sẽ thay thế
configuration_field
API.
# example/rules.bzl
MyProvider = provider(fields = ["my_field"])
def _dep_impl(ctx):
return MyProvider(my_field = "yeehaw")
dep_rule = rule(
implementation = _dep_impl
)
def _parent_impl(ctx):
if ctx.attr.my_field_provider[MyProvider].my_field == "cowabunga":
...
parent_rule = rule(
implementation = _parent_impl,
attrs = { "my_field_provider": attr.label() }
)
# example/BUILD
load("//example:rules.bzl", "dep_rule", "parent_rule")
dep_rule(name = "dep")
parent_rule(name = "parent", my_field_provider = ":my_field_provider")
label_flag(
name = "my_field_provider",
build_setting_default = ":dep"
)
Tạo chế độ cài đặt và Select()
Người dùng có thể định cấu hình thuộc tính trên chế độ cài đặt bản dựng bằng cách sử dụng
select()
. Bạn có thể truyền mục tiêu cài đặt bản dựng đến thuộc tính flag_values
của
config_setting
. Giá trị cần khớp với cấu hình được chuyển dưới dạng
Sau đó, String
được phân tích cú pháp thành loại chế độ cài đặt bản dựng để so khớp.
config_setting(
name = "my_config",
flag_values = {
"//example:favorite_flavor": "MANGO"
}
)
Hiệu ứng chuyển đổi do người dùng xác định
Cấu hình chuyển đổi ánh xạ chuyển đổi từ một mục tiêu đã được định cấu hình sang một mục tiêu khác trong biểu đồ bản dựng.
Quy tắc đặt ra các giá trị này phải bao gồm một thuộc tính đặc biệt:
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist"
)
Bằng cách thêm các hiệu ứng chuyển đổi, bạn có thể dễ dàng tăng kích thước của biểu đồ bản dựng. Thao tác này sẽ đặt danh sách cho phép cho những gói mà bạn có thể tạo mục tiêu của quy tắc này. Giá trị mặc định trong khối mã ở trên đưa mọi thứ vào danh sách cho phép. Nhưng nếu bạn muốn hạn chế ai đang sử dụng quy tắc của mình, bạn có thể đặt thuộc tính đó để trỏ đến danh sách cho phép tuỳ chỉnh của riêng bạn. Hãy liên hệ với bazel-discuss@googlegroups.com nếu bạn muốn được tư vấn hoặc hỗ trợ tìm hiểu xem việc chuyển đổi có thể ảnh hưởng như thế nào đến hiệu suất của bản dựng.
Định nghĩa
Chuyển đổi xác định thay đổi cấu hình giữa các quy tắc. Ví dụ: yêu cầu chẳng hạn như "biên dịch phần phụ thuộc của tôi cho một CPU khác với CPU gốc" được xử lý bởi một chuyển đổi.
Về chính thức, phép chuyển đổi là một hàm từ một cấu hình đầu vào đến một hoặc nhiều
cấu hình đầu ra. Hầu hết các quá trình chuyển đổi đều có tỷ lệ 1:1, chẳng hạn như "ghi đè giá trị đầu vào
với --cpu=ppc
". Các hiệu ứng chuyển cảnh 1:2+ cũng có thể tồn tại nhưng đến
với các hạn chế đặc biệt.
Trong Starlark, hiệu ứng chuyển đổi được xác định giống như các quy tắc, trong đó
transition()
hàm
và một hàm triển khai.
# example/transitions/transitions.bzl
def _impl(settings, attr):
_ignore = (settings, attr)
return {"//example:favorite_flavor" : "MINT"}
hot_chocolate_transition = transition(
implementation = _impl,
inputs = [],
outputs = ["//example:favorite_flavor"]
)
Hàm transition()
có một hàm triển khai, một tập hợp
chế độ cài đặt bản dựng để đọc(inputs
) và một nhóm chế độ cài đặt bản dựng để ghi
(outputs
). Hàm triển khai có hai tham số: settings
và
attr
. settings
là từ điển {String
:Object
} của tất cả chế độ cài đặt đã khai báo
trong tham số inputs
vào transition()
.
attr
là từ điển các thuộc tính và giá trị của quy tắc mà
đã đính kèm hiệu ứng chuyển đổi. Khi được đính kèm dưới dạng
chuyển tiếp cạnh đi, giá trị của
đều là độ phân giải post-select() được định cấu hình. Khi được đính kèm dưới dạng
chuyển đổi cạnh sắp tới, attr
sẽ không
bao gồm mọi thuộc tính sử dụng bộ chọn để phân giải giá trị của chúng. Nếu một
hiệu ứng chuyển đổi cạnh đến trên --foo
sẽ đọc thuộc tính bar
, sau đó cũng
chọn trên --foo
để đặt thuộc tính bar
, thì có khả năng
chuyển đổi cạnh đến để đọc giá trị không chính xác của bar
trong quá trình chuyển đổi.
Hàm triển khai phải trả về một từ điển (hoặc danh sách
từ điển, trong trường hợp
chuyển đổi có nhiều cấu hình đầu ra)
các giá trị cài đặt bản dựng mới sẽ áp dụng. (Các) bộ khoá từ điển được trả về phải
chứa chính xác tập hợp các chế độ cài đặt bản dựng được truyền cho outputs
tham số của hàm chuyển đổi. Điều này đúng ngay cả khi chế độ cài đặt bản dựng là
không thực sự thay đổi trong quá trình chuyển đổi - giá trị ban đầu của nó phải
được chuyển một cách rõ ràng trong từ điển được trả về.
Xác định hiệu ứng chuyển đổi 1:2+
Chuyển đổi cạnh đi có thể ánh xạ một thiết bị đầu vào duy nhất thành hai hoặc nhiều cấu hình đầu ra. Điều này rất hữu ích khi xác định các quy tắc gói mã đa cấu trúc.
Hiệu ứng chuyển đổi 1:2+ được xác định bằng cách trả về một danh sách các từ điển trong hàm thực thi chuyển đổi.
# example/transitions/transitions.bzl
def _impl(settings, attr):
_ignore = (settings, attr)
return [
{"//example:favorite_flavor" : "LATTE"},
{"//example:favorite_flavor" : "MOCHA"},
]
coffee_transition = transition(
implementation = _impl,
inputs = [],
outputs = ["//example:favorite_flavor"]
)
Họ cũng có thể đặt khoá tuỳ chỉnh mà chức năng triển khai quy tắc có thể sử dụng đọc các phần phụ thuộc riêng lẻ:
# example/transitions/transitions.bzl
def _impl(settings, attr):
_ignore = (settings, attr)
return {
"Apple deps": {"//command_line_option:cpu": "ppc"},
"Linux deps": {"//command_line_option:cpu": "x86"},
}
multi_arch_transition = transition(
implementation = _impl,
inputs = [],
outputs = ["//command_line_option:cpu"]
)
Đính kèm hiệu ứng chuyển đổi
Bạn có thể đính kèm hiệu ứng chuyển đổi ở hai vị trí: cạnh đến và cạnh đi. Điều này có nghĩa là các quy tắc có thể chuyển đổi cấu hình của chính chúng (sẽ đến) chuyển tiếp cạnh) và chuyển đổi các phần phụ thuộc cấu hình (cuộc gọi đi chuyển tiếp cạnh).
LƯU Ý: Hiện không có cách nào để đính kèm chuyển đổi Starlark vào quy tắc gốc. Nếu bạn cần thực hiện việc này, hãy liên hệ với bazel-discuss@googlegroups.com để được trợ giúp tìm cách giải quyết.
Chuyển đổi cạnh đến
Hiệu ứng chuyển đổi cạnh đến được kích hoạt bằng cách đính kèm một đối tượng transition
(được tạo bởi transition()
) vào tham số cfg
của rule()
:
# example/rules.bzl
load("example/transitions:transitions.bzl", "hot_chocolate_transition")
drink_rule = rule(
implementation = _impl,
cfg = hot_chocolate_transition,
...
Các lượt chuyển đổi cạnh đến phải là lượt chuyển đổi 1:1.
Chuyển đổi cạnh đi
Kích hoạt hiệu ứng chuyển đổi cạnh đi bằng cách đính kèm một đối tượng transition
(do transition()
tạo) thành tham số cfg
của một thuộc tính:
# example/rules.bzl
load("example/transitions:transitions.bzl", "coffee_transition")
drink_rule = rule(
implementation = _impl,
attrs = { "dep": attr.label(cfg = coffee_transition)}
...
Hiệu ứng chuyển tiếp cạnh đi có thể là 1:1 hoặc 1:2+.
Xem bài viết Truy cập vào thuộc tính bằng hiệu ứng chuyển đổi để biết cách đọc các khoá này.
Hiệu ứng chuyển đổi trên tuỳ chọn gốc
Các hiệu ứng chuyển đổi Starlark cũng có thể khai báo hoạt động đọc và ghi trên bản dựng gốc các tuỳ chọn cấu hình qua một tiền tố đặc biệt vào tên tuỳ chọn.
# example/transitions/transitions.bzl
def _impl(settings, attr):
_ignore = (settings, attr)
return {"//command_line_option:cpu": "k8"}
cpu_transition = transition(
implementation = _impl,
inputs = [],
outputs = ["//command_line_option:cpu"]
Tùy chọn gốc không được hỗ trợ
Bazel không hỗ trợ chuyển đổi trên --define
bằng
"//command_line_option:define"
. Thay vào đó, hãy sử dụng
chế độ cài đặt của bản dựng. Nhìn chung, cách sử dụng mới của
Bạn không nên sử dụng --define
, thay vào đó là các chế độ cài đặt bản dựng.
Bazel không hỗ trợ chuyển đổi trên --config
. Lý do là --config
sự "mở rộng" cờ này mở rộng sang các cờ khác.
Điều quan trọng là --config
có thể bao gồm cờ không ảnh hưởng đến cấu hình bản dựng,
chẳng hạn như
--spawn_strategy
của Google. Theo thiết kế, Bazel không thể liên kết các cờ như vậy với từng mục tiêu riêng lẻ. Điều này có nghĩa là
không có cách nào mạch lạc để áp dụng chúng trong quá trình chuyển đổi.
Để giải quyết vấn đề này, bạn có thể phân loại rõ ràng các cờ thuộc
cấu hình trong chuyển đổi. Điều này đòi hỏi bạn duy trì--config
mở rộng ở hai vị trí, đó là một nhược điểm đã biết của giao diện người dùng.
Hiệu ứng chuyển đổi đang bật cho phép nhiều chế độ cài đặt bản dựng
Khi đặt chế độ cài đặt bản dựng cho phép nhiều giá trị, giá trị của cài đặt phải được đặt bằng một danh sách.
# example/buildsettings/build_settings.bzl
string_flag = rule(
implementation = _impl,
build_setting = config.string(flag = True, allow_multiple = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "string_flag")
string_flag(name = "roasts", build_setting_default = "medium")
# example/transitions/rules.bzl
def _transition_impl(settings, attr):
# Using a value of just "dark" here will throw an error
return {"//example:roasts" : ["dark"]},
coffee_transition = transition(
implementation = _transition_impl,
inputs = [],
outputs = ["//example:roasts"]
)
Chuyển đổi không hoạt động
Nếu hiệu ứng chuyển đổi trả về {}
, []
hoặc None
, thì đây là cách viết tắt để giữ lại tất cả
ở giá trị ban đầu. Cách này có thể thuận tiện hơn là nói rõ
đặt từng đầu ra thành chính nó.
# example/transitions/transitions.bzl
def _impl(settings, attr):
_ignore = (attr)
if settings["//example:already_chosen"] is True:
return {}
return {
"//example:favorite_flavor": "dark chocolate",
"//example:include_marshmallows": "yes",
"//example:desired_temperature": "38C",
}
hot_chocolate_transition = transition(
implementation = _impl,
inputs = ["//example:already_chosen"],
outputs = [
"//example:favorite_flavor",
"//example:include_marshmallows",
"//example:desired_temperature",
]
)
Truy cập vào các thuộc tính bằng hiệu ứng chuyển đổi
Khi đính kèm hiệu ứng chuyển đổi vào một cạnh gọi đi
(bất kể quá trình chuyển đổi là chuyển đổi 1:1 hay 1:2+, ctx.attr
buộc phải là một danh sách
nếu chưa được cập nhật. Chưa xác định thứ tự của các phần tử trong danh sách này.
# example/transitions/rules.bzl
def _transition_impl(settings, attr):
return {"//example:favorite_flavor" : "LATTE"},
coffee_transition = transition(
implementation = _transition_impl,
inputs = [],
outputs = ["//example:favorite_flavor"]
)
def _rule_impl(ctx):
# Note: List access even though "dep" is not declared as list
transitioned_dep = ctx.attr.dep[0]
# Note: Access doesn't change, other_deps was already a list
for other_dep in ctx.attr.other_deps:
# ...
coffee_rule = rule(
implementation = _rule_impl,
attrs = {
"dep": attr.label(cfg = coffee_transition)
"other_deps": attr.label_list(cfg = coffee_transition)
})
Nếu hiệu ứng chuyển đổi là 1:2+
và đặt khoá tuỳ chỉnh, bạn có thể sử dụng ctx.split_attr
để đọc phần phụ thuộc riêng lẻ cho từng khoá:
# example/transitions/rules.bzl
def _impl(settings, attr):
_ignore = (settings, attr)
return {
"Apple deps": {"//command_line_option:cpu": "ppc"},
"Linux deps": {"//command_line_option:cpu": "x86"},
}
multi_arch_transition = transition(
implementation = _impl,
inputs = [],
outputs = ["//command_line_option:cpu"]
)
def _rule_impl(ctx):
apple_dep = ctx.split_attr.dep["Apple deps"]
linux_dep = ctx.split_attr.dep["Linux deps"]
# ctx.attr has a list of all deps for all keys. Order is not guaranteed.
all_deps = ctx.attr.dep
multi_arch_rule = rule(
implementation = _rule_impl,
attrs = {
"dep": attr.label(cfg = multi_arch_transition)
})
Xem ví dụ đầy đủ vào đây.
Tích hợp với các nền tảng và chuỗi công cụ
Nhiều cờ gốc hiện nay, như --cpu
và --crosstool_top
có liên quan đến
phân giải chuỗi công cụ. Trong tương lai, việc chuyển đổi rõ ràng trên các loại
cờ có thể sẽ được thay thế bằng cách chuyển đổi trên
nền tảng mục tiêu.
Những điều cần cân nhắc về bộ nhớ và hiệu suất
Việc thêm các chuyển đổi và theo đó các cấu hình mới vào bản dựng của bạn cần có chi phí: biểu đồ bản dựng lớn hơn, biểu đồ bản dựng khó hiểu hơn và chậm hơn bản dựng. Bạn nên cân nhắc những chi phí này khi cân nhắc bằng cách sử dụng hiệu ứng chuyển đổi trong quy tắc xây dựng. Dưới đây là ví dụ về cách chuyển đổi có thể tạo ra sự tăng trưởng luỹ thừa của biểu đồ bản dựng.
Bản dựng có hành vi xấu: một nghiên cứu điển hình
Hình 1. Biểu đồ về khả năng mở rộng cho thấy mục tiêu cấp cao nhất và các phần phụ thuộc của mục tiêu đó.
Biểu đồ này cho thấy mục tiêu cấp cao nhất, //pkg:app
, phụ thuộc vào hai mục tiêu, một
//pkg:1_0
và //pkg:1_1
. Cả hai mục tiêu này phụ thuộc vào hai mục tiêu là //pkg:2_0
và
//pkg:2_1
. Cả hai mục tiêu này phụ thuộc vào hai mục tiêu là //pkg:3_0
và //pkg:3_1
.
Tác vụ này sẽ tiếp tục cho đến //pkg:n_0
và //pkg:n_1
, cả hai đều phụ thuộc vào một
mục tiêu //pkg:dep
.
Việc xây dựng //pkg:app
yêu cầu \(2n+2\) các mục tiêu:
//pkg:app
//pkg:dep
//pkg:i_0
và//pkg:i_1
với giá \(i\) trong \([1..n]\)
Giả sử bạn triển khai một cờ
Áp dụng --//foo:owner=<STRING>
và //pkg:i_b
depConfig = myConfig + depConfig.owner="$(myConfig.owner)$(b)"
Nói cách khác, //pkg:i_b
sẽ thêm b
vào giá trị cũ của --owner
cho tất cả
Phần phụ thuộc của nó.
Thao tác này sẽ tạo ra các mục tiêu đã định cấu hình sau:
//pkg:app //foo:owner=""
//pkg:1_0 //foo:owner=""
//pkg:1_1 //foo:owner=""
//pkg:2_0 (via //pkg:1_0) //foo:owner="0"
//pkg:2_0 (via //pkg:1_1) //foo:owner="1"
//pkg:2_1 (via //pkg:1_0) //foo:owner="0"
//pkg:2_1 (via //pkg:1_1) //foo:owner="1"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_0) //foo:owner="00"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_1) //foo:owner="01"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_0) //foo:owner="10"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_1) //foo:owner="11"
...
//pkg:dep
tạo ra \(2^n\) các mục tiêu đã định cấu hình: config.owner=
"\(b_0b_1...b_n\)" cho tất cả \(b_i\) trong \(\{0,1\}\).
Điều này làm cho biểu đồ bản dựng lớn hơn theo cấp số nhân so với biểu đồ mục tiêu, với bộ nhớ và hiệu suất tương ứng.
VIỆC CẦN LÀM: Thêm các chiến lược để đo lường và giảm thiểu những vấn đề này.
Tài liệu đọc thêm
Để biết thêm thông tin về cách sửa đổi cấu hình bản dựng, hãy xem:
- Cấu hình bản dựng Starlark
- Lộ trình về khả năng định cấu hình Bazel
- Bộ đầy đủ các ví dụ từ đầu đến cuối