หน้านี้จะอธิบายพื้นฐานและประโยชน์ของการใช้แง่มุม รวมถึงแสดงตัวอย่างแบบง่ายและแบบขั้นสูง
ส่วนช่วยให้คุณเพิ่มกราฟความเกี่ยวข้องของบิลด์ด้วยข้อมูลเพิ่มเติมและการดําเนินการ สถานการณ์ทั่วไปที่อาจเป็นประโยชน์ในการใช้แง่มุมมีดังนี้
- IDE ที่ผสานรวม Bazel สามารถใช้แง่มุมต่างๆ เพื่อรวบรวมข้อมูลเกี่ยวกับโปรเจ็กต์ได้
- เครื่องมือสร้างโค้ดสามารถใช้ประโยชน์จากแง่มุมต่างๆ เพื่อดำเนินการกับอินพุตในลักษณะไม่เจาะจงเป้าหมาย ตัวอย่างเช่น ไฟล์
BUILD
สามารถระบุลำดับชั้นของคำจำกัดความไลบรารี protocolbuf และกฎเฉพาะภาษาสามารถใช้องค์ประกอบต่างๆ เพื่อแนบการดำเนินการที่สร้างโค้ดการสนับสนุน protobuf สำหรับภาษาหนึ่งๆ
ข้อมูลเบื้องต้นเกี่ยวกับการแสดงผล
ไฟล์ BUILD
ให้คำอธิบายเกี่ยวกับซอร์สโค้ดของโปรเจ็กต์ เช่น ไฟล์ต้นฉบับเป็นส่วนหนึ่งของโปรเจ็กต์ อาร์ติแฟกต์ (เป้าหมาย) ใดควรสร้างขึ้นจากไฟล์เหล่านั้น ทรัพยากร Dependency ระหว่างไฟล์เหล่านั้นเป็นอย่างไร ฯลฯ Bazel ใช้ข้อมูลนี้ในการสร้าง กล่าวคือ คำนวณชุดการดำเนินการที่จำเป็นในการสร้างอาร์ติแฟกต์ (เช่น การเรียกใช้คอมไพเลอร์หรือ Linker) และปฏิบัติการ 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 จะวิเคราะห์กราฟนี้โดยเรียกใช้ฟังก์ชันการใช้งานของกฎที่เกี่ยวข้อง (ในกรณีนี้คือ "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 จะคล้ายกับคําจํากัดความของกฎและกําหนดโดยใช้ฟังก์ชัน 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
ได้รับการกำหนดให้เป็นผู้ให้บริการที่มี 1 ช่อง count
แนวทางปฏิบัติแนะนำคือให้กําหนดช่องของผู้ให้บริการอย่างชัดเจนโดยใช้แอตทริบิวต์ 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
จากข้อกําหนดของเป้าหมายเพื่อรวบรวมจํานวนไฟล์ทั้งหมดที่ส่งผ่าน
การเรียกใช้แง่มุมจากกฎ
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