หน้านี้อธิบายเฟรมเวิร์ก Toolchain ซึ่งเป็นวิธีที่ผู้เขียนกฎใช้แยกตรรกะของกฎออกจากเครื่องมือที่เลือกตามแพลตฟอร์ม เราขอแนะนำให้อ่านหน้า กฎและแพลตฟอร์ม ก่อนดำเนินการต่อ หน้านี้จะอธิบายเหตุผลที่ต้องใช้ Toolchain วิธีกำหนดและใช้ Toolchain รวมถึงวิธีที่ Bazel เลือก Toolchain ที่เหมาะสมตามข้อจำกัดของแพลตฟอร์ม
แรงจูงใจ
ก่อนอื่นเรามาดูปัญหาที่ Toolchain ได้รับการออกแบบมาเพื่อแก้ไข สมมติว่าคุณกำลังเขียนกฎเพื่อรองรับภาษาโปรแกรม "bar" กฎ bar_binary จะคอมไพล์ไฟล์ *.bar โดยใช้คอมไพเลอร์ barc ซึ่งเป็นเครื่องมือที่สร้างขึ้นเป็นเป้าหมายอื่นในพื้นที่ทำงาน เนื่องจากผู้ใช้ที่เขียนเป้าหมาย bar_binary ไม่ควรต้องระบุทรัพยากร Dependency กับคอมไพเลอร์ คุณจึงทำให้เป็นทรัพยากร Dependency โดยนัยโดยเพิ่มลงในการกำหนดกฎเป็นแอตทริบิวต์ส่วนตัว
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 เป็นทรัพยากร Dependency ของเป้าหมาย bar_binary ทุกรายการแล้ว ดังนั้นระบบจะสร้างเป้าหมายนี้ก่อนเป้าหมาย 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 แก้ไขปัญหานี้โดยเพิ่มระดับการอ้างอิงทางอ้อม โดยพื้นฐานแล้ว คุณประกาศว่ากฎของคุณมีทรัพยากร Dependency แบบนามธรรมกับสมาชิก บางรายของกลุ่มเป้าหมาย (ประเภท Toolchain) และ Bazel จะแก้ปัญหานี้โดยอัตโนมัติไปยังเป้าหมายที่เฉพาะเจาะจง (Toolchain) ตามข้อจำกัดของแพลตฟอร์มที่เกี่ยวข้อง ทั้งผู้เขียนกฎและผู้เขียนเป้าหมายไม่จำเป็นต้องทราบชุดแพลตฟอร์มและ 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")
การกำหนดกฎในส่วนก่อนหน้าได้รับการแก้ไขเพื่อให้ประกาศว่าใช้ Toolchain //bar_tools:toolchain_type แทนที่จะรับคอมไพเลอร์เป็นแอตทริบิวต์
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 แก้ปัญหาทรัพยากร Dependency ของ Toolchain กฎของเครื่องมือพื้นฐานจะเป็นผู้กำหนดช่องของออบเจ็กต์ ToolchainInfo ในส่วนถัดไป เราจะกำหนดกฎนี้เพื่อให้มีช่อง barcinfo ที่ครอบคลุมออบเจ็กต์ BarcInfo
ขั้นตอนของ Bazel ในการแก้ปัญหา Toolchain ไปยังเป้าหมายมีอธิบายไว้ด้านล่าง
เฉพาะเป้าหมาย Toolchain ที่แก้ปัญหาแล้วเท่านั้นที่จะกลายเป็นการขึ้นอยู่กับเป้าหมาย bar_binary ไม่ใช่พื้นที่ทั้งหมดของ Toolchain ที่เป็นไปได้
Toolchain ที่บังคับและไม่บังคับ
โดยค่าเริ่มต้น เมื่อกฎแสดงการขึ้นอยู่กับประเภท 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
จะเป็นแบบบังคับโดยค่าเริ่มต้น
คุณใช้รูปแบบต่อไปนี้ได้
- ประเภท Toolchain ที่บังคับ
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),
],
)
คุณยังใช้รูปแบบต่างๆ ร่วมกันในกฎเดียวกันได้ด้วย อย่างไรก็ตาม หากมีการระบุประเภท Toolchain เดียวกันหลายครั้ง ระบบจะใช้เวอร์ชันที่เข้มงวดที่สุด โดยที่แบบบังคับจะเข้มงวดกว่าแบบไม่บังคับ
การเขียน Aspect ที่ใช้ Toolchain
Aspect มีสิทธิ์เข้าถึง Toolchain API เดียวกับกฎ โดยคุณสามารถกำหนดประเภท 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 บางรายการสำหรับประเภท Toolchain ที่กำหนด คุณต้องมีสิ่งต่อไปนี้ 3 อย่าง
กฎเฉพาะภาษาที่แสดงถึงเครื่องมือหรือชุดเครื่องมือ โดยธรรมเนียมแล้ว ชื่อกฎนี้จะมีคำต่อท้ายเป็น "_toolchain"
- หมายเหตุ: กฎ
\_toolchainไม่สามารถสร้างการดำเนินการบิลด์ใดๆ ได้ แต่จะรวบรวมอาร์ติแฟกต์จากกฎอื่นๆ และส่งต่ออาร์ติแฟกต์เหล่านั้นไปยังกฎที่ใช้ Toolchain กฎดังกล่าวมีหน้าที่รับผิดชอบในการสร้างการดำเนินการสร้างทั้งหมด
- หมายเหตุ: กฎ
เป้าหมายหลายรายการของกฎประเภทนี้ ซึ่งแสดงถึงเครื่องมือหรือชุดเครื่องมือเวอร์ชันต่างๆ สำหรับแพลตฟอร์มต่างๆ
สำหรับเป้าหมายแต่ละรายการดังกล่าว เป้าหมายที่เชื่อมโยงของกฎทั่วไป
toolchainจะให้ข้อมูลเมตาที่เฟรมเวิร์ก Toolchain ใช้ เป้าหมายtoolchainนี้ยังอ้างอิงถึงtoolchain_typeที่เชื่อมโยงกับ Toolchain นี้ด้วย ซึ่งหมายความว่ากฎ_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 ซึ่งจะกลายเป็นออบเจ็กต์ที่กฎที่ใช้ดึงข้อมูลโดยใช้ ctx.toolchains และป้ายกำกับของประเภท Toolchain ToolchainInfo สามารถเก็บคู่คีย์-ค่าที่กำหนดเองได้เช่นเดียวกับ struct การระบุช่องที่จะเพิ่มลงใน ToolchainInfo ควรมีการระบุไว้อย่างชัดเจนที่ประเภท Toolchain ในตัวอย่างนี้ ค่าจะแสดงผลโดยครอบคลุมในออบเจ็กต์ 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
Toolchain และการกำหนดค่า
คำถามสำคัญสำหรับผู้เขียนกฎคือ เมื่อมีการวิเคราะห์เป้าหมาย bar_toolchain เป้าหมายจะเห็นการกำหนดค่าใด และควรใช้การเปลี่ยนผ่านใดสำหรับการขึ้นอยู่กัน ตัวอย่างด้านบนใช้แอตทริบิวต์สตริง แต่จะเกิดอะไรขึ้นกับ Toolchain ที่ซับซ้อนมากขึ้นซึ่งขึ้นอยู่กับเป้าหมายอื่นๆ ในที่เก็บ 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 จะแตกต่างกันเล็กน้อย
ทรัพยากร Dependency จากเป้าหมาย (เรียกว่า "รายการหลัก") ไปยัง Toolchain ผ่านการแก้ปัญหา Toolchain จะใช้การเปลี่ยนผ่านการกำหนดค่าพิเศษที่เรียกว่า "การเปลี่ยนผ่าน Toolchain" การเปลี่ยนผ่าน Toolchain จะรักษาการกำหนดค่าไว้เหมือนเดิม ยกเว้นว่าจะบังคับให้แพลตฟอร์มการดำเนินการเหมือนกันสำหรับ Toolchain และรายการหลัก (มิฉะนั้น การแก้ปัญหา Toolchain สำหรับ Toolchain อาจเลือกแพลตฟอร์มการดำเนินการใดก็ได้ และไม่จำเป็นต้องเหมือนกับรายการหลัก) การดำเนินการนี้ช่วยให้ทรัพยากร Dependency exec ของ Toolchain สามารถปฏิบัติการได้สำหรับการดำเนินการสร้างของรายการหลักด้วย การขึ้นอยู่กันของ Toolchain ที่ใช้ cfg =
"target" (หรือไม่ได้ระบุ cfg เนื่องจาก "target" เป็นค่าเริ่มต้น) จะ
สร้างขึ้นสำหรับแพลตฟอร์มเป้าหมายเดียวกันกับรายการหลัก การดำเนินการนี้ช่วยให้กฎ Toolchain สามารถมีส่วนร่วมทั้งไลบรารี (แอตทริบิวต์ system_lib ด้านบน) และเครื่องมือ (แอตทริบิวต์ compiler) ในกฎการสร้างที่จำเป็น ระบบจะลิงก์ไลบรารีของระบบเข้ากับอาร์ติแฟกต์สุดท้าย ดังนั้นจึงต้องสร้างขึ้นสำหรับแพลตฟอร์มเดียวกัน ในขณะที่คอมไพเลอร์เป็นเครื่องมือที่เรียกใช้ระหว่างการบิลด์ และต้องสามารถทำงานบนแพลตฟอร์มการดำเนินการได้
การลงทะเบียนและการสร้างด้วย Toolchain
ตอนนี้เราได้รวบรวมส่วนประกอบทั้งหมดแล้ว และคุณเพียงแค่ต้องทำให้ 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 แต่ละประเภท รวมถึงแพลตฟอร์มการดำเนินการที่เลือกสำหรับเป้าหมายปัจจุบัน
ระบบจะรวบรวมแพลตฟอร์มการดำเนินการและ Toolchain ที่ใช้ได้จาก กราฟการขึ้นอยู่กันภายนอกผ่าน register_execution_platforms และ register_toolchains การเรียกใน MODULE.bazel ไฟล์
นอกจากนี้ คุณยังระบุแพลตฟอร์มการดำเนินการและ Toolchain เพิ่มเติมใน
บรรทัดคำสั่งผ่าน
--extra_execution_platforms
และ
--extra_toolchainsได้ด้วย
ระบบจะรวมแพลตฟอร์มโฮสต์เป็นแพลตฟอร์มการดำเนินการที่ใช้ได้โดยอัตโนมัติ
ระบบจะติดตามแพลตฟอร์มและ Toolchain ที่ใช้ได้เป็นรายการที่เรียงลำดับเพื่อความแน่นอน โดยจะให้ความสำคัญกับรายการก่อนหน้าในรายการ
ระบบจะสร้างชุด Toolchain ที่ใช้ได้ตามลำดับความสำคัญจาก --extra_toolchains และ register_toolchains ดังนี้
- ระบบจะเพิ่ม Toolchain ที่ลงทะเบียนโดยใช้
--extra_toolchainsก่อน (Toolchain สุดท้าย ใน Toolchain เหล่านี้มีความสำคัญสูงสุด) - Toolchain ที่ลงทะเบียนโดยใช้
register_toolchainsในกราฟทรัพยากร Dependency ภายนอกแบบถ่ายทอด ในลำดับต่อไปนี้ (Toolchain แรก ที่กล่าวถึงใน Toolchain เหล่านี้มีความสำคัญสูงสุด)- Toolchain ที่ลงทะเบียนโดยโมดูลราก (เช่น
MODULE.bazelที่รูทของพื้นที่ทำงาน) - Toolchain ที่ลงทะเบียนในไฟล์
WORKSPACEของผู้ใช้ รวมถึงในมาโครที่เรียกใช้จากไฟล์ดังกล่าว - Toolchain ที่ลงทะเบียนโดยโมดูลที่ไม่ใช่ราก (เช่น การขึ้นอยู่กันที่ระบุโดยโมดูลราก และการขึ้นอยู่กันของโมดูลเหล่านั้น เป็นต้น)
- Toolchain ที่ลงทะเบียนใน "คำต่อท้าย WORKSPACE" ซึ่งใช้โดยกฎเนทีฟบางรายการที่รวมอยู่ในการติดตั้ง Bazel เท่านั้น
- Toolchain ที่ลงทะเบียนโดยโมดูลราก (เช่น
หมายเหตุ: ระบบจะจัดลำดับเป้าหมายเทียม เช่น :all, :* และ
/... ตามกลไกการโหลดแพ็กเกจ
ของ Bazel ซึ่งใช้การจัดลำดับตามตัวอักษร
ขั้นตอนการแก้ปัญหามีดังนี้
ข้อความ
target_compatible_withหรือexec_compatible_withจะ ตรงกันกับแพลตฟอร์มหากแพลตฟอร์มมีconstraint_valueเดียวกันกับconstraint_valueแต่ละรายการในรายการ (ไม่ว่าจะระบุอย่างชัดเจนหรือเป็นค่าเริ่มต้น)หากแพลตฟอร์มมี
constraint_valueจากconstraint_settingที่ข้อความไม่ได้อ้างอิง การดำเนินการนี้จะไม่ส่งผลต่อการจับคู่หากเป้าหมายที่สร้างระบุแอตทริบิวต์
exec_compatible_with(หรือการกำหนดกฎระบุอาร์กิวเมนต์exec_compatible_with) ระบบจะกรองรายการแพลตฟอร์มการดำเนินการที่ใช้ได้เพื่อนำ แพลตฟอร์มที่ไม่ตรงกับข้อจำกัดการดำเนินการออกระบบจะกรองรายการ Toolchain ที่ใช้ได้เพื่อนำ Toolchain ที่ระบุ
target_settingsซึ่งไม่ตรงกับการกำหนดค่าปัจจุบันออกสำหรับแพลตฟอร์มการดำเนินการแต่ละรายการที่ใช้ได้ ให้เชื่อมโยงประเภท Toolchain แต่ละประเภทกับ Toolchain แรกที่ใช้ได้ (หากมี) ซึ่งเข้ากันได้กับแพลตฟอร์มการดำเนินการนี้และแพลตฟอร์มเป้าหมาย
ระบบจะตัดแพลตฟอร์มการดำเนินการที่ไม่พบ Toolchain ที่บังคับที่เข้ากันได้สำหรับประเภท Toolchain ประเภทใดประเภทหนึ่งออก จากแพลตฟอร์มที่เหลือ แพลตฟอร์มแรกจะกลายเป็นแพลตฟอร์มการดำเนินการของเป้าหมายปัจจุบัน และ Toolchain ที่เชื่อมโยง (หากมี) จะกลายเป็นทรัพยากร Dependency ของเป้าหมาย
ระบบจะใช้แพลตฟอร์มการดำเนินการที่เลือกเพื่อเรียกใช้การดำเนินการทั้งหมดที่เป้าหมายสร้างขึ้น
ในกรณีที่สร้างเป้าหมายเดียวกันได้ในการกำหนดค่าหลายรายการ (เช่น สำหรับ CPU ต่างๆ) ภายในบิลด์เดียวกัน ระบบจะใช้ขั้นตอนการแก้ปัญหาแยกกันกับเป้าหมายแต่ละเวอร์ชัน
หากกฎใช้กลุ่มการดำเนินการ กลุ่มการดำเนินการแต่ละกลุ่มจะดำเนินการแก้ปัญหา Toolchain แยกกัน และแต่ละกลุ่มจะมีแพลตฟอร์มการดำเนินการและ Toolchain ของตัวเอง
การแก้ไขข้อบกพร่องของ Toolchain
หากคุณกำลังเพิ่มการรองรับ Toolchain ลงในกฎที่มีอยู่ ให้ใช้แฟล็ก --toolchain_resolution_debug=regex ระหว่างการแก้ปัญหา Toolchain แฟล็กจะแสดงเอาต์พุตแบบละเอียดสำหรับประเภท Toolchain หรือชื่อเป้าหมายที่ตรงกับตัวแปร regex คุณใช้ .* เพื่อแสดงข้อมูลทั้งหมดได้ Bazel จะแสดงชื่อ Toolchain ที่ตรวจสอบและข้ามระหว่างกระบวนการแก้ปัญหา
หากต้องการดูว่าทรัพยากร Dependency ของ cquery รายการใดมาจากการแก้ปัญหา Toolchain ให้ใช้ cquery's --transitions ดังนี้
# 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