มาโคร

หน้านี้ครอบคลุมข้อมูลพื้นฐานเกี่ยวกับการใช้มาโคร รวมถึงกรณีการใช้งานทั่วไป การแก้ไขข้อบกพร่อง และรูปแบบการตั้งชื่อ

มาโครคือฟังก์ชันที่เรียกจากไฟล์ BUILD ซึ่งสามารถสร้างอินสแตนซ์ของกฎได้ โดยหลักๆ แล้วจะใช้มาโครเพื่อการห่อหุ้มและการนำโค้ดของกฎที่มีอยู่และมาโครอื่นๆ กลับมาใช้ซ้ำ

มาโครมี 2 รูปแบบ ได้แก่ มาโครเชิงสัญลักษณ์ ซึ่งอธิบายไว้ในหน้านี้ และ มาโครเดิม เราขอแนะนำให้ใช้มาโครเชิงสัญลักษณ์เพื่อความชัดเจนของโค้ดหากเป็นไปได้

มาโครเชิงสัญลักษณ์มีอาร์กิวเมนต์ที่พิมพ์ (การแปลงสตริงเป็นป้ายกำกับ ซึ่งสัมพันธ์กับตำแหน่งที่เรียกมาโคร) และความสามารถในการจำกัดและระบุระดับการเข้าถึงของเป้าหมายที่สร้างขึ้น โดยได้รับการออกแบบมาให้รองรับการประเมินแบบเลื่อนออก (ซึ่งจะเพิ่มใน Bazel เวอร์ชันที่จะเปิดตัวในอนาคต) มาโครเชิงสัญลักษณ์พร้อมใช้งานโดยค่าเริ่มต้นใน Bazel 8 เมื่อเอกสารนี้กล่าวถึง macros จะหมายถึงมาโครเชิงสัญลักษณ์

ดูตัวอย่างที่ใช้งานได้ของมาโครเชิงสัญลักษณ์ได้ใน ที่เก็บตัวอย่าง

การใช้งาน

มาโครจะกำหนดไว้ใน .bzl ไฟล์โดยการเรียก macro() ฟังก์ชันด้วย พารามิเตอร์ที่ต้องระบุ 2 รายการ ได้แก่ attrs และ implementation

แอตทริบิวต์

attrs ยอมรับพจนานุกรมของชื่อแอตทริบิวต์กับ ประเภท แอตทริบิวต์ ซึ่งแสดงถึง อาร์กิวเมนต์ของมาโคร ระบบจะเพิ่มแอตทริบิวต์ทั่วไป 2 รายการ ได้แก่ name และ visibility ลงในมาโครทั้งหมดโดยนัย และจะไม่รวมอยู่ในพจนานุกรมที่ส่งไปยัง attrs

# macro/macro.bzl
my_macro = macro(
    attrs = {
        "deps": attr.label_list(mandatory = True, doc = "The dependencies passed to the inner cc_binary and cc_test targets"),
        "create_test": attr.bool(default = False, configurable = False, doc = "If true, creates a test target"),
    },
    implementation = _my_macro_impl,
)

การประกาศประเภทแอตทริบิวต์ยอมรับ พารามิเตอร์, mandatory, default, และ doc นอกจากนี้ ประเภทแอตทริบิวต์ส่วนใหญ่ยังยอมรับพารามิเตอร์ configurable ซึ่งกำหนดว่าแอตทริบิวต์ยอมรับ select หรือไม่ หากแอตทริบิวต์เป็น configurable ระบบจะแยกวิเคราะห์ค่าที่ไม่ใช่ select เป็น select ที่กำหนดค่าไม่ได้ – "foo" จะกลายเป็น select({"//conditions:default": "foo"}) ดูข้อมูลเพิ่มเติมได้ใน Selects

การรับค่าแอตทริบิวต์

