Phiên bản

Báo cáo vấn đề Xem nguồn Nightly · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

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 xây dựng dự án. Tài liệu này bao gồm cách xác định chế độ cài đặt 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 bạn, không cần đến --define nữa
  • 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)
  • đưa các giá trị mặc định tốt hơn vào quy tắc (chẳng hạn như tự động tạo //my:android_app bằng một SDK đã chỉ định)

v.v., tất cả đều hoàn toàn từ tệp .bzl (không yêu cầu bản phát hành Bazel). Hãy xem kho lưu trữ bazelbuild/examples để biết 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ị. Việc đặt --cpu=ppc--copt="-DFoo" sẽ tạo ra một cấu hình có dạng như {cpu: ppc, copt: "-DFoo"}. Mỗi mục nhập là một chế độ cài đặt bản dựng.

Các cờ truyền thống như cpucopt là các chế độ cài đặt gốc – khoá của các cờ này được xác định và giá trị của các cờ này đượ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. Các chế độ cài đặt bản dựng do người dùng xác định được xác định trong tệp .bzl (do đó, không cần bản phát hành bazel để đăng ký các thay đổi). Bạn cũng có thể đặt các giá trị này thông qua dòng lệnh (nếu được chỉ định là flags, hãy xem thêm bên dưới), nhưng cũng có thể đặt thông qua hiệu ứng chuyển đổi do người dùng xác định.

Xác định chế độ cài đặt bản dựng

Ví dụ từ đầu đến cuối

Tham số build_setting rule()

Chế độ cài đặt bản dựng là các quy tắc giống như mọi quy tắc 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ư boolstring. Hãy xem tài liệu về mô-đun config để 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 một tham số boolean không bắt buộc, flag, được đặt thành false theo mặc định. Nếu bạn đặt flag thành true, người dùng cũng như người viết quy tắc nội bộ có thể đặt chế độ cài đặt bản dựng trên dòng lệnh thông qua các giá trị mặc định và quá trình chuyển đổi. Không phải người dùng nào cũng có thể thiết lập tất cả các chế độ cài đặt. Ví dụ: nếu bạn là một trình ghi quy tắc có một số chế độ gỡ lỗi mà bạn muốn bật bên trong các quy tắc kiểm thử, bạn không muốn cho phép người dùng bật tính năng đó một cách vô tội vạ bên trong các quy tắc không phải 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 vào giá trị loại Starlark cơ bản của chế độ cài đặt bản dựng thông qua phương thức 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. Giá trị mặc định của các thuộc tính này 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

Mã trên được phân tích cú pháp thành {"//example:roasts": ["blonde", "medium,dark"]}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

Ví dụ từ đầu đến cuối

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 để viết 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 tham khảo 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 một mục tiêu muốn đọc một phần thông tin cấu hình, thì mục tiêu đó có thể trực tiếp phụ thuộc 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",
)

Các ngôn ngữ có thể tạo một tập hợp các chế độ 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 vào. Mặc dù khái niệm gốc của fragments không còn tồn tại dưới dạng đối tượng được mã hoá cứng trong thế giới cấu hình Starlark, nhưng một cách để diễn giải khái niệm này là sử dụng các tập hợp 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 bí danh bằng cách thêm --flag_alias=ALIAS_NAME=TARGET_PATH vào .bazelrc. 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 việc bí danh gần đây nhất đượ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 bí danh trên dòng lệnh, nhưng việc để các bí danh đó trong .bazelrc sẽ làm giảm tình trạng lộn xộn của dòng lệnh.

Chế độ cài đặt bản dựng đã nhập nhãn

Ví dụ từ đầu đến cuối

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_flaglabel_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_flaglabel_setting có thể được đọc/ghi bằng các chuyển đổi và người dùng có thể đặt label_flag 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.

Chế độ cài đặt được nhập bằng nhãn cuối cùng sẽ thay thế chức năng của các giá trị mặc định liên kết trễ. Thuộc tính mặc định giới hạn trễ là các thuộc tính 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, tên 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()

Ví dụ toàn diện

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 các 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 so khớp với cấu hình được truyền dưới dạng String, sau đó đượ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

Quá trình chuyển đổi cấu hình liên kết quá trình chuyển đổi từ một mục tiêu đã đị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 cho phép mọi thứ. Nhưng nếu bạn muốn hạn chế người đ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ụ: một yêu cầu như "biên dịch phần phụ thuộc của tôi cho một CPU khác với CPU mẹ" sẽ được xử lý bằng một quá trình chuyển đổi.

