หน้านี้อธิบายเฟรมเวิร์ก Toolchain ซึ่งเป็นวิธีที่ผู้เขียนกฎแยกตรรกะกฎออกจากการเลือกเครื่องมือตามแพลตฟอร์ม เราขอแนะนำให้อ่านหน้ากฎและแพลตฟอร์มก่อนดำเนินการต่อ หน้านี้จะอธิบายถึงเหตุผลที่ต้องใช้ชุดเครื่องมือ วิธีกำหนดและใช้ชุดเครื่องมือ และวิธีที่ Bazel เลือกชุดเครื่องมือที่เหมาะสมตามข้อจำกัดของแพลตฟอร์ม
แรงจูงใจ
ก่อนอื่นมาพิจารณาปัญหาที่เครื่องมือทางเทคนิคออกแบบมาเพื่อแก้ปัญหา สมมติว่าคุณเขียนกฎเพื่อรองรับภาษาโปรแกรม "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
ทุกคน
หากไม่ได้ใช้รูปแบบนี้อย่างสอดคล้องกันทั่วทั้งพื้นที่ทำงาน จะนำไปสู่การสร้างที่ทำงานได้ดีในแพลตฟอร์มเดียวแต่ล้มเหลวเมื่อขยายไปใช้กับสถานการณ์หลายแพลตฟอร์ม และไม่จัดการปัญหาในการเพิ่มการรองรับแพลตฟอร์มและคอมไพเลอร์ใหม่ๆ โดยไม่แก้ไขกฎหรือเป้าหมายที่มีอยู่
เฟรมเวิร์กเครื่องมือช่วยแก้ปัญหานี้ด้วยการเพิ่มการสื่อกลางอีกระดับ สรุปคือ คุณประกาศว่ากฎของคุณมีความสัมพันธ์แบบนามธรรมกับสมาชิกบางคนของกลุ่มเป้าหมาย (ประเภทเครื่องมือทางเทคนิค) และ Bazel จะแก้ไขเป้าหมายนี้โดยอัตโนมัติเป็นเป้าหมายหนึ่งๆ (เครื่องมือทางเทคนิค) ตามข้อจำกัดของแพลตฟอร์มที่เกี่ยวข้อง ผู้เขียนกฎและผู้เขียนเป้าหมายไม่จำเป็นต้องทราบแพลตฟอร์มและชุดเครื่องมือทั้งหมดที่ใช้ได้
การเขียนกฎที่ใช้เครื่องมือทางเทคนิค
ในเฟรมเวิร์กเครื่องมือทํางาน กฎจะขึ้นอยู่กับประเภทเครื่องมือทํางานแทนที่จะขึ้นอยู่กับเครื่องมือโดยตรง ประเภทเครื่องมือทางเทคนิคคือเป้าหมายง่ายๆ ที่แสดงถึงคลาสของเครื่องมือที่มีบทบาทเหมือนกันสำหรับแพลตฟอร์มต่างๆ เช่น คุณสามารถประกาศประเภทที่แสดงถึงคอมไพเลอร์บาร์ ดังนี้
# 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
โดยใช้ประเภทเครื่องมือเป็นคีย์
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
providerของเป้าหมายใดก็ตามที่ Bazel แก้ปัญหาการพึ่งพาใน Toolchain ช่องของออบเจ็กต์ ToolchainInfo
กำหนดโดยกฎของเครื่องมือพื้นฐาน ส่วนในหัวข้อถัดไป กฎนี้จะกำหนดให้มีช่อง barcinfo
ที่รวมออบเจ็กต์ BarcInfo
ขั้นตอนของ Bazel สำหรับการแปลงเครื่องมือเชนกับเป้าหมายอธิบายได้ด้านล่าง มีเพียงเป้าหมายเครื่องมือทางเทคนิคที่แก้ไขแล้วเท่านั้นที่จะเป็นทรัพยากรของเป้าหมาย bar_binary
ไม่ใช่พื้นที่ทั้งหมดของเครื่องมือทางเทคนิคที่เป็นไปได้
เครื่องมือที่จำเป็นและไม่จำเป็น
โดยค่าเริ่มต้น เมื่อกฎแสดงถึงความสัมพันธ์แบบประเภทเครื่องมือที่ใช้สร้างซอฟต์แวร์โดยใช้ป้ายกำกับแบบเดี่ยว (ดังที่แสดงด้านบน) ระบบจะถือว่าประเภทเครื่องมือที่ใช้สร้างซอฟต์แวร์นั้นต้องระบุ หาก Bazel ไม่พบ Toolchain ที่ตรงกัน (ดูการแก้ไข Toolchain ด้านล่าง) สำหรับประเภท Toolchain ที่ต้องระบุ การวิเคราะห์จะหยุดลงและแสดงข้อผิดพลาด
คุณประกาศการพึ่งพาประเภทเครื่องมือทางเทคนิคที่ไม่บังคับแทนได้ ดังนี้
bar_binary = rule(
...
toolchains = [
config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = False),
],
)
เมื่อไม่สามารถแก้ไขประเภทเครื่องมือทางเทคนิคที่ไม่บังคับได้ การวิเคราะห์จะยังคงดำเนินต่อไป และผลลัพธ์ของ 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)]
- ประเภทเครื่องมือทางเทคนิคที่ไม่บังคับ
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
แง่มุมมีสิทธิ์เข้าถึง API ของเครื่องมือชุดเดียวกันกับกฎ คุณจึงกำหนดประเภทเครื่องมือชุดที่จำเป็น เข้าถึงเครื่องมือชุดผ่านบริบท และใช้เพื่อสร้างการดำเนินการใหม่โดยใช้เครื่องมือชุดนั้นได้
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
เพื่อระบุข้อมูลเมตาที่เฟรมเวิร์กเครื่องมือทางเทคนิคใช้ เป้าหมายtoolchain
นี้ยังหมายถึง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
ซึ่งจะกลายเป็นออบเจ็กต์ที่กฎที่ใช้จะดึงข้อมูลโดยใช้ 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 รายการ
คําจํากัดความเหล่านี้จะลิงก์เป้าหมายเฉพาะภาษากับประเภทเครื่องมือและระบุข้อมูลข้อจํากัดที่จะบอก Bazel ว่าเครื่องมือควรใช้กับแพลตฟอร์มใด
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
จะแตกต่างออกไปเล็กน้อย
Dependency จากเป้าหมาย (เรียกว่า "รายการหลัก") ไปยัง Toolchain ผ่าน Toolchain Resolution ใช้การเปลี่ยนการกำหนดค่าพิเศษที่เรียกว่า "Toolchain Revolution" การเปลี่ยนเครื่องมือทางเทคนิคจะเก็บการกำหนดค่าไว้เหมือนเดิม ยกเว้นว่าจะบังคับให้แพลตฟอร์มการดําเนินการของเครื่องมือทางเทคนิคเหมือนกับของเครื่องมือหลัก (ไม่เช่นนั้น การแก้ไขเครื่องมือทางเทคนิคสําหรับเครื่องมือทางเทคนิคอาจเลือกแพลตฟอร์มการดําเนินการใดก็ได้ และไม่จำเป็นต้องเหมือนกับของเครื่องมือหลัก) ซึ่งจะช่วยให้สามารถเรียกใช้exec
Dependency ของ Toolchain สำหรับการดำเนินการสร้างของส่วนกลางได้ ไลบรารีของเครื่องมือทางเทคนิคที่ใช้ cfg =
"target"
(หรือไม่ได้ระบุ cfg
เนื่องจาก "target" เป็นค่าเริ่มต้น) จะสร้างขึ้นสำหรับแพลตฟอร์มเป้าหมายเดียวกันกับแพลตฟอร์มหลัก ซึ่งช่วยให้กฎชุดเครื่องมือสามารถนําทั้งไลบรารี (แอตทริบิวต์ system_lib
ด้านบน) และเครื่องมือ (แอตทริบิวต์ compiler
) ไปใช้กับกฎการสร้างที่ต้องใช้ ไลบรารีของระบบจะลิงก์กับอาร์ติแฟกต์สุดท้าย จึงต้องสร้างสำหรับแพลตฟอร์มเดียวกัน ส่วนคอมไพเลอร์เป็นเครื่องมือที่เรียกใช้ระหว่างการสร้าง และจำเป็นต้องทำงานได้บนแพลตฟอร์มการดำเนินการ
การลงทะเบียนและการสร้างด้วยชุดเครื่องมือ
ตอนนี้บล็อกการสร้างทั้งหมดจะประกอบเข้าด้วยกันแล้ว และคุณเพียงแค่ต้องทำให้ชุดเครื่องมือพร้อมใช้งานสำหรับกระบวนการแก้ไขของ Bazel ซึ่งทำได้โดยการลงทะเบียนเครื่องมือทางเทคนิคในไฟล์ MODULE.bazel
โดยใช้ register_toolchains()
หรือโดยการส่งป้ายกำกับของเครื่องมือทางเทคนิคในบรรทัดคำสั่งโดยใช้ Flag --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/...",
)
เมื่อใช้รูปแบบเป้าหมายเพื่อลงทะเบียนเครื่องมือทางเทคนิค ลำดับการลงทะเบียนเครื่องมือทางเทคนิคแต่ละรายการจะกำหนดโดยกฎต่อไปนี้
- เครื่องมือที่กําหนดไว้ในแพ็กเกจย่อยของแพ็กเกจจะได้รับการลงทะเบียนก่อนเครื่องมือที่กําหนดไว้ในแพ็กเกจนั้นๆ
- ภายในแพ็กเกจ ระบบจะลงทะเบียนเครื่องมือทางเทคนิคตามลําดับตัวอักษรของชื่อ
ตอนนี้เมื่อคุณสร้างเป้าหมายที่ขึ้นอยู่กับประเภทเครื่องมือทางเทคนิค ระบบจะเลือกเครื่องมือทางเทคนิคที่เหมาะสมตามแพลตฟอร์มเป้าหมายและแพลตฟอร์มการดำเนินการ
# 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
สําหรับแต่ละเป้าหมายที่ใช้ชุดเครื่องมือ ขั้นตอนการแก้ไขชุดเครื่องมือของ Bazel จะกําหนดข้อกําหนดเฉพาะของชุดเครื่องมือของเป้าหมาย ขั้นตอนนี้ใช้ชุดประเภทเครื่องมือทางเทคนิคที่จำเป็น แพลตฟอร์มเป้าหมาย รายการแพลตฟอร์มการเรียกใช้ที่ใช้ได้ และรายการเครื่องมือทางเทคนิคที่ใช้ได้ เอาต์พุตคือเครื่องมือทางเทคนิคที่เลือกสำหรับเครื่องมือทางเทคนิคแต่ละประเภท รวมถึงแพลตฟอร์มการเรียกใช้ที่เลือกสำหรับเป้าหมายปัจจุบัน
ระบบจะรวบรวมแพลตฟอร์มการดําเนินการและชุดเครื่องมือที่ใช้ได้จากกราฟทรัพยากร Dependency ภายนอกผ่านregister_execution_platforms
และregister_toolchains
ที่เรียกใช้ในส่วน MODULE.bazel
files.
Additional execution platforms and toolchains may also be specified on the
command line via
[
--extra_execution_platforms](/versions/7.4.0/reference/command-line-reference#flag--extra_execution_platforms)
and
[
--extra_toolchains`](/versions/7.4.0/reference/command-line-reference#flag--extra_toolchains)
ระบบจะรวมแพลตฟอร์มโฮสต์เป็นแพลตฟอร์มการดำเนินการที่ใช้ได้โดยอัตโนมัติ
แพลตฟอร์มและ Toolchain ที่ใช้ได้จะได้รับการติดตามเป็นรายการตามลำดับสำหรับการกำหนดที่กำหนดโดยความต้องการ ซึ่งได้กำหนดให้กับรายการก่อนหน้าในลิสต์แล้ว
ชุดเครื่องมือทางเทคนิคที่ใช้ได้ (ตามลําดับความสําคัญ) จะสร้างขึ้นจาก --extra_toolchains
และ register_toolchains
ดังนี้
- ระบบจะเพิ่มเครื่องมือที่ลงทะเบียนโดยใช้
--extra_toolchains
ก่อน (เครื่องมือทางเทคนิคล่าสุดจะมีลำดับความสำคัญสูงสุด) - toolchain ที่ลงทะเบียนโดยใช้
register_toolchains
ในกราฟความเกี่ยวข้องภายนอกแบบทรานซิทีฟ ตามลำดับต่อไปนี้ (ในบรรดาเหล่านี้ toolchain ที่กล่าวถึงครั้งแรกจะมีลำดับความสำคัญสูงสุด)- เชนเครื่องมือที่ลงทะเบียนโดยโมดูลรูท (เช่น
MODULE.bazel
ที่รูทของพื้นที่ทำงาน) - เชนเครื่องมือที่ลงทะเบียนในไฟล์
WORKSPACE
ของผู้ใช้ รวมถึงในมาโครที่เรียกใช้จากที่นั่น - เครื่องมือที่ลงทะเบียนโดยโมดูลที่ไม่ใช่รูท (เช่น การอ้างอิงที่ระบุโดยโมดูลรูทและการอ้างอิงของโมดูลนั้น และอื่นๆ)
- เครื่องมือที่ลงทะเบียนใน "WORKSPACE suffix" ซึ่งจะใช้โดยกฎเนทีฟบางรายการที่รวมอยู่กับการติดตั้ง Bazel เท่านั้น
- เชนเครื่องมือที่ลงทะเบียนโดยโมดูลรูท (เช่น
หมายเหตุ: เป้าหมายจำลอง เช่น :all
, :*
และ /...
จะจัดเรียงตามกลไกการโหลดแพ็กเกจของ Bazel ซึ่งใช้การจัดเรียงตามลําดับตัวอักษร
ขั้นตอนการแก้ปัญหามีดังนี้
ประโยค
target_compatible_with
หรือexec_compatible_with
จะตรงกับแพลตฟอร์มหากแพลตฟอร์มมีconstraint_value
นั้น (อย่างชัดแจ้งหรือเป็นค่าเริ่มต้น) สำหรับconstraint_value
แต่ละรายการในรายการหากแพลตฟอร์มมี
constraint_value
จากconstraint_setting
ที่ไม่ได้อ้างอิงโดยอนุประโยค ก็จะไม่ส่งผลต่อการจับคู่หากเป้าหมายที่สร้างระบุแอตทริบิวต์
exec_compatible_with
(หรือคําจํากัดความของกฎระบุอาร์กิวเมนต์exec_compatible_with
) ระบบจะกรองรายการแพลตฟอร์มการเรียกใช้ที่ใช้ได้เพื่อนำแพลตฟอร์มที่ไม่ตรงกับข้อจำกัดการเรียกใช้ออกสําหรับแพลตฟอร์มการเรียกใช้แต่ละแพลตฟอร์มที่พร้อมใช้งาน คุณจะเชื่อมโยงเครื่องมือทางเทคนิคแต่ละประเภทกับเครื่องมือทางเทคนิคแรกที่พร้อมใช้งาน (หากมี) ซึ่งเข้ากันได้กับแพลตฟอร์มการเรียกใช้นี้และแพลตฟอร์มเป้าหมาย
ระบบจะยกเว้นแพลตฟอร์มการดําเนินการใดๆ ที่ไม่พบเครื่องมือทางเทคนิคที่จําเป็นซึ่งเข้ากันได้สําหรับเครื่องมือทางเทคนิคประเภทใดประเภทหนึ่ง แพลตฟอร์มแรกจากแพลตฟอร์มที่เหลือจะกลายเป็นแพลตฟอร์มการเรียกใช้ของเป้าหมายปัจจุบัน และเครื่องมือทางเทคนิคที่เกี่ยวข้อง (หากมี) จะกลายเป็นทรัพยากรของเป้าหมาย
ระบบจะใช้แพลตฟอร์มการดำเนินการที่เลือกเพื่อเรียกใช้การดำเนินการทั้งหมดที่เป้าหมายสร้างขึ้น
ในกรณีที่สร้างเป้าหมายเดียวกันได้หลายการกำหนดค่า (เช่น สำหรับ CPU ที่แตกต่างกัน) ภายในบิลด์เดียวกัน ระบบจะใช้ขั้นตอนการแก้ปัญหากับเป้าหมายแต่ละเวอร์ชันแยกกัน
หากกฎใช้กลุ่มการดำเนินการ กลุ่มการดำเนินการแต่ละกลุ่มจะทำการแปลง Toolchain แยกกัน และแต่ละกลุ่มจะมีแพลตฟอร์มการดำเนินการและ Toolchain ของตนเอง
การแก้ไขข้อบกพร่องเกี่ยวกับโซ่เครื่องมือ
หากต้องการเพิ่มการรองรับเครื่องมือทางเทคนิคลงในกฎที่มีอยู่ ให้ใช้ Flag --toolchain_resolution_debug=regex
ในระหว่างการแก้ไขเครื่องมือ FLAG จะแสดงผลลัพธ์แบบละเอียดสำหรับประเภทเครื่องมือหรือชื่อเป้าหมายที่ตรงกับตัวแปรนิพจน์ทั่วไป คุณใช้ .*
เพื่อแสดงข้อมูลทั้งหมดได้ Bazel จะแสดงชื่อเครื่องมือเชนที่ตรวจสอบและข้ามระหว่างกระบวนการแก้ปัญหา
หากต้องการดูว่าทรัพยากร 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