มาโครมักมีไว้เพื่อห่อหุ้มกฎ (หรือมาโครอื่น) และผู้เขียนมาโครมักต้องการส่งต่อแอตทริบิวต์ส่วนใหญ่ของสัญลักษณ์ที่ห่อหุ้มไว้โดยไม่เปลี่ยนแปลง โดยใช้ **kwargs ไปยังเป้าหมายหลักของมาโคร (หรือมาโครภายในหลัก)

มาโครสามารถ รับค่าแอตทริบิวต์ จากกฎหรือ มาโครอื่นได้โดยการส่งสัญลักษณ์กฎ หรือ มาโครไปยังอาร์กิวเมนต์ macro()'s inherit_attrs (นอกจากนี้ คุณยังใช้สตริงพิเศษ "common" แทนสัญลักษณ์กฎหรือมาโครเพื่อรับค่า แอตทริบิวต์ทั่วไปที่กำหนดไว้สำหรับ กฎการบิลด์ Starlark ทั้งหมดได้ด้วย) ระบบจะรับค่าแอตทริบิวต์สาธารณะเท่านั้น และแอตทริบิวต์ในพจนานุกรม attrs ของมาโครเองจะลบล้างแอตทริบิวต์ที่รับค่ามาซึ่งมีชื่อเดียวกัน นอกจากนี้ คุณยัง นำ แอตทริบิวต์ที่รับค่ามาออกได้โดยใช้ None เป็นค่าในพจนานุกรม attrs ดังนี้

# macro/macro.bzl
my_macro = macro(
    inherit_attrs = native.cc_library,
    attrs = {
        # override native.cc_library's `local_defines` attribute
        "local_defines": attr.string_list(default = ["FOO"]),
        # do not inherit native.cc_library's `defines` attribute
        "defines": None,
    },
    ...
)

ระบบจะลบล้างค่าเริ่มต้นของแอตทริบิวต์ที่รับค่ามาซึ่งไม่บังคับให้เป็น None เสมอ ไม่ว่าค่าเริ่มต้นของคำจำกัดความแอตทริบิวต์เดิมจะเป็นค่าใดก็ตาม หากต้องการตรวจสอบหรือแก้ไขแอตทริบิวต์ที่รับค่ามาซึ่งไม่บังคับ เช่น หากต้องการเพิ่มแท็กลงในแอตทริบิวต์ tags ที่รับค่ามา คุณต้องตรวจสอบว่าได้จัดการกรณี None ในฟังก์ชันการใช้งานของมาโครแล้ว ดังนี้

# macro/macro.bzl
_my_macro_implementation(name, visibility, tags, **kwargs):
    # Append a tag; tags attr is an inherited non-mandatory attribute, and
    # therefore is None unless explicitly set by the caller of our macro.
    my_tags = (tags or []) + ["another_tag"]
    native.cc_library(
        ...
        tags = my_tags,
        **kwargs,
    )
    ...

การใช้งาน

implementation ยอมรับฟังก์ชันที่มีตรรกะของมาโคร ฟังก์ชันการใช้งานมักจะสร้างเป้าหมายโดยการเรียกกฎอย่างน้อย 1 ข้อ และมักจะเป็นฟังก์ชันส่วนตัว (ตั้งชื่อด้วยขีดล่างนำหน้า) โดยทั่วไปแล้ว จะตั้งชื่อเหมือนกับมาโคร แต่มีคำนำหน้าเป็น _ และคำต่อท้ายเป็น _impl

ฟังก์ชันการใช้งานกฎจะใช้พารามิเตอร์เดียว (ctx) ที่มีการอ้างอิงถึงแอตทริบิวต์ แต่ฟังก์ชันการใช้งานมาโครจะยอมรับพารามิเตอร์สำหรับอาร์กิวเมนต์แต่ละรายการ

# macro/macro.bzl
def _my_macro_impl(name, visibility, deps, create_test):
    cc_library(
        name = name + "_cc_lib",
        deps = deps,
    )

    if create_test:
        cc_test(
            name = name + "_test",
            srcs = ["my_test.cc"],
            deps = deps,
        )

