หน้านี้ครอบคลุมข้อมูลเบื้องต้นเกี่ยวกับการใช้มาโคร รวมถึงกรณีการใช้งานทั่วไป การแก้ไขข้อบกพร่อง และรูปแบบการตั้งชื่อ
มาโครคือฟังก์ชันที่เรียกจากไฟล์ BUILD ซึ่งสามารถสร้างอินสแตนซ์ของกฎได้
โดยส่วนใหญ่แล้วจะใช้มาโครเพื่อการห่อหุ้มและการนำโค้ดของกฎและมาโครอื่นๆ ที่มีอยู่กลับมาใช้ซ้ำ
มาโครมี 2 รูปแบบ ได้แก่ มาโครเชิงสัญลักษณ์ ซึ่งอธิบายไว้ในหน้านี้ และ มาโครเดิม เราขอแนะนำให้ใช้มาโครเชิงสัญลักษณ์เพื่อความชัดเจนของโค้ดหากเป็นไปได้
มาโครเชิงสัญลักษณ์มีอาร์กิวเมนต์ที่พิมพ์ (การแปลงสตริงเป็นป้ายกำกับ ซึ่งสัมพันธ์กับตำแหน่งที่เรียกมาโคร) และความสามารถในการจำกัดและระบุระดับการเข้าถึงของเป้าหมายที่สร้างขึ้น โดยได้รับการออกแบบมาให้รองรับการประเมินแบบ Lazy (ซึ่งจะเพิ่มใน Bazel เวอร์ชันที่จะเปิดตัวในอนาคต) มาโครเชิงสัญลักษณ์พร้อมใช้งานโดยค่าเริ่มต้นใน Bazel 8 เมื่อเอกสารนี้กล่าวถึง macros จะหมายถึงมาโครเชิงสัญลักษณ์
ดูตัวอย่างมาโครเชิงสัญลักษณ์ที่เรียกใช้งานได้ใน ที่เก็บตัวอย่าง
การใช้งาน
คุณกำหนดมาโครในไฟล์ .bzl ได้โดยการเรียกฟังก์ชัน
macro() ด้วย
พารามิเตอร์ที่ต้องระบุ 2 รายการ ได้แก่ attrs และ implementation
แอตทริบิวต์
attrs ยอมรับพจนานุกรมของชื่อแอตทริบิวต์กับ attribute
types ซึ่งแสดงถึง
อาร์กิวเมนต์ของมาโคร ระบบจะเพิ่มแอตทริบิวต์ทั่วไป 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"}) ดูข้อมูลเพิ่มเติมใน Select
การรับค่าแอตทริบิวต์
มาโครมักมีไว้เพื่อห่อหุ้มกฎ (หรือมาโครอื่น) และผู้เขียนมาโครมักต้องการส่งต่อแอตทริบิวต์ส่วนใหญ่ของสัญลักษณ์ที่ห่อหุ้มไว้โดยไม่เปลี่ยนแปลง โดยใช้ **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
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 ไม่ได้
ไฟล์และเป้าหมายที่ไม่ใช่มาโครภายในแพ็กเกจเดียวกันกับอินสแตนซ์มาโคร ไม่ควร มีชื่อที่ขัดแย้งกับชื่อเป้าหมายมาโครที่อาจเกิดขึ้น แม้ว่าจะไม่มีการบังคับใช้การตั้งชื่อที่ไม่ซ้ำกันนี้ก็ตาม เรากำลังดำเนินการเพื่อใช้ การประเมินแบบ Lazy เพื่อปรับปรุงประสิทธิภาพของมาโครเชิงสัญลักษณ์ ซึ่งจะได้รับผลกระทบในแพ็กเกจที่ละเมิดรูปแบบการตั้งชื่อ
ข้อจำกัด
มาโครเชิงสัญลักษณ์มีข้อจำกัดเพิ่มเติมบางอย่างเมื่อเทียบกับมาโครเดิม
มาโครเชิงสัญลักษณ์
- ต้องใช้อาร์กิวเมนต์
nameและอาร์กิวเมนต์visibility - ต้องมีฟังก์ชัน
implementation - ต้องไม่แสดงผลค่า
- ต้องไม่เปลี่ยนแปลงอาร์กิวเมนต์
- ต้องไม่เรียก
native.existing_rules()เว้นแต่จะเป็นมาโครfinalizerพิเศษ - ต้องไม่เรียก
native.package() - ต้องไม่เรียก
glob() - ต้องไม่เรียก
native.environment_group() - ต้องสร้างเป้าหมายที่มีชื่อเป็นไปตามรูปแบบการตั้งชื่อ
- อ้างอิงไฟล์อินพุตที่ไม่ได้ประกาศหรือส่งเป็นอาร์กิวเมนต์ไม่ได้
- อ้างอิงเป้าหมายส่วนตัวของผู้เรียกไม่ได้ (ดู รายละเอียดเพิ่มเติมในระดับการเข้าถึงและมาโคร)
ระดับการเข้าถึงและมาโคร
ระบบระดับการเข้าถึงช่วยปกป้องรายละเอียดการใช้งาน ของทั้งมาโคร (เชิงสัญลักษณ์) และผู้เรียก
โดยค่าเริ่มต้น เป้าหมายที่สร้างขึ้นในมาโครเชิงสัญลักษณ์จะมองเห็นได้ภายในมาโครเอง แต่ไม่จำเป็นต้องมองเห็นได้สำหรับผู้เรียกมาโคร มาโครสามารถ "ส่งออก" เป้าหมายเป็น API สาธารณะได้โดยการส่งต่อค่าของแอตทริบิวต์ visibilityของตัวเอง เช่น some_rule(..., visibility = visibility)
แนวคิดหลักของระดับการเข้าถึงมาโครมีดังนี้
ระบบจะตรวจสอบระดับการเข้าถึงตามมาโครที่ประกาศเป้าหมาย ไม่ใช่แพ็กเกจที่เรียกมาโคร
- กล่าวอีกนัยหนึ่ง การอยู่ในแพ็กเกจเดียวกันไม่ได้ทำให้เป้าหมายหนึ่งมองเห็นเป้าหมายอื่นได้โดยอัตโนมัติ ซึ่งจะช่วยปกป้องเป้าหมายภายในของมาโครไม่ให้กลายเป็นทรัพยากร Dependency ของมาโครอื่นหรือเป้าหมายระดับบนสุดในแพ็กเกจ
แอตทริบิวต์
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()
Select
หากแอตทริบิวต์เป็น 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,
)
Lazy
สำคัญ: เรากำลังดำเนินการเพื่อใช้การขยายและการประเมินมาโครแบบ Lazy ฟีเจอร์นี้ยังไม่พร้อมใช้งาน
ปัจจุบัน ระบบจะประเมินมาโครทั้งหมดทันทีที่โหลดไฟล์ BUILD ซึ่งอาจส่งผลเสียต่อประสิทธิภาพของเป้าหมายในแพ็กเกจที่มีมาโครที่ไม่เกี่ยวข้องซึ่งใช้ทรัพยากรมาก ในอนาคต ระบบจะประเมินมาโครเชิงสัญลักษณ์ที่ไม่ใช่ Finalizer ก็ต่อเมื่อจำเป็นสำหรับการสร้างเท่านั้น รูปแบบการตั้งชื่อคำนำหน้าจะช่วยให้ Bazel กำหนดได้ว่าจะขยายมาโครใดเมื่อได้รับเป้าหมายที่ขอ
การแก้ปัญหาการย้ายข้อมูล
ต่อไปนี้คือปัญหาที่พบบ่อยในการย้ายข้อมูลและวิธีแก้ไข
- การเรียกมาโครเดิม
glob()
ย้ายการเรียก glob() ไปยังไฟล์ BUILD (หรือไปยังมาโครเดิมที่เรียกจากไฟล์ BUILD) และส่งค่า glob() ไปยังมาโครเชิงสัญลักษณ์โดยใช้แอตทริบิวต์รายการป้ายกำกับ
# BUILD file
my_macro(
...,
deps = glob(...),
)
- มาโครเดิมมีพารามิเตอร์ที่ไม่ใช่ประเภท
attrของ Starlark ที่ถูกต้อง
ดึงตรรกะให้ได้มากที่สุดเท่าที่จะทำได้ไปยังมาโครเชิงสัญลักษณ์ที่ซ้อนกัน แต่ให้มาโครระดับบนสุดเป็นมาโครเดิม
- มาโครเดิมเรียกกฎที่สร้างเป้าหมายซึ่งละเมิดรูปแบบการตั้งชื่อ
ไม่เป็นไร เพียงแค่อย่าใช้เป้าหมายที่ "ละเมิด" ระบบจะละเว้นการตรวจสอบการตั้งชื่อโดยไม่แจ้งให้ทราบ