หน้านี้อธิบายเฟรมเวิร์ก 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_tools:barc_linux ก่อนเป้าหมาย bar_binary ฟังก์ชันการใช้งานของกฎจะเข้าถึง `//bar_tools:barc_linux` ได้เหมือนกับแอตทริบิวต์อื่นๆ ดังนี้
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 แก้ปัญหานี้โดยเพิ่มระดับการอ้างอิงทางอ้อม โดยพื้นฐานแล้ว คุณจะประกาศว่ากฎมีการขึ้นอยู่แบบนามธรรมกับสมาชิก บางราย ของกลุ่มเป้าหมาย (ประเภท 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 เดียวกันหลายครั้ง ระบบจะใช้เวอร์ชันที่เข้มงวดที่สุด โดยที่บังคับจะเข้มงวดกว่าไม่บังคับ
การเขียนแง่มุมที่ใช้ Toolchain
แง่มุมต่างๆ มีสิทธิ์เข้าถึง 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 ตัวอย่างของเรามีเพียงคอมไพเลอร์ แต่เครื่องมืออื่นๆ เช่น ลิงเกอร์ก็อาจจัดกลุ่มไว้ภายใต้คอมไพเลอร์ได้เช่นกัน
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 ที่พร้อมใช้งานจาก กราฟทรัพยากร Dependency ภายนอกผ่าน 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ที่อนุประโยคไม่ได้อ้างอิง การดำเนินการนี้จะไม่ส่งผลต่อการจับคู่หากเป้าหมายที่กำลังสร้างระบุแ101
exec_compatible_withตริบิวต์ (หรือการกำหนดกฎระบุอ101exec_compatible_withกิวเมนต์)101ระบบจะกรองรายการแพลตฟอร์มการดำเนินการที่พร้อมใช้งานเพื่อนำ101แพลตฟอร์มที่ไม่ตรงกับข้อจำกัดการดำเนินการออกระบบจะกรองรายการ Toolchain ที่พร้อมใช้งานเพื่อนำ Toolchain ที่ระบุ
target_settingsซึ่งไม่ตรงกับการกำหนดค่าปัจจุบันออกสำหรับแพลตฟอร์มการดำเนินการที่พร้อมใช้งานแต่ละแพลตฟอร์ม ให้เชื่อมโยงประเภท Toolchain แต่ละประเภทกับ Toolchain แรกที่พร้อมใช้งาน (หากมี) ซึ่งเข้ากันได้กับแพลตฟอร์มการดำเนินการและแพลตฟอร์มเป้าหมาย
ระบบจะตัดแพลตฟอร์มการดำเนินการที่ไม่พบ Toolchain ที่บังคับที่เข้ากันได้สำหรับประเภท Toolchain อย่างน้อย 1 ประเภทออก จากแพลตฟอร์มที่เหลือ แพลตฟอร์มแรกจะกลายเป็นแพลตฟอร์มการดำเนินการของเป้าหมายปัจจุบัน และ Toolchain ที่เชื่อมโยง (หากมี) จะกลายเป็นทรัพยากร Dependency ของเป้าหมาย
ระบบจะใช้แพลตฟอร์มการดำเนินการที่เลือกเพื่อเรียกใช้การดำเนินการทั้งหมดที่เป้าหมายสร้างขึ้น
ในกรณีที่สร้างเป้าหมายเดียวกันได้ในการกำหนดค่าหลายรายการ (เช่น สำหรับ CPU ต่างๆ) ภายในบิลด์เดียวกัน ระบบจะใช้ขั้นตอนการแก้ปัญหาแยกกันกับเป้าหมายแต่ละเวอร์ชัน
หากกฎใช้กลุ่มการดำเนินการ กลุ่มการดำเนินการแต่ละกลุ่มจะทำการแก้ปัญหา Toolchain แยกกัน และแต่ละกลุ่มจะมีแพลตฟอร์มการดำเนินการและ Toolchain ของตัวเอง
การแก้ไขข้อบกพร่องของ Toolchain
หากคุณกำลังเพิ่มการรองรับ Toolchain ลงในกฎที่มีอยู่ ให้ใช้แฟล็ก --toolchain_resolution_debug=regex ระหว่างการแก้ปัญหา Toolchain แฟล็กจะแสดงเอาต์พุตแบบละเอียดสำหรับประเภท Toolchain หรือชื่อเป้าหมายที่ตรงกับตัวแปร regex คุณใช้ .* เพื่อแสดงข้อมูลทั้งหมดได้ Bazel จะแสดงชื่อ Toolchain ที่ตรวจสอบและข้ามระหว่างกระบวนการแก้ปัญหา
ตัวอย่างเช่น หากต้องการแก้ไขข้อบกพร่องการเลือก Toolchain สำหรับการดำเนินการทั้งหมดที่สร้างขึ้นโดยตรงโดย //my:target ให้ใช้คำสั่งต่อไปนี้
$ bazel build //my:all --toolchain_resolution_debug=//my:target
หากต้องการแก้ไขข้อบกพร่องการเลือก Toolchain สำหรับการดำเนินการทั้งหมดในเป้าหมายการสร้างทั้งหมด ให้ใช้คำสั่งต่อไปนี้
$ bazel build //my:all --toolchain_resolution_debug=.*
หากต้องการดูว่าทรัพยากร 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