หน้านี้จะอธิบายพื้นฐานและประโยชน์ของการใช้แง่มุม รวมถึงแสดงตัวอย่างแบบง่ายและแบบขั้นสูง
ส่วนช่วยให้คุณเพิ่มกราฟความเกี่ยวข้องของบิลด์ด้วยข้อมูลเพิ่มเติมและการดําเนินการ สถานการณ์ทั่วไปที่อาจเป็นประโยชน์ในการใช้แง่มุมมีดังนี้
- IDE ที่ผสานรวม Bazel สามารถใช้แง่มุมต่างๆ เพื่อรวบรวมข้อมูลเกี่ยวกับโปรเจ็กต์ได้
- เครื่องมือสร้างโค้ดสามารถใช้ประโยชน์จากแง่มุมต่างๆ เพื่อดำเนินการกับอินพุตในลักษณะไม่เจาะจงเป้าหมาย ตัวอย่างเช่น ไฟล์
BUILD
สามารถระบุลำดับชั้นของคำจำกัดความไลบรารี protocolbuf และกฎเฉพาะภาษาสามารถใช้องค์ประกอบต่างๆ เพื่อแนบการดำเนินการที่สร้างโค้ดการสนับสนุน 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 นั้น แง่มุมหนึ่งๆ มีการนําไปใช้ และรายการแอตทริบิวต์ทั้งหมดที่เผยแพร่ไปพร้อมกับแง่มุมนั้น พิจารณาแง่มุม 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'],
)
เรามาแยกตัวอย่างออกเป็นส่วนๆ และพิจารณาแต่ละส่วนกัน
คําจํากัดความของ Aspect
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 []
ฟังก์ชันการติดตั้งใช้งานแง่มุมจะคล้ายกับฟังก์ชันการติดตั้งใช้งานกฎ โดยจะแสดงผลผู้ให้บริการ สร้างการดำเนินการ และรับอาร์กิวเมนต์ 2 รายการ ดังนี้
target
: เป้าหมายที่มีการใช้แง่มุมctx
: ออบเจ็กต์ctx
ที่ใช้เข้าถึงแอตทริบิวต์ ตลอดจนสร้างเอาต์พุตและการดําเนินการได้
ฟังก์ชันการใช้งานเข้าถึงแอตทริบิวต์ของกฎเป้าหมายได้ผ่าน ctx.rule.attr
โดยสามารถตรวจสอบผู้ให้บริการที่ได้จากเป้าหมายที่ใช้ (ผ่านอาร์กิวเมนต์ target
)
จำเป็นต้องระบุแง่มุมเพื่อแสดงรายการผู้ให้บริการ ในตัวอย่างนี้ ข้อมูลพร็อพเพอร์ตี้ไม่ได้ระบุข้อมูลใดๆ ระบบจึงแสดงผลรายการว่าง
การเรียกใช้มุมมองโดยใช้บรรทัดคำสั่ง
วิธีที่ง่ายที่สุดในการใช้แง่มุมคือจากบรรทัดคำสั่งโดยใช้อาร์กิวเมนต์ --aspects
สมมติว่ามีการกําหนดแง่มุมข้างต้นในไฟล์ชื่อ print.bzl
ดังนี้
bazel build //MyExample:example --aspects print.bzl%print_aspect
จะใช้ print_aspect
กับ example
เป้าหมายและกฎเป้าหมายทั้งหมดที่เข้าถึงแบบซ้ำผ่านแอตทริบิวต์ deps
แฟล็ก --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',
)
คําจํากัดความของ Aspect
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
1 ช่อง แนวทางปฏิบัติแนะนำคือให้กําหนดช่องของผู้ให้บริการอย่างชัดเจนโดยใช้แอตทริบิวต์ fields
กลุ่มผู้ให้บริการสำหรับแอปพลิเคชันด้าน A(X) คือการรวมผู้ให้บริการที่มาจากการใช้กฎสำหรับเป้าหมาย X และจากการใช้งานด้าน A ระบบจะสร้างและตรึงผู้ให้บริการที่การใช้งานกฎนำไปใช้ก่อนที่จะนำแอตทริบิวต์ไปใช้ และไม่สามารถแก้ไขจากแอตทริบิวต์ได้ ระบบจะแสดงข้อผิดพลาดหากเป้าหมายและองค์ประกอบที่ใช้กับเป้าหมายแต่ละรายการมีผู้ให้บริการประเภทเดียวกัน ยกเว้น OutputGroupInfo
(ซึ่งจะผสานกัน ตราบใดที่กฎและองค์ประกอบระบุกลุ่มเอาต์พุตที่แตกต่างกัน) และ InstrumentedFilesInfo
(ซึ่งนำมาจากองค์ประกอบ) ซึ่งหมายความว่าการติดตั้งใช้งานแอตทริบิวต์อาจไม่แสดง DefaultInfo
เลย
ระบบจะส่งพารามิเตอร์และแอตทริบิวต์ส่วนตัวในแอตทริบิวต์ของ ctx
ตัวอย่างนี้อ้างอิงพารามิเตอร์ extension
และกำหนดไฟล์ที่จะนับ
สำหรับผู้ให้บริการที่กลับมา ระบบจะแทนที่ค่าของแอตทริบิวต์ที่มีการเผยแพร่ (จากรายการ attr_aspects
) ด้วยผลลัพธ์ของการใช้ลักษณะดังกล่าว เช่น หากเป้าหมาย
X มี Y และ Z ใน deps ctx.rule.attr.deps
สำหรับ A(X) จะเป็น [A(Y), A(Z)]
ในตัวอย่างนี้ ctx.rule.attr.deps
คือออบเจ็กต์เป้าหมาย ซึ่งเป็นผลลัพธ์จากการนำแง่มุมไปใช้กับ "deps" ของเป้าหมายเดิมที่ใช้ลักษณะดังกล่าว
ในตัวอย่างนี้ สัดส่วนภาพจะเข้าถึงผู้ให้บริการ FileCountInfo
จากทรัพยากร Dependency ของเป้าหมายเพื่อสะสมจำนวนไฟล์ทรานซิทีฟทั้งหมด
การเรียกใช้แง่มุมจากกฎ
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