หน้านี้ครอบคลุมถึงสิทธิประโยชน์และการใช้งานพื้นฐานของการกำหนดค่า 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()
การตั้งค่าการสร้างเป็นกฎเหมือนกับกฎอื่นๆ และแยกความแตกต่างโดยใช้ แอตทริบิวต์ของฟังก์ชัน rule() ของ Starlark build_setting
# 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 อื่นที่ไม่ใช่ 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 จะไม่รวมแอตทริบิวต์ใดๆ ที่ใช้ตัวเลือกเพื่อแก้ปัญหาค่า หากการเปลี่ยนขอบขาเข้าใน --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()) กับพารามิเตอร์ rule()'s cfg
# 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 ทั้งหมด \(b_i\) \(\{0,1\}\).
ซึ่งจะทำให้กราฟการสร้างมีขนาดใหญ่กว่ากราฟเป้าหมายแบบทวีคูณ พร้อมผลกระทบต่อหน่วยความจำและประสิทธิภาพที่เกี่ยวข้อง
สิ่งที่ต้องทำ: เพิ่มกลยุทธ์สำหรับการวัดผลและการลดผลกระทบของปัญหาเหล่านี้
อ่านเพิ่มเติม
โปรดดูรายละเอียดเพิ่มเติมเกี่ยวกับการแก้ไขการกำหนดค่าการสร้างได้ที่หัวข้อต่อไปนี้
- การกำหนดค่าการสร้าง Starlark
- โรดแมปความสามารถในการกำหนดค่าของ Bazel
- ชุดตัวอย่างแบบครบวงจร