หน้านี้ครอบคลุมถึงสิทธิประโยชน์และการใช้งานพื้นฐานของการกำหนดค่า Starlark ซึ่งเป็น API ของ Bazel สำหรับการปรับแต่งวิธีสร้างโปรเจ็กต์ รวมถึงวิธีกำหนดการตั้งค่าบิลด์และตัวอย่าง
ซึ่งจะช่วยให้คุณทำสิ่งต่อไปนี้ได้
- กำหนดแฟล็กที่กำหนดเองสำหรับโปรเจ็กต์ ซึ่งจะทำให้ไม่จำเป็นต้องใช้
--define - เขียน
การเปลี่ยนเพื่อกำหนดค่าการขึ้นต่อกันในการกำหนดค่าที่
แตกต่างจากระดับบน
(เช่น
--compilation_mode=optหรือ--cpu=arm) - กำหนดค่าเริ่มต้นที่ดีขึ้นในกฎ (เช่น สร้าง
//my:android_appด้วย SDK ที่ระบุโดยอัตโนมัติ)
และอื่นๆ อีกมากมาย ทั้งหมดนี้ทำได้จากไฟล์ .bzl (ไม่จำเป็นต้องใช้ Bazel เวอร์ชันที่เผยแพร่) ดูตัวอย่างได้ที่ที่เก็บ
bazelbuild/examples สำหรับ
ตัวอย่าง
การตั้งค่าบิลด์ที่ผู้ใช้กำหนด
การตั้งค่าบิลด์คือข้อมูลการกำหนดค่าเพียงรายการเดียว
การกำหนดค่า ลองนึกถึงการกำหนดค่าเป็นแมปคีย์/ค่า การตั้งค่า --cpu=ppc
และ --copt="-DFoo" จะสร้างการกำหนดค่าที่มีลักษณะเป็น
{cpu: ppc, copt: "-DFoo"} โดยแต่ละรายการคือการตั้งค่าบิลด์
แฟล็กแบบเดิม เช่น cpu และ copt เป็นการตั้งค่าดั้งเดิม ซึ่งมีการกำหนดคีย์และตั้งค่าภายในโค้ด Java ของ Bazel ดั้งเดิม
ผู้ใช้ Bazel สามารถอ่านและเขียนแฟล็กเหล่านี้ได้ผ่านบรรทัดคำสั่งและ API อื่นๆ ที่ดูแลโดยดั้งเดิมเท่านั้น การเปลี่ยนแปลงแฟล็กดั้งเดิมและ API ที่แสดงแฟล็กเหล่านี้ต้องใช้ Bazel เวอร์ชันที่เผยแพร่ การตั้งค่าบิลด์ที่ผู้ใช้กำหนดจะกำหนดไว้ในไฟล์ .bzl (จึงไม่จำเป็นต้องใช้ Bazel เวอร์ชันที่เผยแพร่เพื่อลงทะเบียนการเปลี่ยนแปลง) นอกจากนี้ยังตั้งค่าผ่านบรรทัดคำสั่งได้ด้วย
(หากกำหนดให้เป็น flags โปรดดูรายละเอียดเพิ่มเติมด้านล่าง) แต่ก็ตั้งค่าผ่านการเปลี่ยนที่ผู้ใช้กำหนดได้เช่นกัน
การกำหนดการตั้งค่าบิลด์
พารามิเตอร์ build_setting ของ rule()
การตั้งค่าการสร้างเป็นกฎเช่นเดียวกับกฎอื่นๆ และแยกความแตกต่างโดยใช้แอตทริบิวต์ของฟังก์ชันbuild_setting
Starlark rule()
# example/buildsettings/build_settings.bzl
string_flag = rule(
implementation = _impl,
build_setting = config.string(flag = True)
)
แอตทริบิวต์ build_setting จะใช้ฟังก์ชันที่กำหนดประเภทของการตั้งค่าบิลด์ ประเภทจะจำกัดอยู่เพียงชุดประเภท Starlark พื้นฐาน เช่น bool และ string โปรดดูรายละเอียดในเอกสารประกอบของโมดูล config
การพิมพ์ที่ซับซ้อนมากขึ้นสามารถทำได้ในฟังก์ชันการใช้งานของกฎ โปรดดูรายละเอียดเพิ่มเติมด้านล่าง
ฟังก์ชันของโมดูล config จะใช้พารามิเตอร์บูลีนที่ไม่บังคับ flag,
ซึ่งตั้งค่าเป็น "เท็จ" โดยค่าเริ่มต้น หากตั้งค่า flag เป็น "จริง" ผู้ใช้จะตั้งค่าบิลด์
ในบรรทัดคำสั่งได้ รวมถึงผู้เขียนกฎจะตั้งค่าภายใน
ผ่านค่าเริ่มต้นและการเปลี่ยนผ่านได้ด้วย
ไม่ควรให้ผู้ใช้ตั้งค่าการตั้งค่าทั้งหมดได้ ตัวอย่างเช่น หากคุณในฐานะผู้เขียนกฎมีโหมดแก้ไขข้อบกพร่องที่ต้องการเปิดใช้ภายในกฎการทดสอบ คุณก็ไม่ต้องการให้ผู้ใช้มีความสามารถในการเปิดใช้ฟีเจอร์นั้นโดยไม่เลือกปฏิบัติภายในกฎอื่นๆ ที่ไม่ใช่กฎการทดสอบ
การใช้ ctx.build_setting_value
กฎการตั้งค่าการสร้างมีฟังก์ชันการใช้งานเช่นเดียวกับกฎทั้งหมด
คุณเข้าถึงค่าประเภท Starlark พื้นฐานของการตั้งค่าการสร้างได้ผ่านเมธอด ctx.build_setting_value เมธอดนี้ใช้ได้กับ
ctx ออบเจ็กต์ของกฎการตั้งค่าการสร้างเท่านั้น เมธอดการใช้งานเหล่านี้สามารถส่งต่อค่าการตั้งค่าบิลด์ได้โดยตรง หรือดำเนินการเพิ่มเติม เช่น การตรวจสอบประเภทหรือการสร้างโครงสร้างที่ซับซ้อนมากขึ้น ต่อไปนี้คือวิธีใช้งานการตั้งค่าบิลด์ประเภท 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)
)
การกำหนดแฟล็กสตริงแบบหลายชุด
การตั้งค่าสตริงมีพารามิเตอร์ allow_multiple เพิ่มเติม ซึ่งอนุญาตให้ตั้งค่าแฟล็กหลายครั้งในบรรทัดคำสั่งหรือใน bazelrc ค่าเริ่มต้นจะยังคงตั้งค่าด้วยแอตทริบิวต์ประเภทสตริง ดังนี้
# 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"
)
ระบบจะถือว่าการตั้งค่าแต่ละรายการของแฟล็กเป็นค่าเดียว ดังนี้
$ bazel build //my/target --//example:roasts=blonde \
--//example:roasts=medium,dark
ระบบจะแยกวิเคราะห์ข้อมูลข้างต้นเป็น {"//example:roasts": ["blonde", "medium,dark"]} และ
ctx.build_setting_value จะแสดงผลรายการ ["blonde", "medium,dark"]
การสร้างอินสแตนซ์การตั้งค่าบิลด์
กฎที่กำหนดด้วยพารามิเตอร์ build_setting มีแอตทริบิวต์ที่บังคับโดยนัย
build_setting_default แอตทริบิวต์นี้มีประเภทเดียวกับที่ประกาศโดยพารามิเตอร์ 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"
)
การตั้งค่าที่กำหนดไว้ล่วงหน้า
ไลบรารี Skylib มีชุดการตั้งค่าที่กำหนดไว้ล่วงหน้าซึ่งคุณสร้างอินสแตนซ์ได้โดยไม่ต้อง เขียน Starlark ที่กำหนดเอง
ตัวอย่างเช่น หากต้องการกำหนดการตั้งค่าที่ยอมรับค่าสตริงที่จำกัด ให้ทำดังนี้
# example/BUILD
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
string_flag(
name = "myflag",
values = ["a", "b", "c"],
build_setting_default = "a",
)
โปรดดูรายการทั้งหมดที่หัวข้อ กฎการตั้งค่าบิลด์ทั่วไป
การใช้การตั้งค่าบิลด์
ขึ้นอยู่กับการตั้งค่าบิลด์
หากเป้าหมายต้องการอ่านข้อมูลการกำหนดค่า เป้าหมายจะขึ้นอยู่กับการตั้งค่าบิลด์ได้โดยตรงผ่านการขึ้นต่อกันของแอตทริบิวต์ปกติ
# 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",
)
ภาษาต่างๆ อาจต้องการสร้างชุดการตั้งค่าบิลด์ที่เป็นมาตรฐานซึ่งกฎทั้งหมดสำหรับภาษานั้นขึ้นอยู่ด้วย แม้ว่าแนวคิดดั้งเดิมของ fragments จะไม่มีอยู่อีกต่อไปในฐานะออบเจ็กต์ที่ฮาร์ดโค้ดไว้ในโลกของการกำหนดค่า Starlark แต่วิธีหนึ่งในการแปลแนวคิดนี้คือการใช้ชุดแอตทริบิวต์โดยนัยทั่วไป ตัวอย่างเช่น
# 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)
การใช้การตั้งค่าการสร้างในบรรทัดคำสั่ง
คุณสามารถใช้บรรทัดคำสั่งเพื่อตั้งค่าการสร้าง
ที่ทำเครื่องหมายเป็นแฟล็กได้เช่นเดียวกับแฟล็กดั้งเดิมส่วนใหญ่ ชื่อของการตั้งค่าการสร้างคือเส้นทางเป้าหมายแบบเต็มโดยใช้ไวยากรณ์ name=value ดังนี้
$ bazel build //my/target --//example:string_flag=some-value # allowed
$ bazel build //my/target --//example:string_flag some-value # not allowed
ระบบรองรับไวยากรณ์บูลีนพิเศษ ดังนี้
$ bazel build //my/target --//example:boolean_flag
$ bazel build //my/target --no//example:boolean_flag
การใช้นามแฝงของการตั้งค่าบิลด์
คุณสามารถตั้งนามแฝงสำหรับเส้นทางเป้าหมายของการตั้งค่าการสร้างเพื่อให้ผู้ใช้สามารถอ่านได้ง่ายขึ้นในบรรทัดคำสั่ง นามแฝงทำงานคล้ายกับแฟล็กดั้งเดิมและใช้ไวยากรณ์ตัวเลือกขีดกลาง 2 ขีดด้วย
ตั้งนามแฝงโดยเพิ่ม --flag_alias=ALIAS_NAME=TARGET_PATH ลงใน .bazelrc ตัวอย่างเช่น หากต้องการตั้งอีเมลแทนเป็น coffee ให้ทำดังนี้
# .bazelrc
build --flag_alias=coffee=//experimental/user/starlark_configurations/basic_build_setting:coffee-temp
แนวทางปฏิบัติแนะนำ: การตั้งนามแฝงหลายครั้งจะทำให้รายการล่าสุดมีความสำคัญสูงสุด ใช้ชื่อนามแฝงที่ไม่ซ้ำกันเพื่อหลีกเลี่ยงผลการแยกวิเคราะห์ที่ไม่ต้องการ
หากต้องการใช้นามแฝง ให้พิมพ์นามแฝงแทนเส้นทางเป้าหมายของการตั้งค่าการสร้าง
โดยใช้ตัวอย่าง coffee ที่ตั้งไว้ใน .bazelrc ของผู้ใช้ข้างต้น
$ bazel build //my/target --coffee=ICED
แทนที่จะเป็น
$ bazel build //my/target --//experimental/user/starlark_configurations/basic_build_setting:coffee-temp=ICED
แนวทางปฏิบัติแนะนำ: แม้ว่าจะตั้งนามแฝงในบรรทัดคำสั่งได้ แต่การเก็บนามแฝงไว้ใน .bazelrc จะช่วยลดความยุ่งเหยิงในบรรทัดคำสั่ง
การตั้งค่าบิลด์ประเภทป้ายกำกับ
การตั้งค่าประเภทป้ายกำกับไม่สามารถกำหนดได้โดยใช้พารามิเตอร์กฎ build_setting ซึ่งแตกต่างจากการตั้งค่าบิลด์อื่นๆ แต่ Bazel มีกฎในตัว 2 ข้อ ได้แก่ label_flag และ label_setting กฎเหล่านี้จะส่งต่อผู้ให้บริการของเป้าหมายจริงที่ตั้งค่าการสร้างไว้ การเปลี่ยนสามารถอ่าน/เขียน label_flag และ label_setting ได้ และผู้ใช้สามารถตั้งค่า label_flag ได้เช่นเดียวกับกฎ build_setting อื่นๆ ความแตกต่างเพียงอย่างเดียวคือไม่สามารถกำหนดเองได้
การตั้งค่าประเภทป้ายกำกับจะแทนที่ฟังก์ชันการทำงานของค่าเริ่มต้นที่ผูกไว้ในภายหลังในที่สุด แอตทริบิวต์ค่าเริ่มต้นที่ผูกไว้ในภายหลังคือแอตทริบิวต์ประเภทป้ายกำกับซึ่งค่าสุดท้ายอาจได้รับผลกระทบจากการกำหนดค่า ใน Starlark การตั้งค่านี้จะแทนที่
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"
)
การตั้งค่าบิลด์และ select()
ผู้ใช้สามารถกำหนดค่าแอตทริบิวต์ในการตั้งค่าบิลด์ได้โดยใช้
select() คุณส่งเป้าหมายการตั้งค่าบิลด์ไปยังแอตทริบิวต์ flag_values ของ config_setting ได้ ค่าที่จะจับคู่กับการกำหนดค่าจะส่งเป็น String จากนั้นแยกวิเคราะห์เป็นประเภทของการตั้งค่าการสร้างเพื่อการจับคู่
config_setting(
name = "my_config",
flag_values = {
"//example:favorite_flavor": "MANGO"
}
)
การเปลี่ยนที่ผู้ใช้กำหนด
การเปลี่ยนการกำหนดค่า จะแมปการแปลงจากเป้าหมายที่กำหนดค่าเป้าหมายหนึ่งไปยังอีกเป้าหมายหนึ่งภายใน กราฟการสร้าง
การกำหนด
การเปลี่ยนจะกำหนดการเปลี่ยนแปลงการกำหนดค่าระหว่างกฎ ตัวอย่างเช่น การเปลี่ยนจะจัดการคำขอ เช่น "คอมไพล์ทรัพยากร Dependency ของฉันสำหรับ CPU อื่นที่ไม่ใช่ระดับบน"
อย่างเป็นทางการ การเปลี่ยนคือฟังก์ชันจากการกำหนดค่าอินพุตเป็นการกำหนดค่าเอาต์พุตอย่างน้อย 1 รายการ การเปลี่ยนส่วนใหญ่เป็นการเปลี่ยนแบบ 1:1 เช่น "ลบล้างการกำหนดค่าอินพุตด้วย --cpu=ppc" การเปลี่ยนแบบ 1:2 ขึ้นไปก็อาจมีอยู่เช่นกัน แต่มีข้อจำกัดพิเศษ
ใน Starlark การเปลี่ยนจะกำหนดไว้คล้ายกับกฎ โดยมีฟังก์ชัน
transition()
ที่กำหนด
และฟังก์ชันการใช้งาน
# 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"]
)
ฟังก์ชัน transition() จะใช้ฟังก์ชันการใช้งาน ชุดการตั้งค่าการสร้างที่จะอ่าน(inputs) และชุดการตั้งค่าการสร้างที่จะเขียน (outputs) ฟังก์ชันการใช้งานมีพารามิเตอร์ 2 รายการ ได้แก่ settings และ attr settings คือพจนานุกรม {String:Object} ของการตั้งค่าทั้งหมดที่ประกาศในพารามิเตอร์ inputs เป็น transition()
attr คือพจนานุกรมของแอตทริบิวต์และค่าของกฎที่แนบการเปลี่ยนไว้ เมื่อแนบเป็นการเปลี่ยนขอบขาออก ค่าของแอตทริบิวต์เหล่านี้จะได้รับการกำหนดค่าทั้งหมดหลังจากการแก้ปัญหา select() เมื่อแนบเป็นการเปลี่ยนขอบขาเข้า
`attr` จะไม่รวมแอตทริบิวต์ใดๆ ที่ใช้ตัวเลือกเพื่อแก้ค่าattr หากการเปลี่ยนขอบขาเข้าใน --foo อ่านแอตทริบิวต์ bar แล้วเลือก --foo เพื่อตั้งค่าแอตทริบิวต์ bar ด้วย ก็อาจมีการเปลี่ยนขอบขาเข้าเพื่ออ่านค่า bar ที่ไม่ถูกต้องในการเปลี่ยน
ฟังก์ชันการใช้งานต้องแสดงผลพจนานุกรม (หรือรายการพจนานุกรม ในกรณีของการเปลี่ยนที่มีการกำหนดค่าเอาต์พุตหลายรายการ) ของค่าการตั้งค่าบิลด์ใหม่ที่จะนำไปใช้ ชุดคีย์ของพจนานุกรมที่แสดงผลต้องมีชุดการตั้งค่าบิลด์ที่ส่งไปยังพารามิเตอร์ outputs ของฟังก์ชันการเปลี่ยนอย่างแน่นอน ข้อกำหนดนี้เป็นจริงแม้ว่าการตั้งค่าบิลด์จะไม่มีการเปลี่ยนแปลงจริงตลอดการเปลี่ยนผ่านก็ตาม ค่าเดิมจะต้องส่งผ่านอย่างชัดเจนในพจนานุกรมที่แสดงผล
การกำหนดการเปลี่ยนแบบ 1:2 ขึ้นไป
การเปลี่ยนขอบขาออก สามารถแมปการกำหนดค่าอินพุตเดียวกับการกำหนดค่าเอาต์พุตอย่างน้อย 2 รายการ ซึ่งมีประโยชน์สำหรับการกำหนดกฎที่รวมโค้ดหลายสถาปัตยกรรม
การเปลี่ยนแบบ 1:2 ขึ้นไปจะกำหนดโดยการแสดงผลรายการพจนานุกรมในฟังก์ชันการใช้งานการเปลี่ยน
# 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"]
)
นอกจากนี้ยังตั้งค่าคีย์ที่กำหนดเองซึ่งฟังก์ชันการใช้งานกฎสามารถใช้เพื่ออ่านทรัพยากร Dependency แต่ละรายการได้ด้วย ดังนี้
# 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"]
)
การแนบการเปลี่ยน
คุณแนบการเปลี่ยนได้ 2 ที่ ได้แก่ ขอบขาเข้าและขอบขาออก ซึ่งหมายความว่ากฎสามารถเปลี่ยนการกำหนดค่าของตัวเอง (การเปลี่ยนขอบขาเข้า) และเปลี่ยนการกำหนดค่าของทรัพยากร Dependency (การเปลี่ยนขอบขาออก) ได้อย่างมีประสิทธิภาพ
หมายเหตุ: ปัจจุบันยังไม่มีวิธีแนบการเปลี่ยน Starlark กับกฎดั้งเดิม หากต้องการทำเช่นนี้ โปรดติดต่อ bazel-discuss@googlegroups.com เพื่อขอความช่วยเหลือในการหาวิธีแก้ปัญหา
การเปลี่ยนขอบขาเข้า
การเปลี่ยนขอบขาเข้าจะเปิดใช้งานโดยการแนบออบเจ็กต์ transition
(สร้างโดย transition()) กับพารามิเตอร์ cfg ของ rule() ดังนี้
# example/rules.bzl
load("example/transitions:transitions.bzl", "hot_chocolate_transition")
drink_rule = rule(
implementation = _impl,
cfg = hot_chocolate_transition,
...
การเปลี่ยนขอบขาเข้าต้องเป็นการเปลี่ยนแบบ 1:1
การเปลี่ยนขอบขาออก
การเปลี่ยนขอบขาออกจะเปิดใช้งานโดยการแนบออบเจ็กต์ transition
(สร้างโดย transition()) กับพารามิเตอร์ cfg ของแอตทริบิวต์ ดังนี้
# example/rules.bzl
load("example/transitions:transitions.bzl", "coffee_transition")
drink_rule = rule(
implementation = _impl,
attrs = { "dep": attr.label(cfg = coffee_transition)}
...
การเปลี่ยนขอบขาออกอาจเป็นการเปลี่ยนแบบ 1:1 หรือ 1:2 ขึ้นไป
โปรดดูวิธีอ่านคีย์เหล่านี้ได้ที่หัวข้อการเข้าถึงแอตทริบิวต์ด้วยการเปลี่ยน
การเปลี่ยนในตัวเลือกดั้งเดิม
การเปลี่ยน Starlark ยังประกาศการอ่านและการเขียนในตัวเลือกการกำหนดค่าการสร้างดั้งเดิมได้ด้วยผ่านคำนำหน้าพิเศษสำหรับชื่อตัวเลือก
# 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"]
ตัวเลือกดั้งเดิมที่ไม่รองรับ
Bazel ไม่รองรับการเปลี่ยนใน --define ด้วย
"//command_line_option:define" ให้ใช้การตั้งค่าการสร้างที่กำหนดเองแทน
โดยทั่วไป เราไม่แนะนำให้ใช้ --define ในรูปแบบใหม่ และแนะนำให้ใช้การตั้งค่าบิลด์แทน
Bazel ไม่รองรับการเปลี่ยนใน --config เนื่องจาก --config เป็นแฟล็ก "การขยาย" ที่ขยายเป็นแฟล็กอื่นๆ
สิ่งสำคัญคือ --config อาจมีแฟล็กที่ไม่ส่งผลต่อการกำหนดค่าบิลด์
เช่น
--spawn_strategy Bazel ได้รับการออกแบบมาให้ไม่สามารถผูกแฟล็กดังกล่าวกับเป้าหมายแต่ละรายการได้ ซึ่งหมายความว่าไม่มีวิธีที่สอดคล้องกันในการนำแฟล็กเหล่านี้ไปใช้ในการเปลี่ยน
วิธีแก้ปัญหาคือคุณสามารถระบุแฟล็กที่ เป็น ส่วนหนึ่งของการกำหนดค่าในการเปลี่ยนได้อย่างชัดเจน ซึ่งต้องดูแลการขยายของ --config ใน 2 ที่ ซึ่งเป็นข้อบกพร่องที่ทราบกันดีใน UI
การเปลี่ยนในการตั้งค่าการสร้างที่อนุญาตหลายรายการ
เมื่อตั้งค่าการสร้างที่ อนุญาตหลายค่า คุณต้องตั้งค่าด้วยรายการ
# 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"]
)
การเปลี่ยนแบบไม่มีการดำเนินการ
หากการเปลี่ยนแสดงผล {}, [] หรือ None แสดงว่าเป็นการย่อเพื่อคงการตั้งค่าทั้งหมดไว้ที่ค่าเดิม ซึ่งอาจสะดวกกว่าการตั้งค่าเอาต์พุตแต่ละรายการเป็นค่าเดิมอย่างชัดเจน
# 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",
]
)
การเข้าถึงแอตทริบิวต์ด้วยการเปลี่ยน
เมื่อแนบการเปลี่ยนกับขอบขาออก
(ไม่ว่าการเปลี่ยนจะเป็นแบบ 1:1 หรือ 1:2 ขึ้นไป) ระบบจะบังคับให้ ctx.attr เป็นรายการ
หากยังไม่ได้เป็น โดยลำดับขององค์ประกอบในรายการนี้ไม่ได้ระบุไว้
# 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)
})
หากการเปลี่ยนเป็น 1:2+ และตั้งค่าคีย์ที่กำหนดเอง คุณจะใช้ ctx.split_attr เพื่ออ่านการขึ้นต่อกันแต่ละรายการสำหรับแต่ละคีย์ได้ ดังนี้
# 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)
})
ดูตัวอย่างที่สมบูรณ์ ได้ที่นี่
การผสานรวมกับแพลตฟอร์มและชุดเครื่องมือ
แฟล็กดั้งเดิมจำนวนมากในปัจจุบัน เช่น --cpu และ --crosstool_top เกี่ยวข้องกับการแก้ปัญหา Toolchain ในอนาคต การเปลี่ยนที่ชัดเจนในแฟล็กประเภทเหล่านี้
จะถูกแทนที่ด้วยการเปลี่ยนใน
แพลตฟอร์มเป้าหมาย
สิ่งที่ควรพิจารณาเกี่ยวกับหน่วยความจำและประสิทธิภาพ
การเพิ่มการเปลี่ยนและดังนั้นการกำหนดค่าใหม่ลงในการสร้างจะมีค่าใช้จ่าย ได้แก่ กราฟการสร้างที่ใหญ่ขึ้น กราฟการสร้างที่เข้าใจยากขึ้น และการสร้างที่ช้าลง คุณควรพิจารณาค่าใช้จ่ายเหล่านี้เมื่อพิจารณาใช้การเปลี่ยนผ่านในกฎบิลด์ของคุณ ด้านล่างนี้คือตัวอย่างวิธีที่การเปลี่ยนอาจทำให้กราฟบิลด์ของคุณเติบโตแบบทวีคูณ
การสร้างที่มีลักษณะการทำงานไม่ดี: กรณีศึกษา

