หน้านี้อธิบายเฟรมเวิร์กของชุดเครื่องมือ ซึ่งเป็นวิธีที่ผู้เขียนกฎใช้ในการ แยกตรรกะของกฎออกจากเครื่องมือที่เลือกตามแพลตฟอร์ม เราขอแนะนำให้อ่านหน้ากฎและแพลตฟอร์ม ก่อนดำเนินการต่อ หน้านี้จะอธิบายเหตุผลที่ต้องใช้ Toolchain วิธี กำหนดและใช้ Toolchain รวมถึงวิธีที่ Bazel เลือก Toolchain ที่เหมาะสมตาม ข้อจำกัดของแพลตฟอร์ม
แรงจูงใจ
ก่อนอื่นมาดูปัญหาที่เครื่องมือเชนได้รับการออกแบบมาเพื่อแก้ไขกัน สมมติว่าคุณ
กำลังเขียนกฎเพื่อรองรับภาษาโปรแกรม "bar" bar_binary
กฎจะคอมไพล์ไฟล์ *.bar
โดยใช้คอมไพเลอร์ barc
ซึ่งเป็นเครื่องมือที่สร้างขึ้นเป็นอีกเป้าหมายหนึ่งในพื้นที่ทํางานของคุณ
เนื่องจากผู้ใช้ที่เขียนbar_binary
เป้าหมายไม่ควรต้องระบุการขึ้นต่อกันในคอมไพเลอร์ คุณจึงทำให้เป็น
การขึ้นต่อกันโดยนัยได้ด้วยการเพิ่มลงในการกำหนดกฎเป็นแอตทริบิวต์ส่วนตัว
bar_binary = rule(
implementation = _bar_binary_impl,
attrs = {
"srcs": attr.label_list(allow_files = True),
...
"_compiler": attr.label(
default = "//bar_tools:barc_linux", # the compiler running on linux
providers = [BarcInfo],
),
},
)
ตอนนี้ //bar_tools:barc_linux
เป็นทรัพยากรที่ต้องใช้ของเป้าหมาย bar_binary
ทุกรายการ ดังนั้นระบบจะสร้าง //bar_tools:barc_linux
ก่อนเป้าหมาย bar_binary
ซึ่งสามารถเข้าถึงได้โดยฟังก์ชันการติดตั้งใช้งานของกฎ
เช่นเดียวกับแอตทริบิวต์อื่นๆ
BarcInfo = provider(
doc = "Information about how to invoke the barc compiler.",
# In the real world, compiler_path and system_lib might hold File objects,
# but for simplicity they are strings for this example. arch_flags is a list
# of strings.
fields = ["compiler_path", "system_lib", "arch_flags"],
)
def _bar_binary_impl(ctx):
...
info = ctx.attr._compiler[BarcInfo]
command = "%s -l %s %s" % (
info.compiler_path,
info.system_lib,
" ".join(info.arch_flags),
)
...
ปัญหาในที่นี้คือป้ายกำกับของคอมไพเลอร์ได้รับการฮาร์ดโค้ดใน bar_binary
แต่
เป้าหมายที่แตกต่างกันอาจต้องใช้คอมไพเลอร์ที่แตกต่างกัน ทั้งนี้ขึ้นอยู่กับแพลตฟอร์มที่สร้างเป้าหมายและแพลตฟอร์มที่สร้างเป้าหมาย ซึ่งเรียกว่าแพลตฟอร์มเป้าหมายและแพลตฟอร์มการดำเนินการตามลำดับ นอกจากนี้ ผู้เขียนกฎ
ไม่จำเป็นต้องรู้จักเครื่องมือและแพลตฟอร์มที่มีอยู่ทั้งหมด ดังนั้น
จึงไม่สามารถฮาร์ดโค้ดไว้ในคำจำกัดความของกฎได้
โซลูชันที่อาจไม่ดีนักคือการผลักภาระให้ผู้ใช้โดยการทำให้แอตทริบิวต์ _compiler
ไม่เป็นส่วนตัว จากนั้นจึงจะสามารถฮาร์ดโค้ดเป้าหมายแต่ละรายการเพื่อสร้างสำหรับแพลตฟอร์มหนึ่งหรืออีกแพลตฟอร์มหนึ่ง
bar_binary(
name = "myprog_on_linux",
srcs = ["mysrc.bar"],
compiler = "//bar_tools:barc_linux",
)
bar_binary(
name = "myprog_on_windows",
srcs = ["mysrc.bar"],
compiler = "//bar_tools:barc_windows",
)
คุณสามารถปรับปรุงโซลูชันนี้ได้โดยใช้ select
เพื่อเลือก compiler
ตามแพลตฟอร์ม ดังนี้
config_setting(
name = "on_linux",
constraint_values = [
"@platforms//os:linux",
],
)
config_setting(
name = "on_windows",
constraint_values = [
"@platforms//os:windows",
],
)
bar_binary(
name = "myprog",
srcs = ["mysrc.bar"],
compiler = select({
":on_linux": "//bar_tools:barc_linux",
":on_windows": "//bar_tools:barc_windows",
}),
)
แต่การทำเช่นนี้เป็นเรื่องที่น่าเบื่อและอาจเป็นการขอให้ผู้ใช้ bar_binary
ทุกคนทำมากเกินไป
หากไม่ได้ใช้รูปแบบนี้อย่างสม่ำเสมอตลอดทั้งพื้นที่ทำงาน จะทำให้เกิด
บิลด์ที่ทำงานได้ดีบนแพลตฟอร์มเดียว แต่ล้มเหลวเมื่อขยายไปยัง
สถานการณ์แบบหลายแพลตฟอร์ม นอกจากนี้ ยังไม่แก้ปัญหาการเพิ่มการรองรับ
แพลตฟอร์มและคอมไพเลอร์ใหม่โดยไม่ต้องแก้ไขกฎหรือเป้าหมายที่มีอยู่
เฟรมเวิร์กของชุดเครื่องมือช่วยแก้ปัญหานี้ได้โดยการเพิ่มระดับ การเปลี่ยนเส้นทาง กล่าวโดยสรุปคือ คุณประกาศว่ากฎของคุณมีการขึ้นต่อกันแบบนามธรรม กับสมาชิกบางรายในตระกูลเป้าหมาย (ประเภท Toolchain) และ Bazel จะแก้ไขการขึ้นต่อกันนี้โดยอัตโนมัติเป็นเป้าหมายที่เฉพาะเจาะจง (Toolchain) ตาม ข้อจำกัดของแพลตฟอร์มที่เกี่ยวข้อง ทั้งผู้เขียนกฎและผู้เขียนเป้าหมาย ไม่จำเป็นต้องทราบชุดแพลตฟอร์มและชุดเครื่องมือทั้งหมดที่พร้อมใช้งาน
การเขียนกฎที่ใช้ Toolchain
ภายใต้เฟรมเวิร์กของ Toolchain แทนที่จะให้กฎขึ้นอยู่กับเครื่องมือโดยตรง กฎจะขึ้นอยู่กับประเภท Toolchain แทน ประเภท Toolchain คือเป้าหมายอย่างง่าย ที่แสดงถึงคลาสของเครื่องมือที่ทำหน้าที่เดียวกันสำหรับแพลตฟอร์มต่างๆ เช่น คุณสามารถประกาศประเภทที่แสดงถึงคอมไพเลอร์ Bar ได้ดังนี้
# By convention, toolchain_type targets are named "toolchain_type" and
# distinguished by their package path. So the full path for this would be
# //bar_tools:toolchain_type.
toolchain_type(name = "toolchain_type")
คำจำกัดความของกฎในส่วนก่อนหน้าได้รับการแก้ไขเพื่อให้ประกาศว่าใช้//bar_tools:toolchain_type
Toolchain แทนที่จะใช้คอมไพเลอร์เป็นแอตทริบิวต์
bar_binary = rule(
implementation = _bar_binary_impl,
attrs = {
"srcs": attr.label_list(allow_files = True),
...
# No `_compiler` attribute anymore.
},
toolchains = ["//bar_tools:toolchain_type"],
)
ตอนนี้ฟังก์ชันการใช้งานจะเข้าถึงการขึ้นตอนนี้ภายใต้ ctx.toolchains
แทน ctx.attr
โดยใช้ประเภท Toolchain เป็นคีย์
def _bar_binary_impl(ctx):
...
info = ctx.toolchains["//bar_tools:toolchain_type"].barcinfo
# The rest is unchanged.
command = "%s -l %s %s" % (
info.compiler_path,
info.system_lib,
" ".join(info.arch_flags),
)
...
ctx.toolchains["//bar_tools:toolchain_type"]
จะแสดงผลToolchainInfo
ผู้ให้บริการ
ของเป้าหมายใดก็ตามที่ Bazel แก้ไขการขึ้นต่อกันของ Toolchain ฟิลด์ของออบเจ็กต์
ToolchainInfo
จะได้รับการตั้งค่าตามกฎของเครื่องมือพื้นฐาน ในส่วนถัดไป
จะมีการกำหนดกฎนี้เพื่อให้มีฟิลด์ barcinfo
ที่ครอบคลุมออบเจ็กต์ BarcInfo
ขั้นตอนของ Bazel ในการแก้ไข Toolchain เป็นเป้าหมายอธิบายไว้ด้านล่าง มีเพียงเป้าหมายของเครื่องมือที่แก้ไขแล้วเท่านั้นที่กลายเป็น
การขึ้นต่อกันของเป้าหมาย bar_binary
ไม่ใช่พื้นที่ทั้งหมดของเครื่องมือที่อาจเป็นไปได้
เครื่องมือที่ต้องใช้และไม่บังคับ
โดยค่าเริ่มต้น เมื่อกฎแสดงการอ้างอิงประเภท Toolchain โดยใช้ป้ายกำกับเปล่า (ดังที่แสดงด้านบน) ระบบจะถือว่าประเภท Toolchain เป็นข้อบังคับ หาก Bazel ไม่พบ Toolchain ที่ตรงกัน (ดูการแก้ปัญหา Toolchain ด้านล่าง) สำหรับ Toolchain ประเภทที่จำเป็น จะถือว่าเป็นข้อผิดพลาดและระบบจะหยุดการวิเคราะห์
คุณสามารถประกาศการขึ้นต่อกันของประเภท Toolchain แบบไม่บังคับแทนได้ ดังนี้
bar_binary = rule(
...
toolchains = [
config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = False),
],
)
เมื่อไม่สามารถระบุประเภท Toolchain ที่ไม่บังคับได้ การวิเคราะห์จะดำเนินต่อไป และctx.toolchains["//bar_tools:toolchain_type"]
None
จะมีผลเป็น
ฟังก์ชัน config_common.toolchain_type
จะเป็นฟังก์ชันที่ต้องระบุโดยค่าเริ่มต้น
คุณใช้แบบฟอร์มต่อไปนี้ได้
- ประเภทเครื่องมือที่จำเป็น
toolchains = ["//bar_tools:toolchain_type"]
toolchains = [config_common.toolchain_type("//bar_tools:toolchain_type")]
toolchains = [config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = True)]
- ประเภท Toolchain ที่ไม่บังคับ
toolchains = [config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = False)]
bar_binary = rule(
...
toolchains = [
"//foo_tools:toolchain_type",
config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = False),
],
)
คุณยังผสมผสานรูปแบบในกฎเดียวกันได้ด้วย อย่างไรก็ตาม หากมีการระบุประเภท ชุดเครื่องมือเดียวกันหลายครั้ง ระบบจะใช้เวอร์ชันที่เข้มงวดที่สุด โดยที่เวอร์ชันที่ต้องระบุจะเข้มงวดกว่าเวอร์ชันที่ไม่บังคับ
การเขียนที่ใช้เครื่องมือ
Aspect มีสิทธิ์เข้าถึง API ของ Toolchain เดียวกันกับกฎ โดยคุณสามารถกำหนดประเภท Toolchain ที่จำเป็น เข้าถึง Toolchain ผ่านบริบท และใช้ Toolchain เพื่อสร้างการดำเนินการใหม่ได้
bar_aspect = aspect(
implementation = _bar_aspect_impl,
attrs = {},
toolchains = ['//bar_tools:toolchain_type'],
)
def _bar_aspect_impl(target, ctx):
toolchain = ctx.toolchains['//bar_tools:toolchain_type']
# Use the toolchain provider like in a rule.
return []
การกำหนดทูลเชน
หากต้องการกำหนด Toolchain บางอย่างสำหรับประเภท Toolchain ที่ต้องการ คุณต้องมี 3 สิ่งต่อไปนี้
กฎเฉพาะภาษาที่แสดงถึงประเภทของเครื่องมือหรือชุดเครื่องมือ ตาม ธรรมเนียมแล้ว ชื่อของกฎนี้จะลงท้ายด้วย "_toolchain"
- หมายเหตุ: กฎ
\_toolchain
สร้างการดำเนินการบิลด์ไม่ได้ แต่จะรวบรวมอาร์ติแฟกต์จากกฎอื่นๆ และส่งต่อให้กฎที่ใช้ Toolchain กฎดังกล่าวมีหน้าที่สร้างการดำเนินการบิลด์ทั้งหมด
- หมายเหตุ: กฎ
เป้าหมายหลายรายการของกฎประเภทนี้ ซึ่งแสดงถึงเวอร์ชันของเครื่องมือหรือชุดเครื่องมือสำหรับแพลตฟอร์มต่างๆ
สำหรับเป้าหมายแต่ละรายการดังกล่าว เป้าหมายที่เชื่อมโยงของกฎทั่วไป
toolchain
เพื่อระบุข้อมูลเมตาที่ใช้โดยเฟรมเวิร์ก Toolchaintoolchain
เป้าหมายนี้ยังอ้างอิงถึงtoolchain_type
ที่เชื่อมโยงกับเครื่องมือชุดนี้ด้วย ซึ่งหมายความว่ากฎ_toolchain
ที่ระบุจะเชื่อมโยงกับtoolchain_type
ใดก็ได้ และเฉพาะในอินสแตนซ์toolchain
ที่ใช้กฎ_toolchain
นี้เท่านั้นที่กฎจะเชื่อมโยงกับtoolchain_type
สำหรับตัวอย่างที่กำลังดำเนินการอยู่ นี่คือคำจำกัดความของbar_toolchain
กฎ
ตัวอย่างของเรามีเพียงคอมไพเลอร์ แต่เครื่องมืออื่นๆ เช่น Linker ก็อาจจัดกลุ่มไว้ใต้คอมไพเลอร์ได้เช่นกัน
def _bar_toolchain_impl(ctx):
toolchain_info = platform_common.ToolchainInfo(
barcinfo = BarcInfo(
compiler_path = ctx.attr.compiler_path,
system_lib = ctx.attr.system_lib,
arch_flags = ctx.attr.arch_flags,
),
)
return [toolchain_info]
bar_toolchain = rule(
implementation = _bar_toolchain_impl,
attrs = {
"compiler_path": attr.string(),
"system_lib": attr.string(),
"arch_flags": attr.string_list(),
},
)
กฎต้องแสดงผล ToolchainInfo
provider ซึ่งจะกลายเป็นออบเจ็กต์ที่กฎการใช้งานดึงข้อมูลโดยใช้ ctx.toolchains
และป้ายกำกับของประเภทเครื่องมือ ToolchainInfo
เช่น struct
สามารถเก็บคู่ฟิลด์-ค่าที่กำหนดเองได้
การระบุฟิลด์ที่เพิ่มลงใน ToolchainInfo
ควรมีการบันทึกอย่างชัดเจนที่ประเภทเครื่องมือ ในตัวอย่างนี้ ค่าจะแสดงในออบเจ็กต์ BarcInfo
เพื่อนำสคีมาที่กำหนดไว้ข้างต้นมาใช้ซ้ำ รูปแบบนี้อาจมีประโยชน์สำหรับการตรวจสอบและการนำโค้ดมาใช้ซ้ำ
ตอนนี้คุณกำหนดเป้าหมายสำหรับคอมไพเลอร์ barc
ที่เฉพาะเจาะจงได้แล้ว
bar_toolchain(
name = "barc_linux",
arch_flags = [
"--arch=Linux",
"--debug_everything",
],
compiler_path = "/path/to/barc/on/linux",
system_lib = "/usr/lib/libbarc.so",
)
bar_toolchain(
name = "barc_windows",
arch_flags = [
"--arch=Windows",
# Different flags, no debug support on windows.
],
compiler_path = "C:\\path\\on\\windows\\barc.exe",
system_lib = "C:\\path\\on\\windows\\barclib.dll",
)
สุดท้าย คุณสร้างtoolchain
คำจำกัดความสำหรับbar_toolchain
เป้าหมาย 2 รายการ
คำจำกัดความเหล่านี้จะลิงก์เป้าหมายเฉพาะภาษาเข้ากับประเภท Toolchain และ
ให้ข้อมูลข้อจำกัดที่บอก Bazel เมื่อ Toolchain เหมาะสมกับแพลตฟอร์มที่กำหนด
toolchain(
name = "barc_linux_toolchain",
exec_compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
target_compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
toolchain = ":barc_linux",
toolchain_type = ":toolchain_type",
)
toolchain(
name = "barc_windows_toolchain",
exec_compatible_with = [
"@platforms//os:windows",
"@platforms//cpu:x86_64",
],
target_compatible_with = [
"@platforms//os:windows",
"@platforms//cpu:x86_64",
],
toolchain = ":barc_windows",
toolchain_type = ":toolchain_type",
)
การใช้ไวยากรณ์เส้นทางแบบสัมพัทธ์ข้างต้นแสดงให้เห็นว่าคำจำกัดความเหล่านี้ทั้งหมดอยู่ในแพ็กเกจเดียวกัน แต่ไม่มีเหตุผลที่ประเภท Toolchain, เป้าหมาย Toolchain เฉพาะภาษา และเป้าหมายคำจำกัดความ toolchain
จะอยู่ในแพ็กเกจแยกกันไม่ได้
ดูตัวอย่างการใช้งานจริงได้ที่go_toolchain
ชุดเครื่องมือและการกำหนดค่า
คำถามสำคัญสำหรับผู้เขียนกฎคือ เมื่อมีการวิเคราะห์bar_toolchain
เป้าหมาย
การกำหนดค่าที่เห็นคืออะไร และควรใช้การเปลี่ยนผ่านใดสำหรับทรัพยากร Dependency ตัวอย่างข้างต้นใช้แอตทริบิวต์สตริง แต่จะเกิดอะไรขึ้นกับเครื่องมือที่ซับซ้อนกว่าซึ่งขึ้นอยู่กับเป้าหมายอื่นๆ ในที่เก็บ Bazel
มาดูเวอร์ชันที่ซับซ้อนกว่าของ bar_toolchain
กัน
def _bar_toolchain_impl(ctx):
# The implementation is mostly the same as above, so skipping.
pass
bar_toolchain = rule(
implementation = _bar_toolchain_impl,
attrs = {
"compiler": attr.label(
executable = True,
mandatory = True,
cfg = "exec",
),
"system_lib": attr.label(
mandatory = True,
cfg = "target",
),
"arch_flags": attr.string_list(),
},
)
การใช้ attr.label
จะเหมือนกับกฎมาตรฐาน
แต่ความหมายของพารามิเตอร์ cfg
จะแตกต่างกันเล็กน้อย
การอ้างอิงจากเป้าหมาย (เรียกว่า "พาเรนต์") ไปยัง Toolchain ผ่านการแก้ปัญหา Toolchain จะใช้การเปลี่ยนการกำหนดค่าพิเศษที่เรียกว่า "การเปลี่ยน Toolchain" การเปลี่ยน Toolchain จะทำให้การกำหนดค่าเหมือนเดิม ยกเว้น
บังคับให้แพลตฟอร์มการดำเนินการเหมือนกันสำหรับ Toolchain และสำหรับ
องค์กรหลัก (มิฉะนั้น การแก้ปัญหา Toolchain สำหรับ Toolchain อาจเลือกแพลตฟอร์มการดำเนินการใดก็ได้ และไม่จำเป็นต้องเหมือนกับองค์กรหลัก) ซึ่งจะช่วยให้exec
การขึ้นต่อกันของ Toolchain สามารถเรียกใช้ได้สำหรับการดำเนินการบิลด์ของ
พาเรนต์ด้วย การขึ้นต่อกันของเครื่องมือใดๆ ที่ใช้ cfg =
"target"
(หรือไม่ได้ระบุ cfg
เนื่องจาก "เป้าหมาย" เป็นค่าเริ่มต้น) จะ
สร้างขึ้นสำหรับแพลตฟอร์มเป้าหมายเดียวกันกับแพลตฟอร์มหลัก ซึ่งช่วยให้กฎของ Toolchain สามารถ
มีทั้งไลบรารี (แอตทริบิวต์system_lib
ด้านบน) และเครื่องมือ (แอตทริบิวต์
compiler
) ในกฎการสร้างที่ต้องการ ระบบจะลิงก์ไลบรารีของระบบ
เข้ากับอาร์ติแฟกต์สุดท้าย จึงต้องสร้างไลบรารีสำหรับแพลตฟอร์มเดียวกัน
ในขณะที่คอมไพเลอร์เป็นเครื่องมือที่เรียกใช้ระหว่างการสร้าง และต้อง
เรียกใช้บนแพลตฟอร์มการดำเนินการได้
การลงทะเบียนและการสร้างด้วย Toolchain
ตอนนี้คุณได้ประกอบบล็อกทั้งหมดแล้ว และเพียงแค่ต้องทำให้ Bazel สามารถเข้าถึงเครื่องมือต่างๆ ได้ในกระบวนการแก้ไข โดยทำได้ด้วยการ
ลงทะเบียน Toolchain ในไฟล์ MODULE.bazel
โดยใช้
register_toolchains()
หรือส่งป้ายกำกับของ Toolchain ในบรรทัดคำสั่ง
โดยใช้แฟล็ก --extra_toolchains
register_toolchains(
"//bar_tools:barc_linux_toolchain",
"//bar_tools:barc_windows_toolchain",
# Target patterns are also permitted, so you could have also written:
# "//bar_tools:all",
# or even
# "//bar_tools/...",
)
เมื่อใช้รูปแบบเป้าหมายเพื่อลงทะเบียน Toolchain ลำดับการลงทะเบียน Toolchain แต่ละรายการจะกำหนดโดยกฎต่อไปนี้
- ระบบจะลงทะเบียน Toolchain ที่กำหนดไว้ในแพ็กเกจย่อยของแพ็กเกจก่อน Toolchain ที่กำหนดไว้ในแพ็กเกจเอง
- ภายในแพ็กเกจ ระบบจะลงทะเบียน Toolchain ตามลำดับพจนานุกรมของชื่อ
ตอนนี้เมื่อคุณสร้างเป้าหมายที่ขึ้นอยู่กับประเภท Toolchain ระบบจะเลือก Toolchain ที่เหมาะสมตามเป้าหมายและแพลตฟอร์มการดำเนินการ
# my_pkg/BUILD
platform(
name = "my_target_platform",
constraint_values = [
"@platforms//os:linux",
],
)
bar_binary(
name = "my_bar_binary",
...
)
bazel build //my_pkg:my_bar_binary --platforms=//my_pkg:my_target_platform
Bazel จะเห็นว่า //my_pkg:my_bar_binary
สร้างขึ้นด้วยแพลตฟอร์มที่มี @platforms//os:linux
จึงจะแก้ไขการอ้างอิง //bar_tools:toolchain_type
ไปยัง //bar_tools:barc_linux_toolchain
ได้
ซึ่งจะสร้าง //bar_tools:barc_linux
แต่ไม่ใช่ //bar_tools:barc_windows
การแก้ไข Toolchain
สำหรับแต่ละเป้าหมายที่ใช้ Toolchain ขั้นตอนการแก้ปัญหา Toolchain ของ Bazel จะกำหนดการขึ้นต่อกันของ Toolchain ที่เฉพาะเจาะจงของเป้าหมาย กระบวนการนี้รับชุดประเภท Toolchain ที่จำเป็น แพลตฟอร์มเป้าหมาย รายการ แพลตฟอร์มการดำเนินการที่ใช้ได้ และรายการ Toolchain ที่ใช้ได้เป็นอินพุต เอาต์พุตของเครื่องมือนี้ คือ Toolchain ที่เลือกสำหรับ Toolchain แต่ละประเภท รวมถึงแพลตฟอร์มการดำเนินการที่เลือก สำหรับเป้าหมายปัจจุบัน
แพลตฟอร์มการดำเนินการและชุดเครื่องมือที่มีจะรวบรวมจาก
กราฟทรัพยากร Dependency ภายนอกผ่านการเรียกใช้
register_execution_platforms
และ
register_toolchains
ในไฟล์
MODULE.bazel
คุณยังระบุแพลตฟอร์มการดำเนินการและชุดเครื่องมือเพิ่มเติมใน
บรรทัดคำสั่งผ่าน
--extra_execution_platforms
และ
--extra_toolchains
ได้ด้วย
ระบบจะรวมแพลตฟอร์มโฮสต์เป็นแพลตฟอร์มการดำเนินการที่ใช้ได้โดยอัตโนมัติ
ระบบจะติดตามแพลตฟอร์มและชุดเครื่องมือที่พร้อมใช้งานเป็นรายการที่เรียงตามลำดับเพื่อความแน่นอน
โดยจะให้ความสำคัญกับรายการก่อนหน้าในรายการ
ระบบจะสร้างชุดเครื่องมือที่พร้อมใช้งานตามลำดับความสำคัญจาก
--extra_toolchains
และ register_toolchains
- ระบบจะเพิ่ม Toolchain ที่ลงทะเบียนโดยใช้
--extra_toolchains
ก่อน (ในเครื่องมือเหล่านี้ เครื่องมือ last จะมีลำดับความสำคัญสูงสุด) - Toolchain ที่ลงทะเบียนโดยใช้
register_toolchains
ในกราฟการอ้างอิงภายนอกแบบทรานซิทีฟ ตามลำดับต่อไปนี้ (ใน Toolchain เหล่านี้ Toolchain ที่กล่าวถึงเป็นอันดับแรกจะมีลำดับความสำคัญสูงสุด)- Toolchain ที่ลงทะเบียนโดยรูทโมดูล (เช่น
MODULE.bazel
ที่รูทของเวิร์กสเปซ) - Toolchain ที่ลงทะเบียนในไฟล์
WORKSPACE
ของผู้ใช้ รวมถึงในมาโครที่เรียกใช้จากที่นั่น - Toolchain ที่ลงทะเบียนโดยโมดูลที่ไม่ใช่รูท (เช่น Dependency ที่ระบุโดย โมดูลรูทและ Dependency ของโมดูลเหล่านั้น และอื่นๆ)
- Toolchain ที่ลงทะเบียนใน "คำต่อท้ายของ WORKSPACE" ซึ่งใช้โดย กฎดั้งเดิมบางอย่างที่มาพร้อมกับการติดตั้ง Bazel เท่านั้น
- Toolchain ที่ลงทะเบียนโดยรูทโมดูล (เช่น
หมายเหตุ: เป้าหมายเสมือน เช่น :all
, :*
และ
/...
จะเรียงตามกลไกการโหลดแพ็กเกจของ Bazel
ซึ่งใช้การเรียงตามพจนานุกรม
ขั้นตอนการแก้ปัญหามีดังนี้
ข้อ
target_compatible_with
หรือexec_compatible_with
จะตรงกันกับแพลตฟอร์มหากสำหรับแต่ละconstraint_value
ในรายการ แพลตฟอร์มก็มีconstraint_value
นั้นด้วย (ไม่ว่าจะระบุอย่างชัดเจนหรือเป็นค่าเริ่มต้น)หากแพลตฟอร์มมี
constraint_value
จากconstraint_setting
s ที่ไม่ได้ อ้างอิงโดยข้อกำหนด ข้อกำหนดเหล่านี้จะไม่มีผลต่อการจับคู่หากเป้าหมายที่สร้างระบุ
exec_compatible_with
แอตทริบิวต์ (หรือคำจำกัดความของกฎระบุอาร์กิวเมนต์exec_compatible_with
) ระบบจะกรองรายการแพลตฟอร์มการดำเนินการที่ใช้ได้เพื่อนำแพลตฟอร์มที่ไม่ตรงกับข้อจำกัดในการดำเนินการออกระบบจะกรองรายการ Toolchain ที่ใช้ได้เพื่อนำ Toolchain ที่ระบุ
target_settings
ซึ่งไม่ตรงกับการกำหนดค่าปัจจุบันออกสำหรับแพลตฟอร์มการดำเนินการที่ใช้ได้แต่ละแพลตฟอร์ม คุณจะเชื่อมโยงประเภทเชนเครื่องมือแต่ละประเภทกับ เชนเครื่องมือแรกที่ใช้ได้ (หากมี) ซึ่งเข้ากันได้กับแพลตฟอร์มการดำเนินการนี้ และแพลตฟอร์มเป้าหมาย
ระบบจะตัดแพลตฟอร์มการดำเนินการที่ไม่พบเครื่องมือเชนที่จำเป็นซึ่งเข้ากันได้ สำหรับเครื่องมือเชนประเภทใดประเภทหนึ่งออก ในบรรดาแพลตฟอร์มที่เหลือ แพลตฟอร์มแรกจะกลายเป็นแพลตฟอร์มการดำเนินการของเป้าหมายปัจจุบัน และเครื่องมือที่เชื่อมโยง (หากมี) จะกลายเป็นทรัพยากร Dependency ของเป้าหมาย
ระบบจะใช้แพลตฟอร์มการดำเนินการที่เลือกเพื่อเรียกใช้การดำเนินการทั้งหมดที่เป้าหมายสร้างขึ้น
ในกรณีที่สร้างเป้าหมายเดียวกันได้ในการกำหนดค่าหลายแบบ (เช่น สำหรับ CPU ต่างๆ) ภายในบิลด์เดียวกัน ระบบจะใช้กระบวนการแก้ไขกับเป้าหมายแต่ละเวอร์ชันแยกกัน
หากกฎใช้กลุ่มการดำเนินการ กลุ่มการดำเนินการแต่ละกลุ่มจะทำการแก้ไข Toolchain แยกกัน และแต่ละกลุ่มจะมีแพลตฟอร์มการดำเนินการและ Toolchain ของตัวเอง
เครื่องมือแก้ไขข้อบกพร่อง
หากต้องการเพิ่มการรองรับ Toolchain ลงในกฎที่มีอยู่ ให้ใช้แฟล็ก --toolchain_resolution_debug=regex
ในระหว่างการแก้ไข Toolchain แฟล็ก
จะแสดงเอาต์พุตแบบละเอียดสำหรับประเภท Toolchain หรือชื่อเป้าหมายที่ตรงกับตัวแปรนิพจน์ทั่วไป คุณ
ใช้ .*
เพื่อแสดงข้อมูลทั้งหมดได้ Bazel จะแสดงชื่อของ Toolchain ที่ตรวจสอบและข้ามในระหว่างกระบวนการแก้ไข
เช่น หากต้องการแก้ไขข้อบกพร่องในการเลือก Toolchain สำหรับการดำเนินการทั้งหมดที่สร้างโดยตรงโดย
//my:target
ให้ทำดังนี้
$ bazel build //my:all --toolchain_resolution_debug=//my:target
หากต้องการแก้ไขข้อบกพร่องในการเลือก Toolchain สำหรับการดำเนินการทั้งหมดในเป้าหมายการสร้างทั้งหมด ให้ทำดังนี้
$ bazel build //my:all --toolchain_resolution_debug=.*
หากต้องการดูว่าการขึ้นต่อกันของ cquery
รายการใดมาจากความละเอียดของ Toolchain
ให้ใช้แฟล็ก --transitions
ของ cquery
# Find all direct dependencies of //cc:my_cc_lib. This includes explicitly
# declared dependencies, implicit dependencies, and toolchain dependencies.
$ bazel cquery 'deps(//cc:my_cc_lib, 1)'
//cc:my_cc_lib (96d6638)
@bazel_tools//tools/cpp:toolchain (96d6638)
@bazel_tools//tools/def_parser:def_parser (HOST)
//cc:my_cc_dep (96d6638)
@local_config_platform//:host (96d6638)
@bazel_tools//tools/cpp:toolchain_type (96d6638)
//:default_host_platform (96d6638)
@local_config_cc//:cc-compiler-k8 (HOST)
//cc:my_cc_lib.cc (null)
@bazel_tools//tools/cpp:grep-includes (HOST)
# Which of these are from toolchain resolution?
$ bazel cquery 'deps(//cc:my_cc_lib, 1)' --transitions=lite | grep "toolchain dependency"
[toolchain dependency]#@local_config_cc//:cc-compiler-k8#HostTransition -> b6df211