หน้านี้อธิบายเฟรมเวิร์ก 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 เป็นการขึ้นอยู่ของเป้าหมาย 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"],
)
ตอนนี้ฟังก์ชันการใช้งานจะเข้าถึงทรัพยากร Dependency ภายใต้ 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 ตัวอย่างของเรามีเพียงคอมไพเลอร์ แต่เครื่องมืออื่นๆ เช่น ลิงเกอร์ก็อาจจัดกลุ่มไว้ภายใต้คอมไพเลอร์ได้เช่นกัน
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 ในไฟล์ WORKSPACE โดยใช้ 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",
)
ตอนนี้เมื่อคุณสร้างเป้าหมายที่ขึ้นอยู่กับประเภท 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 ที่พร้อมใช้งานจากไฟล์
WORKSPACEผ่าน
register_execution_platforms
และ
register_toolchains
นอกจากนี้ คุณยังระบุแพลตฟอร์มการดำเนินการและ Toolchain เพิ่มเติมใน
บรรทัดคำสั่งผ่าน
--extra_execution_platforms
และ
--extra_toolchainsได้ด้วย
ระบบจะรวมแพลตฟอร์มโฮสต์เป็นแพลตฟอร์มการดำเนินการที่พร้อมใช้งานโดยอัตโนมัติ
ระบบจะติดตามแพลตฟอร์มและ Toolchain ที่พร้อมใช้งานเป็นรายการที่เรียงลำดับเพื่อความแน่นอน โดยจะให้ความสำคัญกับรายการก่อนหน้าในรายการ
ขั้นตอนการแก้ปัญหามีดังนี้
ข้อความ
target_compatible_withหรือexec_compatible_withจะ ตรงกันกับแพลตฟอร์มหากแพลตฟอร์มมีconstraint_valueเดียวกันกับconstraint_valueแต่ละรายการในรายการ (ไม่ว่าจะระบุอย่างชัดเจนหรือเป็นค่าเริ่มต้น)หากแพลตฟอร์มมี
constraint_valueจากconstraint_settingที่ข้อความไม่ได้อ้างอิง ค่าเหล่านี้จะไม่ส่งผลต่อการจับคู่หากเป้าหมายที่สร้างระบุแอตทริบิวต์
exec_compatible_with(หรือคำจำกัดความของกฎระบุอาร์กิวเมนต์exec_compatible_with) ระบบจะกรองรายการแพลตฟอร์มการดำเนินการที่พร้อมใช้งานเพื่อนำ แพลตฟอร์มที่ไม่ตรงกับข้อจำกัดการดำเนินการออกสำหรับแพลตฟอร์มการดำเนินการที่พร้อมใช้งานแต่ละแพลตฟอร์ม คุณจะเชื่อมโยงประเภท Toolchain แต่ละประเภทกับ Toolchain แรกที่พร้อมใช้งาน (หากมี) ซึ่งเข้ากันได้กับแพลตฟอร์มการดำเนินการและแพลตฟอร์มเป้าหมายนี้
ระบบจะตัดแพลตฟอร์มการดำเนินการที่ไม่พบ Toolchain ที่จำเป็นที่เข้ากันได้สำหรับประเภท Toolchain ประเภทใดประเภทหนึ่งออก จากแพลตฟอร์มที่เหลือ แพลตฟอร์มแรกจะกลายเป็นแพลตฟอร์มการดำเนินการของเป้าหมายปัจจุบัน และ Toolchain ที่เชื่อมโยง (หากมี) จะกลายเป็นทรัพยากร Dependency ของเป้าหมาย
ระบบจะใช้แพลตฟอร์มการดำเนินการที่เลือกเพื่อเรียกใช้การดำเนินการทั้งหมดที่เป้าหมายสร้างขึ้น
ในกรณีที่สร้างเป้าหมายเดียวกันได้ในการกำหนดค่าหลายรายการ (เช่น สำหรับ CPU ต่างๆ) ภายในบิลด์เดียวกัน ระบบจะใช้ขั้นตอนการแก้ปัญหาแยกกันกับเป้าหมายแต่ละเวอร์ชัน
หากกฎใช้กลุ่มการดำเนินการ กลุ่มการดำเนินการแต่ละกลุ่มจะทำการแก้ปัญหา Toolchain แยกกัน และแต่ละกลุ่มจะมีแพลตฟอร์มการดำเนินการและ Toolchain ของตัวเอง
การแก้ไขข้อบกพร่องของ Toolchain
หากคุณกำลังเพิ่มการรองรับ Toolchain ลงในกฎที่มีอยู่ ให้ใช้แฟล็ก --toolchain_resolution_debug=regex ระหว่างการแก้ปัญหา Toolchain แฟล็กจะแสดงเอาต์พุตแบบละเอียดสำหรับประเภท Toolchain หรือชื่อเป้าหมายที่ตรงกับตัวแปร regex คุณสามารถใช้ .* เพื่อแสดงข้อมูลทั้งหมด Bazel จะแสดงชื่อ Toolchain ที่ตรวจสอบและข้ามระหว่างกระบวนการแก้ปัญหา
หากต้องการดูว่าทรัพยากร Dependency 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