หน้านี้จะอธิบายพื้นฐานและประโยชน์ของการใช้ aspects และแสดงแบบง่ายและแบบขั้นสูง ตัวอย่าง
ส่วนช่วยให้คุณเพิ่มกราฟความเกี่ยวข้องของบิลด์ด้วยข้อมูลเพิ่มเติมและการดําเนินการ ตัวอย่างสถานการณ์ทั่วไปที่อาจมีประโยชน์ มีดังนี้
- IDE ที่ผสานรวม Bazel สามารถใช้แง่มุมต่างๆ ในการรวบรวมข้อมูลเกี่ยวกับ
- เครื่องมือสร้างโค้ดสามารถใช้ประโยชน์จากแง่มุมต่างๆ เพื่อดำเนินการกับอินพุตใน
แบบไม่อิงตามเป้าหมาย เช่น ไฟล์
BUILD
สามารถระบุลำดับชั้นได้ จากไลบรารี protobuf และกฎเฉพาะภาษาสามารถใช้ลักษณะต่างๆ เพื่อแนบ การทำงานที่สร้างรหัสสนับสนุน Protobuf สำหรับภาษาใดภาษาหนึ่ง
ข้อมูลเบื้องต้นเกี่ยวกับการแสดงผล
ไฟล์ BUILD
ให้คำอธิบายซอร์สโค้ดของโปรเจ็กต์ ซึ่งได้แก่ ไฟล์ต้นฉบับใดเป็นส่วนหนึ่งของโปรเจ็กต์ อาร์ติแฟกต์ใด (เป้าหมาย) ควรสร้างจากไฟล์เหล่านั้น ไฟล์เหล่านั้นมีการพึ่งพากันอย่างไร ฯลฯ Bazel ใช้ข้อมูลนี้เพื่อทำการบิลด์ กล่าวคือ ค้นหาชุดการดำเนินการที่จำเป็นในการผลิตอาร์ติแฟกต์ (เช่น การเรียกใช้คอมไพเลอร์หรือโปรแกรมลิงก์) และดำเนินการเหล่านั้น Bazel ทําเช่นนี้ได้โดยการสร้างกราฟ Dependency ระหว่างเป้าหมายและไปที่กราฟนี้เพื่อรวบรวมการดําเนินการเหล่านั้น
ลองพิจารณาไฟล์ BUILD
ต่อไปนี้
java_library(name = 'W', ...)
java_library(name = 'Y', deps = [':W'], ...)
java_library(name = 'Z', deps = [':W'], ...)
java_library(name = 'Q', ...)
java_library(name = 'T', deps = [':Q'], ...)
java_library(name = 'X', deps = [':Y',':Z'], runtime_deps = [':T'], ...)
ไฟล์ BUILD
นี้จะกำหนดกราฟความเกี่ยวข้องดังที่แสดงในรูปภาพต่อไปนี้
รูปที่ 1 กราฟทรัพยากร Dependency ของไฟล์ BUILD
Bazel วิเคราะห์กราฟทรัพยากร Dependency นี้โดยการเรียกใช้ฟังก์ชันการใช้งานของ
กฎที่เกี่ยวข้อง (ในกรณีนี้คือ "java_library") ของทุก
ในตัวอย่างข้างต้น ฟังก์ชันการใช้กฎสร้างการกระทำที่
อาร์ติแฟกต์บิลด์ เช่น ไฟล์ .jar
และส่งข้อมูล เช่น ตำแหน่ง
และชื่อของอาร์ติแฟกต์เหล่านั้น ไปยังทรัพยากร Dependency แบบย้อนกลับของเป้าหมายเหล่านั้นใน
ผู้ให้บริการ
แง่มุมคล้ายกับกฎตรงที่มีฟังก์ชันการใช้งานซึ่งสร้างการดำเนินการและแสดงผลผู้ให้บริการ แต่ประสิทธิภาพของเครื่องมือเหล่านี้มาจากการสร้างกราฟทรัพยากร Dependency ด้านหนึ่งมีการใช้งาน และรายการแอตทริบิวต์ทั้งหมดที่จะเผยแพร่ออกไป ลองพิจารณาด้าน A ที่ กระจายไปตามแอตทริบิวต์ที่ชื่อว่า "deps" สามารถใช้แง่มุมนี้กับเป้าหมาย X ซึ่งจะให้โหนดการนําแอปพลิเคชันแง่มุม A(X) ระหว่างการใช้งาน ลักษณะ A จะมีผลซ้ำๆ กับเป้าหมายทั้งหมดที่ X อ้างถึงใน "deps" (แอตทริบิวต์ทั้งหมดในรายการการเผยแพร่ของ A)
ดังนั้น การใช้แง่มุม A กับเป้าหมาย X ครั้งเดียวจะให้ "กราฟเงา" ของกราฟ Dependency เดิมของเป้าหมายดังที่แสดงในรูปภาพต่อไปนี้
รูปที่ 2 สร้างกราฟด้วยแง่มุม
ขอบเดียวที่ถูกทำเป็นเงาคือขอบตามแอตทริบิวต์ใน
ชุดการเผยแพร่ ดังนั้น ขอบ runtime_deps
จึงไม่ถูกบังใน
จากนั้นระบบจะเรียกใช้ฟังก์ชันการใช้งานแง่มุมในโหนดทั้งหมดในกราฟเงา ซึ่งคล้ายกับวิธีเรียกใช้การใช้งานกฎในโหนดของกราฟต้นฉบับ
ตัวอย่างง่ายๆ
ตัวอย่างนี้แสดงวิธีพิมพ์ไฟล์ต้นทางของกฎและรายการที่เกี่ยวข้องทั้งหมดที่มีแอตทริบิวต์ deps
แบบซ้ำ ซึ่งจะแสดงการใช้งานแอตทริบิวต์ คําจํากัดความของแอตทริบิวต์ และวิธีเรียกใช้แอตทริบิวต์จากบรรทัดคําสั่ง Bazel
def _print_aspect_impl(target, ctx):
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the files that make up the sources and
# print their paths.
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
print(f.path)
return []
print_aspect = aspect(
implementation = _print_aspect_impl,
attr_aspects = ['deps'],
)
เรามาแยกตัวอย่างออกเป็นส่วนๆ และพิจารณาแต่ละส่วนกัน
คำจำกัดความ
print_aspect = aspect(
implementation = _print_aspect_impl,
attr_aspects = ['deps'],
)
คําจํากัดความของลักษณะจะคล้ายกับคําจํากัดความของกฎ และกำหนดโดยใช้ฟังก์ชัน aspect
เช่นเดียวกับกฎ แอตทริบิวต์มีฟังก์ชันการใช้งาน ซึ่งในกรณีนี้คือ
_print_aspect_impl
attr_aspects
คือรายการแอตทริบิวต์กฎที่ส่งผ่านแง่มุม
ในกรณีนี้ มุมมองจะกระจายไปตามแอตทริบิวต์ deps
ของ
กฎที่เกี่ยวข้อง
อีกอาร์กิวเมนต์ทั่วไปสําหรับ attr_aspects
คือ ['*']
ซึ่งจะเผยแพร่แง่มุมไปยังแอตทริบิวต์ทั้งหมดของกฎ
การใช้งาน Aspect
def _print_aspect_impl(target, ctx):
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the files that make up the sources and
# print their paths.
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
print(f.path)
return []
ฟังก์ชันการติดตั้งใช้งานแง่มุมจะคล้ายกับฟังก์ชันการติดตั้งใช้งานกฎ แสดงผู้ให้บริการซึ่งสามารถสร้าง actions และใช้อาร์กิวเมนต์ 2 รายการ
target
: เป้าหมายที่มีการใช้แง่มุมctx
: ออบเจ็กต์ctx
ที่ใช้เข้าถึงแอตทริบิวต์ได้ และสร้างเอาต์พุตและการดำเนินการ
ฟังก์ชันการใช้งานสามารถเข้าถึงแอตทริบิวต์ของกฎเป้าหมายผ่านทาง
ctx.rule.attr
โดยสามารถตรวจสอบผู้ให้บริการที่ได้จากเป้าหมายที่ใช้ (ผ่านอาร์กิวเมนต์ target
)
ต้องระบุ Aspect เพื่อแสดงผลรายชื่อผู้ให้บริการ ในตัวอย่างนี้ ลักษณะ ไม่ได้ให้ข้อมูลใดๆ เลย ระบบจึงแสดงผลรายการที่ว่างเปล่า
การเรียกใช้แอตทริบิวต์โดยใช้บรรทัดคำสั่ง
วิธีที่ง่ายที่สุดในการใช้แง่มุมคือจากบรรทัดคำสั่งโดยใช้อาร์กิวเมนต์ --aspects
สมมติว่ามีการกําหนดแง่มุมข้างต้นในไฟล์ชื่อ print.bzl
ดังนี้
bazel build //MyExample:example --aspects print.bzl%print_aspect
จะใช้ print_aspect
กับ example
เป้าหมายและ
กฎเป้าหมายที่เข้าถึงได้ซ้ำๆ ผ่านแอตทริบิวต์ deps
Flag --aspects
จะใช้อาร์กิวเมนต์ 1 รายการ ซึ่งเป็นข้อกำหนดของลักษณะในรูปแบบ <extension file label>%<aspect top-level name>
ตัวอย่างขั้นสูง
ตัวอย่างต่อไปนี้แสดงการใช้แง่มุมจากกฎเป้าหมายซึ่งนับไฟล์ในเป้าหมาย โดยอาจกรองไฟล์ตามนามสกุล แสดงวิธีใช้ผู้ให้บริการเพื่อแสดงผลค่า รวมถึงวิธีใช้พารามิเตอร์เพื่อส่ง อาร์กิวเมนต์เกี่ยวกับการติดตั้งใช้งานด้านต่างๆ และวิธีเรียกด้านจากกฎ
ไฟล์ file_count.bzl
:
FileCountInfo = provider(
fields = {
'count' : 'number of files'
}
)
def _file_count_aspect_impl(target, ctx):
count = 0
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the sources counting files
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if ctx.attr.extension == '*' or ctx.attr.extension == f.extension:
count = count + 1
# Get the counts from our dependencies.
for dep in ctx.rule.attr.deps:
count = count + dep[FileCountInfo].count
return [FileCountInfo(count = count)]
file_count_aspect = aspect(
implementation = _file_count_aspect_impl,
attr_aspects = ['deps'],
attrs = {
'extension' : attr.string(values = ['*', 'h', 'cc']),
}
)
def _file_count_rule_impl(ctx):
for dep in ctx.attr.deps:
print(dep[FileCountInfo].count)
file_count_rule = rule(
implementation = _file_count_rule_impl,
attrs = {
'deps' : attr.label_list(aspects = [file_count_aspect]),
'extension' : attr.string(default = '*'),
},
)
ไฟล์ BUILD.bazel
:
load('//:file_count.bzl', 'file_count_rule')
cc_library(
name = 'lib',
srcs = [
'lib.h',
'lib.cc',
],
)
cc_binary(
name = 'app',
srcs = [
'app.h',
'app.cc',
'main.cc',
],
deps = ['lib'],
)
file_count_rule(
name = 'file_count',
deps = ['app'],
extension = 'h',
)
คำจำกัดความ
file_count_aspect = aspect(
implementation = _file_count_aspect_impl,
attr_aspects = ['deps'],
attrs = {
'extension' : attr.string(values = ['*', 'h', 'cc']),
}
)
ตัวอย่างนี้แสดงวิธีที่แง่มุมดังกล่าวเผยแพร่ผ่านแอตทริบิวต์ deps
attrs
กำหนดชุดแอตทริบิวต์สำหรับแง่มุมหนึ่ง แอตทริบิวต์การแสดงผลแบบสาธารณะ
กำหนดพารามิเตอร์และเป็นได้เฉพาะประเภท bool
, int
หรือ string
สำหรับลักษณะที่เผยแพร่กฎ พารามิเตอร์ int
และ string
ต้องมี
values
ระบุไว้ ตัวอย่างนี้มีพารามิเตอร์ชื่อ extension
ที่ได้รับอนุญาตให้มี "*
" "h
" หรือ "cc
" เป็นค่า
สำหรับด้านที่มีการเผยแพร่กฎ ค่าพารามิเตอร์จะนำมาจากกฎที่ขอ
โดยใช้แอตทริบิวต์ของกฎที่มีชื่อและประเภทเดียวกัน
(ดูคำจำกัดความของ file_count_rule
)
สำหรับด้านบรรทัดคำสั่ง ค่าของพารามิเตอร์จะส่งได้โดยใช้
--aspects_parameters
แจ้ง ข้อจำกัด values
ของพารามิเตอร์ int
และ string
อาจมี
ละเว้น
ระบบยังอนุญาตให้มีแอตทริบิวต์ส่วนตัวประเภท label
หรือ
label_list
คุณใช้แอตทริบิวต์ป้ายกำกับส่วนตัวเพื่อระบุการพึ่งพาเครื่องมือหรือไลบรารีที่จําเป็นสําหรับการดําเนินการที่เกิดจากแง่มุมได้ ไม่มี
แอตทริบิวต์ส่วนตัวที่กำหนดไว้ในตัวอย่างนี้ แต่ข้อมูลโค้ดต่อไปนี้
จะสาธิตวิธีการส่งผ่านเครื่องมือไปยังแง่มุมหนึ่ง
...
attrs = {
'_protoc' : attr.label(
default = Label('//tools:protoc'),
executable = True,
cfg = "exec"
)
}
...
การใช้งาน Aspect
FileCountInfo = provider(
fields = {
'count' : 'number of files'
}
)
def _file_count_aspect_impl(target, ctx):
count = 0
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the sources counting files
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if ctx.attr.extension == '*' or ctx.attr.extension == f.extension:
count = count + 1
# Get the counts from our dependencies.
for dep in ctx.rule.attr.deps:
count = count + dep[FileCountInfo].count
return [FileCountInfo(count = count)]
เช่นเดียวกับฟังก์ชันการใช้งานกฎ ฟังก์ชันการใช้งานด้านต่างๆ จะแสดงผลโครงสร้างของผู้ให้บริการที่การอ้างอิงของผู้ให้บริการดังกล่าวเข้าถึงได้
ในตัวอย่างนี้ FileCountInfo
ได้รับการกำหนดให้เป็นผู้ให้บริการที่มี
ฟิลด์ count
แนวทางปฏิบัติแนะนำคือให้กําหนดช่องของผู้ให้บริการอย่างชัดเจนโดยใช้แอตทริบิวต์ fields
กลุ่มผู้ให้บริการสำหรับแอปพลิเคชันด้าน A(X) คือการรวมผู้ให้บริการ
ที่มาจากการใช้กฎสำหรับเป้าหมาย X และจาก
การนำลักษณะ A มาใช้ ผู้ให้บริการที่มีการใช้กฎ
ได้รับการสร้างและตรึงไว้ก่อนที่จะใช้ด้านต่างๆ และไม่สามารถดัดแปลงจาก
ด้านต่างๆ ระบบจะแสดงข้อผิดพลาดหากเป้าหมายและองค์ประกอบที่ใช้กับเป้าหมายแต่ละรายการมีผู้ให้บริการประเภทเดียวกัน ยกเว้น OutputGroupInfo
(ซึ่งจะผสานกัน ตราบใดที่กฎและองค์ประกอบระบุกลุ่มเอาต์พุตที่แตกต่างกัน) และ InstrumentedFilesInfo
(ซึ่งนำมาจากองค์ประกอบ) ซึ่งหมายความว่าการติดตั้งใช้งานด้านต่างๆ อาจ
ไม่ต้องแสดงผล DefaultInfo
ระบบจะส่งพารามิเตอร์และแอตทริบิวต์ส่วนตัวในแอตทริบิวต์ของ ctx
ตัวอย่างนี้อ้างอิงพารามิเตอร์ extension
และเป็นตัวกำหนด
ไฟล์ที่จะนับ
สําหรับผู้ให้บริการที่แสดงผล ระบบจะแทนที่ค่าของแอตทริบิวต์ที่เผยแพร่แง่มุม (จากรายการ attr_aspects
) ด้วยผลลัพธ์ของการใช้แง่มุมกับผู้ให้บริการ เช่น หากกำหนดเป้าหมาย
X มี Y และ Z อยู่ด้านใน โดย ctx.rule.attr.deps
สำหรับ A(X) จะเป็น [A(Y), A(Z)]
ในตัวอย่างนี้ ctx.rule.attr.deps
คือออบเจ็กต์เป้าหมายที่
ผลลัพธ์ของการนำแง่มุมดังกล่าวไปใช้กับ "ความลึก" ของเป้าหมายเดิมซึ่ง
ที่ได้รับการปรับปรุงแล้ว
ในตัวอย่างนี้ แอตทริบิวต์เข้าถึงผู้ให้บริการ FileCountInfo
จากข้อกําหนดของเป้าหมายเพื่อรวบรวมจํานวนไฟล์ทั้งหมดที่ส่งผ่าน
การเรียกใช้ลักษณะจากกฎ
def _file_count_rule_impl(ctx):
for dep in ctx.attr.deps:
print(dep[FileCountInfo].count)
file_count_rule = rule(
implementation = _file_count_rule_impl,
attrs = {
'deps' : attr.label_list(aspects = [file_count_aspect]),
'extension' : attr.string(default = '*'),
},
)
การใช้กฎสาธิตวิธีเข้าถึง FileCountInfo
ผ่าน ctx.attr.deps
คำจำกัดความของกฎแสดงวิธีกำหนดพารามิเตอร์ (extension
)
และกำหนดค่าเริ่มต้น (*
) โปรดทราบว่าการมีค่าเริ่มต้นที่
ไม่ใช่หนึ่งใน "cc
", "h
" หรือ "*
" ข้อผิดพลาดเนื่องจาก
การจำกัดที่ใช้กับพารามิเตอร์ในคำจำกัดความด้านไว้
การเรียกใช้องค์ประกอบผ่านกฎเป้าหมาย
load('//:file_count.bzl', 'file_count_rule')
cc_binary(
name = 'app',
...
)
file_count_rule(
name = 'file_count',
deps = ['app'],
extension = 'h',
)
ตัวอย่างนี้แสดงวิธีส่งพารามิเตอร์ extension
ไปยังมุมมอง
ผ่านกฎ เนื่องจากพารามิเตอร์ extension
มีค่าเริ่มต้นใน
การใช้งานกฎ extension
จะถือว่าเป็นพารามิเตอร์ที่ไม่บังคับ
เมื่อสร้างเป้าหมาย file_count
แล้ว ระบบจะประเมินแง่มุมของเราเองและเป้าหมายทั้งหมดที่เข้าถึงแบบซ้ำผ่าน deps