เชนเครื่องมือ

หน้านี้อธิบายเฟรมเวิร์ก 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"],
)

ตอนนี้ฟังก์ชันการใช้งานจะเข้าถึงทรัพยากร 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 อย่าง

  1. กฎเฉพาะภาษาที่แสดงถึงเครื่องมือหรือชุดเครื่องมือ โดยธรรมเนียมแล้ว ชื่อกฎนี้จะมีคำต่อท้ายเป็น "_toolchain"

    1. หมายเหตุ: กฎ \_toolchain จะสร้างการดำเนินการสร้างไม่ได้ แต่จะรวบรวมอาร์ติแฟกต์จากกฎอื่นๆ และส่งต่ออาร์ติแฟกต์เหล่านั้นไปยังกฎที่ใช้ Toolchain กฎดังกล่าวมีหน้าที่รับผิดชอบในการสร้างการดำเนินการสร้างทั้งหมด
  2. เป้าหมายหลายรายการของกฎประเภทนี้ ซึ่งแสดงถึงเครื่องมือหรือชุดเครื่องมือเวอร์ชันต่างๆ สำหรับแพลตฟอร์มต่างๆ

  3. สำหรับเป้าหมายแต่ละรายการดังกล่าว เป้าหมายที่เชื่อมโยงของกฎทั่วไป 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 จะแตกต่างกันเล็กน้อย

การขึ้นต่อกันจากเป้าหมาย (เรียกว่า "รายการหลัก") ไปยัง 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",
    # 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 ที่พร้อมใช้งานจากไฟล์ WORKSPACEผ่าน register_execution_platforms และ register_toolchains นอกจากนี้ คุณยังระบุแพลตฟอร์มการดำเนินการและ Toolchain เพิ่มเติมใน บรรทัดคำสั่งผ่าน --extra_execution_platforms และ --extra_toolchainsได้ด้วย ระบบจะรวมแพลตฟอร์มโฮสต์เป็นแพลตฟอร์มการดำเนินการที่พร้อมใช้งานโดยอัตโนมัติ ระบบจะติดตามแพลตฟอร์มและ Toolchain ที่พร้อมใช้งานเป็นรายการที่เรียงลำดับเพื่อความแน่นอน โดยจะให้ความสำคัญกับรายการก่อนหน้าในรายการ

ระบบจะสร้างชุด Toolchain ที่พร้อมใช้งานตามลำดับความสำคัญจาก --extra_toolchains และ register_toolchains ดังนี้

  1. ระบบจะเพิ่ม Toolchain ที่ลงทะเบียนโดยใช้ --extra_toolchains ก่อน
    1. ใน Toolchain เหล่านี้ Toolchain สุดท้าย จะมีความสำคัญสูงสุด
  2. Toolchain ที่ลงทะเบียนโดยใช้ register_toolchains
    1. ใน Toolchain เหล่านี้ Toolchain ที่กล่าวถึงรายการแรก จะมีความสำคัญสูงสุด

หมายเหตุ: ระบบจะจัดเรียงเป้าหมายเทียม เช่น :all, :* และ /... ตามกลไกการโหลดแพ็กเกจ ของ Bazel ซึ่งใช้การจัดเรียงตามพจนานุกรม

ขั้นตอนการแก้ปัญหามีดังนี้

  1. ข้อความ target_compatible_with หรือ exec_compatible_with จะ ตรงกัน กับแพลตฟอร์มหากแพลตฟอร์มมี constraint_value เดียวกันกับ constraint_value แต่ละรายการในรายการ (ไม่ว่าจะระบุอย่างชัดเจนหรือเป็นค่าเริ่มต้น)

    หากแพลตฟอร์มมี constraint_value จาก constraint_setting ที่ข้อความไม่ได้อ้างอิง การดำเนินการนี้จะไม่ส่งผลต่อการจับคู่

  2. หากเป้าหมายที่กำลังสร้างระบุแ101exec_compatible_withตริบิวต์ (หรือการกำหนดกฎระบุอ101exec_compatible_withกิวเมนต์)101ระบบจะกรองรายการแพลตฟอร์มการดำเนินการที่พร้อมใช้งานเพื่อนำ101แพลตฟอร์มที่ไม่ตรงกับข้อจำกัดการดำเนินการออก

  3. สำหรับแพลตฟอร์มการดำเนินการที่พร้อมใช้งานแต่ละแพลตฟอร์ม ให้เชื่อมโยงประเภท Toolchain แต่ละประเภทกับ Toolchain แรกที่พร้อมใช้งาน (หากมี) ซึ่งเข้ากันได้กับแพลตฟอร์มการดำเนินการและแพลตฟอร์มเป้าหมายนี้

  4. ระบบจะตัดแพลตฟอร์มการดำเนินการที่ไม่พบ Toolchain ที่บังคับที่เข้ากันได้สำหรับประเภท Toolchain อย่างน้อย 1 ประเภทออก จากแพลตฟอร์มที่เหลือ แพลตฟอร์มแรกจะกลายเป็นแพลตฟอร์มการดำเนินการของเป้าหมายปัจจุบัน และ 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