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