หากมาโครรับค่าแอตทริบิวต์ ฟังก์ชันการใช้งาน ต้อง มีพารามิเตอร์คีย์เวิร์ดที่เหลือ **kwargs ซึ่งส่งต่อไปยังการเรียกที่เรียกใช้กฎหรือมาโครย่อยที่รับค่ามาได้ (วิธีนี้จะช่วยให้มาโครไม่เสียหายหากกฎหรือมาโครที่คุณรับค่ามาเพิ่มแอตทริบิวต์ใหม่)

คำประกาศ

มาโครจะประกาศโดยการโหลดและเรียกคำจำกัดความในไฟล์ BUILD ```starlark

pkg/BUILD

my_macro( name = "macro_instance", deps = ["src.cc"] + select( { "//config_setting:special": ["special_source.cc"], "//conditions:default": [], }, ), create_tests = True, ) ```

ซึ่งจะสร้างเป้าหมาย //pkg:macro_instance_cc_lib และ//pkg:macro_instance_test

เช่นเดียวกับการเรียกกฎ หากตั้งค่าแอตทริบิวต์ในมาโครให้เป็น None ระบบจะถือว่าแอตทริบิวต์นั้นถูกละเว้นโดยผู้เรียกมาโคร ตัวอย่างเช่น การเรียกมาโคร 2 รายการต่อไปนี้มีความหมายเหมือนกัน

# pkg/BUILD
my_macro(name = "abc", srcs = ["src.cc"], deps = None)
my_macro(name = "abc", srcs = ["src.cc"])

โดยทั่วไปแล้ววิธีนี้ไม่มีประโยชน์ในไฟล์ BUILD แต่จะมีประโยชน์เมื่อห่อหุ้มมาโครภายในมาโครอื่นแบบเป็นโปรแกรม

รายละเอียด

รูปแบบการตั้งชื่อสำหรับเป้าหมายที่สร้างขึ้น

ชื่อของเป้าหมายหรือมาโครย่อยใดก็ตามที่สร้างโดยมาโครเชิงสัญลักษณ์ต้องตรงกับพารามิเตอร์ name ของมาโคร หรือต้องมีคำนำหน้าเป็น name ตามด้วย _ (แนะนำ) . หรือ - ตัวอย่างเช่น my_macro(name = "foo") จะสร้างได้เฉพาะ ไฟล์หรือเป้าหมายที่ชื่อ foo หรือมีคำนำหน้าเป็น foo_, foo- หรือ foo., เช่น foo_bar

คุณประกาศเป้าหมายหรือไฟล์ที่ละเมิดรูปแบบการตั้งชื่อมาโครได้ แต่จะสร้างไม่ได้และใช้เป็นทรัพยากร Dependency ไม่ได้

ไฟล์และเป้าหมายที่ไม่ใช่มาโครภายในแพ็กเกจเดียวกันกับอินสแตนซ์ของมาโคร ไม่ควร มีชื่อที่ขัดแย้งกับชื่อเป้าหมายของมาโครที่อาจเกิดขึ้น แม้ว่าจะไม่มีการบังคับใช้การยกเว้นนี้ก็ตาม เรากำลังดำเนินการเพื่อใช้ การประเมินแบบเลื่อนออกเพื่อปรับปรุงประสิทธิภาพของมาโครเชิงสัญลักษณ์ ซึ่งจะได้รับผลกระทบในแพ็กเกจที่ละเมิดรูปแบบการตั้งชื่อ

ข้อจำกัด

มาโครเชิงสัญลักษณ์มีข้อจำกัดเพิ่มเติมบางอย่างเมื่อเทียบกับมาโครเดิม

