หน้านี้อธิบายเฟรมเวิร์กของชุดเครื่องมือ ซึ่งเป็นวิธีที่ผู้เขียนกฎใช้ในการ แยกตรรกะของกฎออกจากเครื่องมือที่เลือกตามแพลตฟอร์ม เราขอแนะนำให้อ่านหน้ากฎและแพลตฟอร์ม ก่อนดำเนินการต่อ หน้านี้จะอธิบายเหตุผลที่ต้องใช้ Toolchain วิธี กำหนดและใช้ Toolchain รวมถึงวิธีที่ Bazel เลือก Toolchain ที่เหมาะสมตาม ข้อจำกัดของแพลตฟอร์ม
แรงจูงใจ
ก่อนอื่นมาดูปัญหาที่เครื่องมือเชนได้รับการออกแบบมาเพื่อแก้ไขกัน สมมติว่าคุณ
กำลังเขียนกฎเพื่อรองรับภาษาโปรแกรม "bar" bar_binary
กฎจะคอมไพล์ไฟล์ *.bar โดยใช้คอมไพเลอร์ barc ซึ่งเป็นเครื่องมือที่สร้างขึ้นเป็นอีกเป้าหมายหนึ่งในพื้นที่ทํางานของคุณ
เนื่องจากผู้ใช้ที่เขียน bar_binary
targets ไม่ควรต้องระบุการขึ้นต่อกันในคอมไพเลอร์ คุณจึงทำให้เป็น
การขึ้นต่อกันโดยนัยได้ด้วยการเพิ่มลงในการกำหนดกฎเป็นแอตทริบิวต์ส่วนตัว
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 ประเภทที่จำเป็น จะถือว่าเป็นข้อผิดพลาดและระบบจะหยุดการวิเคราะห์
คุณสามารถประกาศการขึ้นต่อกันของประเภทเครื่องมือเชนที่ไม่บังคับแทนได้ ดังนี้
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การขึ้นต่อกันของเครื่องมือสามารถเรียกใช้ได้สำหรับการดำเนินการบิลด์ของ
พาเรนต์ด้วย การขึ้นต่อกันของเครื่องมือใดๆ ที่ใช้ cfg =
"target" (หรือไม่ได้ระบุ cfg เนื่องจาก "เป้าหมาย" เป็นค่าเริ่มต้น) จะ
สร้างขึ้นสำหรับแพลตฟอร์มเป้าหมายเดียวกันกับแพลตฟอร์มหลัก ซึ่งช่วยให้กฎของ 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 ที่พร้อมใช้งานเป็นอินพุต เอาต์พุตของเครื่องมือนี้ คือชุดเครื่องมือที่เลือกสำหรับชุดเครื่องมือแต่ละประเภท รวมถึงแพลตฟอร์มการดำเนินการที่เลือก สำหรับเป้าหมายปัจจุบัน
ระบบจะรวบรวมแพลตฟอร์มการดำเนินการและชุดเครื่องมือที่พร้อมใช้งานจาก
กราฟทรัพยากร 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 ที่ลงทะเบียนโดยโมดูลที่ไม่ใช่รูท (เช่น การขึ้นต่อกันที่ระบุโดย โมดูลรูท และการขึ้นต่อกันของโมดูลรูท และอื่นๆ)
- Toolchain ที่ลงทะเบียนใน "คำต่อท้ายของ WORKSPACE" ซึ่งใช้โดย กฎดั้งเดิมบางอย่างที่มาพร้อมกับการติดตั้ง Bazel เท่านั้น
- Toolchain ที่ลงทะเบียนโดยรูทโมดูล (เช่น
หมายเหตุ: เป้าหมายเสมือน เช่น :all, :* และ
/... จะเรียงตามกลไกการโหลดแพ็กเกจของ Bazel
ซึ่งใช้การเรียงตามพจนานุกรม
ขั้นตอนการแก้ปัญหามีดังนี้
ข้อ
target_compatible_withหรือexec_compatible_withจะตรงกันกับแพลตฟอร์มหากสำหรับแต่ละconstraint_valueในรายการ แพลตฟอร์มมีconstraint_valueนั้นด้วย (ไม่ว่าจะระบุอย่างชัดเจนหรือเป็นค่าเริ่มต้น)หากแพลตฟอร์มมี
constraint_valueจากconstraint_settings ที่ไม่ได้ อ้างอิงในข้อกำหนด ข้อกำหนดดังกล่าวจะไม่มีผลต่อการจับคู่หากเป้าหมายที่กำลังสร้างระบุแอตทริบิวต์
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