หน้านี้ครอบคลุมประโยชน์และการใช้งานพื้นฐานของการกำหนดค่า Starlark API ของ Bazel สำหรับการปรับแต่งวิธีสร้างโปรเจ็กต์ ซึ่งรวมถึงวิธีการนิยาม การตั้งค่าบิลด์ และแสดงตัวอย่าง
วิธีนี้ช่วยให้คุณทำสิ่งต่อไปนี้ได้
- กำหนดแฟล็กที่กำหนดเอง
สำหรับโปรเจ็กต์ของคุณ
--define
- เขียน
การเปลี่ยน เพื่อกำหนดค่า Deps ใน
การกำหนดค่าแตกต่างจากรายการหลัก
(เช่น
--compilation_mode=opt
หรือ--cpu=arm
) - สร้างค่าเริ่มต้นที่ดีขึ้นให้เป็นกฎ (เช่น สร้าง
//my:android_app
โดยอัตโนมัติ ที่มี SDK ที่ระบุ)
และอีกมากมาย ทั้งหมดมาจากไฟล์ .bzl (ไม่ต้องใช้รุ่น Bazel) โปรดดู
ที่เก็บ bazelbuild/examples
สำหรับ
ตัวอย่าง
การตั้งค่าบิลด์ที่ผู้ใช้กำหนด
การตั้งค่าบิลด์เป็นส่วนเดียว
การกำหนดค่า
ให้คิดว่าการกำหนดค่าเป็นการแมปคีย์/ค่า การตั้งค่า --cpu=ppc
และ --copt="-DFoo"
จะสร้างการกำหนดค่าที่มีลักษณะดังนี้
{cpu: ppc, copt: "-DFoo"}
โดยแต่ละรายการคือการตั้งค่าบิลด์
ธงแบบเดิม เช่น cpu
และ copt
เป็นการตั้งค่าแบบเนทีฟ
มีการกำหนดคีย์และกำหนดค่าของคีย์ไว้ภายในโค้ด bazel Java แบบเนทีฟ
ผู้ใช้ Bazel จะอ่านและเขียนได้โดยใช้บรรทัดคำสั่งเท่านั้น
และ API อื่นๆ ที่ดูแลตามปกติ การเปลี่ยน Flag เนทีฟและ API
ที่เผยให้เห็นช่องโหว่ บิลด์ที่ผู้ใช้กำหนด
มีการกำหนดไว้ในไฟล์ .bzl
ไฟล์ (ดังนั้นจึงไม่จำเป็นต้องเผยแพร่ด้วย bazel
ลงทะเบียนการเปลี่ยนแปลง) นอกจากนี้ยังสามารถตั้งค่าผ่านบรรทัดคำสั่ง
(หากได้รับการกำหนดให้เป็น flags
โปรดดูข้อมูลเพิ่มเติมด้านล่าง) และยังสามารถเป็น
ตั้งค่าผ่านการเปลี่ยนที่กำหนดโดยผู้ใช้
การกำหนดการตั้งค่าบิลด์
พารามิเตอร์ rule()
build_setting
การตั้งค่าบิลด์เป็นกฎเช่นเดียวกับกฎอื่นๆ และแยกความแตกต่างโดยใช้
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)
)
การกำหนด Flag สตริงที่มีหลายชุด
การตั้งค่าสตริงมีพารามิเตอร์ allow_multiple
เพิ่มเติมซึ่งทำให้ฟิลด์
ตั้งค่า Flag หลายครั้งในบรรทัดคำสั่งหรือใน bazelrcs ค่าเริ่มต้นของหน่วยโฆษณา
ยังคงกำหนดด้วยแอตทริบิวต์ประเภทสตริง:
# 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"
)
การตั้งค่า Flag แต่ละรายการจะถือเป็นค่าเดียว
$ 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",
)
ดูรายการทั้งหมดได้ที่ กฎการตั้งค่าบิลด์ทั่วไป
กำลังใช้การตั้งค่าบิลด์
ขึ้นอยู่กับการตั้งค่าบิลด์
หากเป้าหมายต้องการอ่านข้อมูลการกำหนดค่า 1 ชิ้นจะสามารถ ขึ้นอยู่กับการตั้งค่าบิลด์ผ่านการอ้างอิงแอตทริบิวต์ทั่วไปโดยตรง
# 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
ใช้ชื่อแทนการตั้งค่าบิลด์
คุณสามารถตั้งค่าชื่อแทนสำหรับเส้นทางเป้าหมายในการตั้งค่าบิลด์เพื่อให้อ่านง่ายขึ้น ในบรรทัดคำสั่ง ชื่อแทนจะทำงานคล้ายกับ 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"
}
)
การเปลี่ยนที่ผู้ใช้กำหนด
การกำหนดค่า การเปลี่ยน แมปการเปลี่ยนรูปแบบจากเป้าหมายที่กำหนดค่าหนึ่งไปยังเป้าหมายอื่นภายใน กราฟบิลด์
กฎที่ตั้งค่าพารามิเตอร์ดังกล่าวต้องมีแอตทริบิวต์พิเศษต่อไปนี้
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist"
)
การเพิ่มทรานซิชันทำให้สามารถแตกขนาดของ กราฟบิลด์ของคุณ การดำเนินการนี้จะตั้งค่ารายการที่อนุญาตในแพ็กเกจที่คุณมีสิทธิ์ สร้างเป้าหมายของกฎนี้ได้ ค่าเริ่มต้นใน Codeblock ด้านบน อนุญาตทุกสิ่ง แต่หากคุณต้องการจำกัด ว่าใครจะใช้กฎของคุณ คุณจะตั้งค่าให้แอตทริบิวต์ดังกล่าวชี้ไปยังรายการที่อนุญาตที่คุณกำหนดเองได้ ติดต่อ bazel-discuss@googlegroups.com หากต้องการคำแนะนำหรือความช่วยเหลือ ทำความเข้าใจว่าการเปลี่ยนผ่าน ส่งผลต่อประสิทธิภาพบิลด์อย่างไร
การให้คำจำกัดความ
การเปลี่ยนจะกำหนดการเปลี่ยนแปลงการกำหนดค่าระหว่างกฎต่างๆ เช่น คำขอ เช่น "คอมไพล์ทรัพยากร Dependency สำหรับ CPU คนละตัวกับระดับบนสุด" จัดการโดย การเปลี่ยนแปลง
อย่างเป็นทางการ การเปลี่ยนคือฟังก์ชันจากการกำหนดค่าอินพุตเป็นหนึ่งหรือหลายรายการ
การกำหนดค่าเอาต์พุต การเปลี่ยนฉากส่วนใหญ่เป็นแบบ 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
เป็นพจนานุกรมแอตทริบิวต์และค่าของกฎที่ฟังก์ชัน
แนบการเปลี่ยนแล้ว เมื่อแนบเป็น
การเปลี่ยนขอบขาออก ค่าของกรณีเหล่านี้
จะมีความละเอียดหลังการเลือก() ทั้งหมดที่กำหนดค่าไว้ เมื่อแนบเป็น
การเปลี่ยนขอบขาเข้า attr
จะไม่
รวมแอตทริบิวต์ที่ใช้ตัวเลือกเพื่อแก้ไขค่า หากมี
การเปลี่ยน Edge ขาเข้าใน --foo
จะอ่านแอตทริบิวต์ bar
ตามด้วย
เลือกใน --foo
เพื่อตั้งค่าแอตทริบิวต์ bar
จึงมีโอกาสสำหรับ
การเปลี่ยน Edge ขาเข้าอ่านค่า 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 ที่ ได้แก่ ขอบขาเข้าและขอบขาออก อย่างมีประสิทธิภาพหมายความว่ากฎสามารถเปลี่ยนการกำหนดค่าของตนเอง (ขาเข้า EDGE) และเปลี่ยนการขึ้นต่อกันของ การกำหนดค่า (ขาออก การเปลี่ยนขอบ)
หมายเหตุ: ขณะนี้ยังไม่มีวิธีแนบการเปลี่ยนของ 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,
...
การเปลี่ยน EDGE ขาเข้าต้องเป็นการเปลี่ยนแบบ 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
อาจรวม Flag ที่ไม่ส่งผลต่อการกำหนดค่าบิลด์
เช่น
--spawn_strategy
ที่ใช้เวลาเพียง 2 นาที การออกแบบของ Bazel ทำให้ไม่สามารถเชื่อมโยง Flag ดังกล่าวกับเป้าหมายแต่ละรายการได้ ซึ่งหมายความว่า
ไม่มีวิธีที่สอดคล้องกันในการนำไปใช้ในการเปลี่ยนแปลง
ในการแก้ไขเบื้องต้น คุณจะระบุรายการแฟล็กที่เป็นอยู่ได้อย่างชัดเจน
การกำหนดค่าในการเปลี่ยนแปลงของคุณได้ การดำเนินการนี้ต้องมีการดูแลรักษา --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)
})
ดูตัวอย่างที่สมบูรณ์ ที่นี่
การผสานรวมกับแพลตฟอร์มและ Toolchain
แฟล็กเนทีฟจำนวนมากในปัจจุบัน เช่น --cpu
และ --crosstool_top
เกี่ยวข้องกับ
ของ Toolchain ในอนาคต การเปลี่ยนแปลงที่ชัดเจนเกี่ยวกับประเภท
จะถูกแทนที่ด้วยการเปลี่ยน
แพลตฟอร์มเป้าหมาย
ข้อควรพิจารณาเกี่ยวกับหน่วยความจำและประสิทธิภาพ
การเพิ่มการเปลี่ยนและการกำหนดค่าใหม่ให้กับบิลด์ของคุณมาพร้อมกับ ต้นทุน: กราฟสร้างที่ใหญ่กว่า กราฟสร้างไม่เข้าใจยาก และช้าลง งานสร้าง คุณควรคำนึงถึงค่าใช้จ่ายเหล่านี้เมื่อพิจารณา โดยใช้การเปลี่ยนในกฎการสร้าง ด้านล่างนี้เป็นตัวอย่างของการเปลี่ยนแปลง อาจสร้างการเติบโตแบบทวีคูณของกราฟบิลด์
งานสร้างที่ประพฤติไม่ดี: กรณีศึกษา
รูปที่ 1 กราฟความสามารถในการปรับขนาดแสดงเป้าหมายระดับบนสุดและทรัพยากร Dependency ของเป้าหมาย
กราฟนี้แสดงเป้าหมายระดับบนสุด ซึ่งก็คือ //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\) ใน \([1..n]\)
สมมติว่าคุณใช้ Flag
เป็นไปตาม--//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\)" สำหรับทุกคน \(b_i\) ใน \(\{0,1\}\)
ซึ่งทำให้กราฟบิลด์มีขนาดใหญ่กว่ากราฟเป้าหมายแบบทวีคูณ โดย หน่วยความจำและประสิทธิภาพที่เกี่ยวข้องกัน
สิ่งที่ต้องทำ: เพิ่มกลยุทธ์สำหรับการวัดผลและบรรเทาปัญหาเหล่านี้
อ่านเพิ่มเติม
ดูรายละเอียดเพิ่มเติมเกี่ยวกับการแก้ไขการกำหนดค่าบิลด์ได้ที่
- การกำหนดค่าบิลด์ของ Starlark
- แผนกลยุทธ์ด้านความสามารถในการกำหนดค่าของ Bazel
- ตัวอย่างแบบต้นทางถึงปลายทางทั้งชุด