มาโครเชิงสัญลักษณ์

  • ต้องใช้อาร์กิวเมนต์ name และอาร์กิวเมนต์ visibility
  • ต้องมีฟังก์ชัน implementation
  • ห้ามแสดงผลค่า
  • ห้ามเปลี่ยนแปลงอาร์กิวเมนต์
  • ห้ามเรียก native.existing_rules() เว้นแต่จะเป็นมาโคร finalizer พิเศษ
  • ห้ามเรียก native.package()
  • ห้ามเรียก glob()
  • ห้ามเรียก native.environment_group()
  • ต้องสร้างเป้าหมายที่มีชื่อเป็นไปตามรูปแบบการตั้งชื่อ
  • อ้างอิงไฟล์อินพุตที่ไม่ได้ประกาศหรือส่งเป็นอาร์กิวเมนต์ไม่ได้
  • อ้างอิงเป้าหมายส่วนตัวของผู้เรียกไม่ได้ (ดู รายละเอียดเพิ่มเติมได้ที่ระดับการเข้าถึงและมาโคร)

ระดับการเข้าถึงและมาโคร

ระบบระดับการเข้าถึงช่วยปกป้องรายละเอียดการใช้งาน ของทั้งมาโคร (เชิงสัญลักษณ์) และผู้เรียก

โดยค่าเริ่มต้น เป้าหมายที่สร้างในมาโครเชิงสัญลักษณ์จะมองเห็นได้ภายในมาโครเอง แต่ไม่จำเป็นต้องมองเห็นได้สำหรับผู้เรียกมาโคร มาโครสามารถ "ส่งออก" เป้าหมายเป็น API สาธารณะได้โดยการส่งต่อค่าของแอตทริบิวต์ของตัวเอง เช่น some_rule(..., visibility = visibility)visibility

แนวคิดหลักของระดับการเข้าถึงมาโครมีดังนี้

  1. ระบบจะตรวจสอบระดับการเข้าถึงโดยอิงตามมาโครที่ประกาศเป้าหมาย ไม่ใช่แพ็กเกจที่เรียกมาโคร

    • กล่าวอีกนัยหนึ่ง การอยู่ในแพ็กเกจเดียวกันไม่ได้ทำให้เป้าหมายหนึ่งมองเห็นเป้าหมายอื่นได้โดยอัตโนมัติ ซึ่งจะช่วยป้องกันไม่ให้เป้าหมายภายในของมาโครกลายเป็นทรัพยากร Dependency ของมาโครอื่นหรือเป้าหมายระดับบนสุดในแพ็กเกจ
  2. แอตทริบิวต์ visibility ทั้งในกฎและมาโครจะรวมตำแหน่งที่เรียกกฎหรือมาโครโดยอัตโนมัติ

    • ดังนั้น เป้าหมายจะมองเห็นเป้าหมายอื่นๆ ที่ประกาศในมาโครเดียวกัน (หรือไฟล์ BUILD หากไม่ได้อยู่ในมาโคร) ได้โดยไม่มีเงื่อนไข

ในทางปฏิบัติ หมายความว่าเมื่อมาโครประกาศเป้าหมายโดยไม่ได้ตั้งค่า visibility เป้าหมายจะตั้งค่าเริ่มต้นเป็นภายในมาโคร (ระดับการเข้าถึงเริ่มต้นของแพ็กเกจ จะไม่มีผลภายในมาโคร ) การส่งออกเป้าหมายหมายความว่าเป้าหมายจะมองเห็นได้สำหรับสิ่งที่ผู้เรียกมาโครระบุไว้ในแอตทริบิวต์ visibility ของมาโคร รวมถึงแพ็กเกจของผู้เรียกมาโครเองและโค้ดของมาโครเอง อีกวิธีหนึ่งในการพิจารณาคือ ระดับการเข้าถึงของมาโครจะกำหนดว่าใคร (นอกเหนือจากมาโครเอง) ที่จะมองเห็นเป้าหมายที่ส่งออกของมาโครได้

# tool/BUILD
...
some_rule(
    name = "some_tool",
    visibility = ["//macro:__pkg__"],
)
# macro/macro.bzl

def _impl(name, visibility):
    cc_library(
        name = name + "_helper",
        ...
        # No visibility passed in. Same as passing `visibility = None` or
        # `visibility = ["//visibility:private"]`. Visible to the //macro
        # package only.
    )
    cc_binary(
        name = name + "_exported",
        deps = [
            # Allowed because we're also in //macro. (Targets in any other
            # instance of this macro, or any other macro in //macro, can see it
            # too.)
            name + "_helper",
            # Allowed by some_tool's visibility, regardless of what BUILD file
            # we're called from.
            "//tool:some_tool",
        ],
        ...
        visibility = visibility,
    )

my_macro = macro(implementation = _impl, ...)
# pkg/BUILD
load("//macro:macro.bzl", "my_macro")
...

my_macro(
    name = "foo",
    ...
)

some_rule(
    ...
    deps = [
        # Allowed, its visibility is ["//pkg:__pkg__", "//macro:__pkg__"].
        ":foo_exported",
        # Disallowed, its visibility is ["//macro:__pkg__"] and
        # we are not in //macro.
        ":foo_helper",
    ]
)

หากเรียกใช้ my_macro ด้วย visibility = ["//other_pkg:__pkg__"] หรือหากแพ็กเกจ //pkg ตั้งค่า default_visibility เป็นค่านั้น ก็จะใช้ //pkg:foo_exported ภายใน //other_pkg/BUILD หรือภายในมาโครที่กำหนดไว้ใน //other_pkg:defs.bzl ได้ด้วย แต่ //pkg:foo_helper จะยังคงได้รับการปกป้อง

มาโครสามารถประกาศว่าเป้าหมายมองเห็นได้สำหรับแพ็กเกจเพื่อนโดยส่ง visibility = ["//some_friend:__pkg__"] (สำหรับเป้าหมายภายใน) หรือ visibility = visibility + ["//some_friend:__pkg__"] (สำหรับเป้าหมายที่ส่งออก) โปรดทราบว่าการประกาศเป้าหมายที่มีระดับการเข้าถึงสาธารณะ (visibility = ["//visibility:public"]) ในมาโครเป็นรูปแบบที่ไม่แนะนำ เนื่องจากจะทำให้ เป้าหมายมองเห็นได้สำหรับทุกแพ็กเกจโดยไม่มีเงื่อนไข แม้ว่าผู้เรียก จะระบุระดับการเข้าถึงที่จำกัดมากกว่าก็ตาม

การตรวจสอบระดับการเข้าถึงทั้งหมดจะทำโดยอิงตามมาโครเชิงสัญลักษณ์ที่ทำงานอยู่ภายในสุดในปัจจุบัน อย่างไรก็ตาม มีกลไกการมอบสิทธิ์ระดับการมองเห็น กล่าวคือ หากมาโครส่งป้ายกำกับเป็นค่าแอตทริบิวต์ไปยังมาโครภายใน ระบบจะตรวจสอบการใช้งานป้ายกำกับในมาโครภายในโดยอิงตามมาโครภายนอก ดูรายละเอียดเพิ่มเติมได้ที่ หน้าเกี่ยวกับการมองเห็น

โปรดทราบว่ามาโครเดิมจะโปร่งใสต่อระบบระดับการเข้าถึงโดยสมบูรณ์ และทำงานราวกับว่าตำแหน่งของมาโครคือไฟล์ BUILD หรือมาโครเชิงสัญลักษณ์ที่เรียกมาโครเดิม

Finalizer และระดับการเข้าถึง

เป้าหมายที่ประกาศใน Finalizer ของกฎจะมองเห็นเป้าหมายตามกฎระดับการเข้าถึงมาโครเชิงสัญลักษณ์ปกติ และ มองเห็นเป้าหมายทั้งหมดที่แพ็กเกจของเป้าหมาย Finalizer มองเห็นได้

ซึ่งหมายความว่าหากคุณย้ายมาโครเดิมที่อิงตาม native.existing_rules() ไปยัง Finalizer เป้าหมายที่ประกาศโดย Finalizer จะยังคงมองเห็นทรัพยากร Dependency เดิมได้

อย่างไรก็ตาม โปรดทราบว่าคุณสามารถประกาศเป้าหมายในมาโครเชิงสัญลักษณ์เพื่อให้เป้าหมายของ Finalizer มองไม่เห็นเป้าหมายนั้นภายใต้ระบบระดับการเข้าถึงได้ แม้ว่า Finalizer จะ ตรวจสอบ แอตทริบิวต์โดยใช้ native.existing_rules() ได้ก็ตาม

Selects

หากแอตทริบิวต์เป็น configurable (ค่าเริ่มต้น) และค่าไม่ใช่ None ฟังก์ชันการใช้งานมาโครจะเห็นค่าแอตทริบิวต์ที่ห่อหุ้มไว้ใน select ที่ไม่สำคัญ ซึ่งจะช่วยให้ผู้เขียนมาโครตรวจพบข้อบกพร่องได้ง่ายขึ้นในกรณีที่ไม่ได้คาดการณ์ว่าค่าแอตทริบิวต์อาจเป็น select

ตัวอย่างเช่น ลองดูมาโครต่อไปนี้

my_macro = macro(
    attrs = {"deps": attr.label_list()},  # configurable unless specified otherwise
    implementation = _my_macro_impl,
)