รูปที่ 1 กราฟความสามารถในการปรับขนาดที่แสดงเป้าหมายระดับบนสุดและการขึ้นต่อกัน
กราฟนี้แสดงเป้าหมายระดับบนสุด //pkg:app ซึ่งขึ้นอยู่กับเป้าหมาย 2 รายการ ได้แก่ //pkg:1_0 และ //pkg:1_1 เป้าหมายทั้ง 2 รายการนี้ขึ้นอยู่กับเป้าหมาย 2 รายการ ได้แก่ //pkg:2_0 และ //pkg:2_1 เป้าหมายทั้ง 2 รายการนี้ขึ้นอยู่กับเป้าหมาย 2 รายการ ได้แก่ //pkg:3_0 และ //pkg:3_1
และดำเนินการต่อไปจนถึง //pkg:n_0 และ //pkg:n_1 ซึ่งทั้ง 2 รายการขึ้นอยู่กับเป้าหมายเดียว ได้แก่ //pkg:dep
การสร้าง //pkg:app ต้องใช้ \(2n+2\) เป้าหมายต่อไปนี้
//pkg:app//pkg:dep//pkg:i_0และ//pkg:i_1สำหรับ \(i\) in \([1..n]\)
ลองนึกภาพว่าคุณ ใช้ แฟล็ก
--//foo:owner=<STRING> และ //pkg:i_b ใช้
depConfig = myConfig + depConfig.owner="$(myConfig.owner)$(b)"
กล่าวอีกนัยหนึ่งคือ //pkg:i_b จะเพิ่ม b ลงในค่าเดิมของ --owner สำหรับการขึ้นต่อกันทั้งหมด
ซึ่งจะสร้างเป้าหมายที่กำหนดค่าไว้ต่อไปนี้:
//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 สร้างเป้าหมายที่กำหนดค่าไว้ \(2^n\) : config.owner=
"\(b_0b_1...b_n\)" สำหรับin \(\{0,1\}\) \(b_i\)
ซึ่งจะทำให้กราฟการสร้างมีขนาดใหญ่กว่ากราฟเป้าหมายแบบทวีคูณ พร้อมผลกระทบต่อหน่วยความจำและประสิทธิภาพที่เกี่ยวข้อง
สิ่งที่ต้องทำ: เพิ่มกลยุทธ์สำหรับการวัดผลและการลดปัญหาเหล่านี้
อ่านเพิ่มเติม
โปรดดูรายละเอียดเพิ่มเติมเกี่ยวกับการแก้ไขการกำหนดค่าการสร้างได้ที่หัวข้อต่อไปนี้
- การกำหนดค่าการสร้าง Starlark
- โรดแมปความสามารถในการกำหนดค่าของ Bazel
- ตัวอย่างแบบครบวงจรทั้งหมด set