มาโคร

รายงานปัญหา ดูแหล่งที่มา Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

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

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

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

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

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

การใช้งาน

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

Attributes

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"}) ดูข้อมูลเพิ่มเติมในเลือก

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

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

มาโครสามารถรับค่าแอตทริบิวต์จากกฎหรือมาโครอื่นได้โดยการส่งกฎหรือสัญลักษณ์มาโครไปยังอาร์กิวเมนต์ inherit_attrs ของ macro() (คุณยังใช้สตริงพิเศษ "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
def _my_macro_impl(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


# 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 สาธารณะได้โดยการส่งต่อค่าของแอตทริบิวต์ของตัวเอง visibility ดังเช่นใน some_rule(..., 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 และระดับการมองเห็น

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

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

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

เลือก

หากแอตทริบิวต์เป็น 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-wrapping จะไม่ทำให้ระบบจัดเก็บค่า select ที่ไม่สำคัญในเป้าหมายทั้งหมดที่สร้างขึ้นโดยใช้มาโคร

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

Finalizers

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

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

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

  • การเรียกใช้มาโครเวอร์ชันเดิม glob()

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

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

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

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

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