หากเรียกใช้ my_macro ด้วย deps = ["//a"] ระบบจะเรียกใช้ _my_macro_impl โดยตั้งค่าพารามิเตอร์ deps เป็น select({"//conditions:default": ["//a"]}) หากการดำเนินการนี้ทำให้ฟังก์ชันการใช้งานล้มเหลว (เช่น เนื่องจากโค้ดพยายามจัดทำดัชนีค่า เช่น deps[0] ซึ่งไม่ได้รับอนุญาตสำหรับ select ผู้เขียนมาโครจะเลือกได้ว่าจะเขียนมาโครใหม่ให้ใช้เฉพาะการดำเนินการที่เข้ากันได้กับ select หรือจะทำเครื่องหมายแอตทริบิวต์เป็นกำหนดค่าไม่ได้ (attr.label_list(configurable = False)) ซึ่งวิธีหลังจะช่วยให้ผู้ใช้ไม่ได้รับอนุญาตให้ส่งค่า select เข้ามา

เป้าหมายกฎจะย้อนกลับการแปลงนี้และจัดเก็บ select ที่ไม่สำคัญเป็นค่าที่ไม่มีเงื่อนไข ในตัวอย่างข้างต้น หาก _my_macro_impl ประกาศเป้าหมายกฎ my_rule(..., deps = deps) ระบบจะจัดเก็บ deps ของเป้าหมายกฎเป็น ["//a"] ซึ่งจะช่วยให้มั่นใจได้ว่าการห่อหุ้ม select จะไม่ทำให้ระบบจัดเก็บค่า select ที่ไม่สำคัญในเป้าหมายทั้งหมดที่สร้างอินสแตนซ์โดยมาโคร

หากค่าของแอตทริบิวต์ที่กำหนดค่าได้เป็น None ระบบจะไม่ห่อหุ้มค่าดังกล่าวใน select ซึ่งจะช่วยให้การทดสอบ เช่น my_attr == None ยังคงทำงานได้ และเมื่อส่งต่อแอตทริบิวต์ไปยังกฎที่มีค่าเริ่มต้นที่คำนวณได้ กฎจะทำงานอย่างถูกต้อง (นั่นคือ ราวกับว่าไม่ได้ส่งแอตทริบิวต์เข้ามาเลย) แอตทริบิวต์อาจไม่สามารถรับค่า None ได้เสมอไป แต่จะเกิดขึ้นได้สำหรับประเภท attr.label() และสำหรับแอตทริบิวต์ที่รับค่ามาซึ่งไม่บังคับ

Finalizer

Finalizer ของกฎคือมาโครเชิงสัญลักษณ์พิเศษซึ่งจะได้รับการประเมินในขั้นตอนสุดท้ายของการโหลดแพ็กเกจหลังจากกำหนดเป้าหมายที่ไม่ใช่ Finalizer ทั้งหมดแล้ว ไม่ว่าตำแหน่งของ Finalizer จะอยู่ที่ใดในไฟล์ BUILD Finalizer สามารถเรียก native.existing_rules() ได้ ซึ่งจะทำงานแตกต่างจากในมาโครเดิมเล็กน้อย โดยจะแสดงผลเฉพาะชุดเป้าหมายกฎที่ไม่ใช่ Finalizer Finalizer อาจยืนยันสถานะของชุดเป้าหมายนั้นหรือกำหนดเป้าหมายใหม่

หากต้องการประกาศ Finalizer ให้เรียก macro() ด้วย finalizer = True ดังนี้

def _my_finalizer_impl(name, visibility, tags_filter):
    for r in native.existing_rules().values():
        for tag in r.get("tags", []):
            if tag in tags_filter:
                my_test(
                    name = name + "_" + r["name"] + "_finalizer_test",
                    deps = [r["name"]],
                    data = r["srcs"],
                    ...
                )
                continue

my_finalizer = macro(
    attrs = {"tags_filter": attr.string_list(configurable = False)},
    implementation = _impl,
    finalizer = True,
)

การประเมินแบบเลื่อนออก

สำคัญ: เรากำลังดำเนินการเพื่อใช้การขยายและการประเมินมาโครแบบเลื่อนออก ฟีเจอร์นี้ยังไม่พร้อมใช้งาน

ปัจจุบัน ระบบจะประเมินมาโครทั้งหมดทันทีที่โหลดไฟล์ BUILD ซึ่งอาจส่งผลเสียต่อประสิทธิภาพของเป้าหมายในแพ็กเกจที่มีมาโครที่ไม่เกี่ยวข้องซึ่งใช้ทรัพยากรมากด้วย ในอนาคต ระบบจะประเมินมาโครเชิงสัญลักษณ์ที่ไม่ใช่ Finalizer ก็ต่อเมื่อจำเป็นสำหรับการสร้างเท่านั้น รูปแบบการตั้งชื่อคำนำหน้าจะช่วยให้ Bazel กำหนดได้ว่าจะขยายมาโครใดเมื่อได้รับเป้าหมายที่ขอ

การแก้ปัญหาการย้ายข้อมูล

ปัญหาที่พบบ่อยในการย้ายข้อมูลและวิธีแก้ไขมีดังนี้

  • มาโครเดิมเรียก glob()

ย้ายการเรียก glob() ไปยังไฟล์ BUILD (หรือไปยังมาโครเดิมที่เรียกจากไฟล์ BUILD) และส่งค่า glob() ไปยังมาโครเชิงสัญลักษณ์โดยใช้แอตทริบิวต์รายการป้ายกำกับ ดังนี้

# BUILD file
my_macro(
    ...,
    deps = glob(...),
)
  • มาโครเดิมมีพารามิเตอร์ที่ไม่ใช่ประเภท attr ของ Starlark ที่ถูกต้อง

ดึงตรรกะให้ได้มากที่สุดเท่าที่จะทำได้ไปยังมาโครเชิงสัญลักษณ์ที่ซ้อนกัน แต่ให้มาโครระดับบนสุดเป็นมาโครเดิม

  • มาโครเดิมเรียกกฎที่สร้างเป้าหมายซึ่งละเมิดรูปแบบการตั้งชื่อ

ไม่เป็นไร เพียงแค่อย่าใช้เป้าหมายที่ "ละเมิด" ระบบจะละเว้นการตรวจสอบการตั้งชื่อโดยไม่แจ้งให้ทราบ