Theo cách chính thức, quá trình chuyển đổi là một hà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, các quá trình chuyển đổi được xác định giống như các quy tắc, với một hàm transition() xác định 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ố: settingsattr. 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 đến, attr không bao gồm bất kỳ thuộc tính nào sử dụng bộ chọn để phân giải giá trị của chúng. Nếu một chuyển đổi cạnh đến trên --foo đọ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 sẽ đọc sai giá trị 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ủa các giá trị cài đặt bản dựng mới cần áp dụng. (Các) tập hợp khoá từ điển được trả về phải chứa chính xác tập hợp chế độ cài đặt bản dựng được truyền vào tham số outputs 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+

Ví dụ từ đầu đến cuối

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.

Các hiệu ứng chuyển đổi 1:2 trở lên được xác định bằng cách trả về danh sách từ điển trong hàm triển khai hiệu ứng 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"]
)

Các lớp này cũng có thể đặt các khoá tuỳ chỉnh mà hàm triển khai quy tắc có thể sử dụng để đọc từng phần phụ thuộc:

# 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

Ví dụ toàn diện

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 riêng chúng (chuyển đổi cạnh đến) và chuyển đổi cấu hình của các phần phụ thuộc (chuyển đổi cạnh đi).

LƯU Ý: Hiện không có cách nào để đính kèm các chuyển đổi Starlark vào quy tắc gốc. Nếu bạn cần làm việc này, hãy liên hệ với bazel-discuss@googlegroups.com để được trợ giúp tìm giải pháp.

Chuyển đổi cạnh đến

Các hiệu ứng chuyển đổi cạnh sắp tới được kích hoạt bằng cách đính kèm đối tượng transition (do transition() tạo) 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.

Hiệu ứng 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 đổi cạnh đi có thể là 1:1 hoặc 1:2 trở lên.

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

Ví dụ từ đầu đến cuối

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, bạn không nên sử dụng các cách mới của --define mà nên sử dụng chế độ cài đặt bản dựng.

Bazel không hỗ trợ quá trình 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.

Để khắc phục, bạn có thể liệt kê rõ ràng các cờ một phần của cấu hình trong quá trình chuyển đổi. Điều này đòi hỏi bạn phải duy trì việc mở rộng --config ở hai vị trí, đây là một lỗi giao diện người dùng đã biết.

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"]
)

Hiệu ứng chuyển đổi không hoạt động

Nếu một quá trình chuyển đổi trả về {}, [] hoặc None, thì đây là viết tắt để giữ tất cả các chế độ cài đặt ở 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

Ví dụ từ đầu đến cuối

Khi đính kèm một hiệu ứng chuyển đổi vào một cạnh đi (bất kể hiệu ứng chuyển đổi đó là hiệu ứng chuyển đổi 1:1 hay 1:2 trở lên), ctx.attr buộc phải là một danh sách nếu chưa phải. Thứ tự của các phần tử trong danh sách này không được chỉ định.

# 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 quá trình chuyển đổi là 1:2+ và đặt các khoá tuỳ chỉnh, bạn có thể sử dụng ctx.split_attr để đọc cá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ụ hoàn chỉnh 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--crosstool_top có liên quan đến phân giải chuỗi công cụ. Trong tương lai, các chuyển đổi rõ ràng trên các loại cờ này có thể sẽ được thay thế bằng việc 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 các chi phí này khi cân nhắc việc sử dụng hiệu ứng chuyển đổi trong quy tắc bản 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

Biểu đồ khả năng mở rộng

Hình 1. Biểu đồ khả năng mở rộng cho thấy một 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//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//pkg:2_1. Cả hai mục tiêu này đều phụ thuộc vào hai mục tiêu, //pkg:3_0//pkg:3_1. Tác vụ này sẽ tiếp tục cho đến //pkg:n_0//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 cần có \(2n+2\) các mục tiêu:

  • //pkg:app
  • //pkg:dep
  • //pkg:i_0//pkg:i_1 cho \(i\) trong \([1..n]\)

Hãy tưởng tượng bạn triển khai một cờ --//foo:owner=<STRING>//pkg:i_b áp dụng

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 chi tiết về cách sửa đổi cấu hình bản dựng, hãy xem: