เป้าหมาย A
ขึ้นอยู่กับ B
เป้าหมาย หาก A
จำเป็นต้องใช้ B
ที่บิลด์หรือ
เวลาดำเนินการ ความสัมพันธ์ที่ ขึ้นอยู่กับ ทำให้เกิด
กราฟแบบ Acyclic ที่มีทิศทาง
(DAG) สูงกว่าเป้าหมาย เรียกว่ากราฟการขึ้นต่อกัน
ทรัพยากร Dependency โดยตรงของเป้าหมายคือเป้าหมายอื่นๆ ที่เข้าถึงได้โดยเส้นทาง ความยาว 1 ในกราฟทรัพยากร Dependency ทรัพยากร Dependency แบบสโลแกน ของเป้าหมาย เป้าหมายที่เป้าหมายนั้นพึ่งพิงผ่านเส้นทางที่มีความยาวเท่าใดก็ได้ผ่านกราฟ
อันที่จริงแล้ว ในบริบทของการสร้าง จะมีกราฟการพึ่งพา 2 แบบ นั่นคือกราฟ ของทรัพยากร Dependency จริง และกราฟของทรัพยากร Dependency ที่ประกาศ ส่วนใหญ่ กราฟทั้งสองมีความคล้ายคลึงกันมากจนไม่จำเป็นต้องแยกความแตกต่างนี้ ก็จะเป็นประโยชน์สำหรับการพูดคุยด้านล่างนี้
ทรัพยากร Dependency จริงและที่ประกาศแล้ว
X
เป้าหมายขึ้นอยู่กับ Y
เป้าหมาย หากต้องมี Y
และเป็นปัจจุบันเพื่อให้ X
สร้างอย่างถูกต้อง สร้าง
หมายถึง การสร้าง ประมวลผล คอมไพล์ เชื่อมโยง เก็บถาวร บีบอัด ดำเนินการ หรือ
งานประเภทอื่นๆ ที่เกิดขึ้นเป็นประจำระหว่างการสร้าง
X
เป้าหมายมีทรัพยากร Dependency ที่ประกาศแล้วใน Y
เป้าหมาย หากมีทรัพยากร Dependency
ขอบจาก X
เป็น Y
ในแพ็กเกจของ X
สำหรับบิลด์ที่ถูกต้อง กราฟของทรัพยากร Dependency จริง A ต้องเป็นกราฟย่อยของ
กราฟของทรัพยากร Dependency ที่ประกาศ D นั่นคือ ทุกคู่ของ
โหนดที่เชื่อมต่อโดยตรง x --> y
ใน A ต้องเชื่อมต่อโดยตรงใน
ง. อาจกล่าวได้ว่า D เป็นค่าประมาณที่มากเกินไปของ A
ผู้เขียนไฟล์ BUILD
คนต้องประกาศโดยตรงทั้งหมดอย่างชัดเจน
ทรัพยากร Dependency สำหรับกฎทุกกฎไปยังระบบบิลด์ จึงไม่อีกต่อไป
การไม่ปฏิบัติตามหลักการนี้ทำให้เกิดลักษณะการทำงานที่ไม่ได้กำหนดไว้: บิลด์อาจล้มเหลว แต่ที่แย่กว่านั้นคือ เวอร์ชันอาจขึ้นอยู่กับการดำเนินการก่อนหน้านี้บางส่วน หรือเป็นการเปลี่ยนเส้นทาง ทรัพยากร Dependency ที่ประกาศไว้โดยมีเป้าหมาย Bazel ตรวจหาการสูญหาย ทรัพยากร Dependency และรายงานข้อผิดพลาด เป็นไปไม่ได้ที่การตรวจสอบนี้จะ เสร็จสมบูรณ์ในทุกกรณี
คุณไม่จำเป็นต้อง (และไม่ควร) พยายามแสดงรายการทั้งหมดที่นำเข้าโดยอ้อม
แม้ว่าจะจำเป็นโดย A
ในเวลาดำเนินการก็ตาม
ระหว่างบิลด์ของเป้าหมาย X
เครื่องมือสร้างจะตรวจสอบทรานซิทีฟทั้งหมด
การปิดทรัพยากร Dependency ของ X
เพื่อให้มั่นใจว่าการเปลี่ยนแปลงในเป้าหมายเหล่านั้น
แสดงในผลลัพธ์สุดท้าย การสร้างตัวกลางใหม่ตามที่จำเป็น
ลักษณะการส่งต่อของทรัพยากร Dependency จะทําให้เกิดข้อผิดพลาดที่พบบ่อย บางครั้ง
โค้ดในไฟล์หนึ่งอาจใช้โค้ดที่ได้จากทรัพยากร Dependency โดยอ้อม ซึ่งก็คือ
สกรรม แต่ไม่ใช่ขอบโดยตรงในกราฟทรัพยากร Dependency ที่ประกาศ โดยอ้อม
ทรัพยากร Dependency ไม่ปรากฏในไฟล์ BUILD
เนื่องจากกฎนี้จะไม่
ขึ้นอยู่กับผู้ให้บริการโดยตรง จะไม่มีวิธีติดตามการเปลี่ยนแปลง ดังที่แสดงใน
ไทม์ไลน์ตัวอย่างต่อไปนี้
1. ทรัพยากร Dependency ที่ประกาศตรงกับทรัพยากร Dependency จริง
เมื่อเริ่มต้น ทุกอย่างก็จะทำงาน รหัสในแพ็กเกจ a
ใช้รหัสในแพ็กเกจ b
รหัสในแพ็กเกจ b
ใช้รหัสในแพ็กเกจ c
ดังนั้นจึงเป็น a
แบบชั่วคราว
ขึ้นอยู่กับ c
a/BUILD |
b/BUILD |
---|---|
rule( name = "a", srcs = "a.in", deps = "//b:b", ) |
rule( name = "b", srcs = "b.in", deps = "//c:c", ) |
a / a.in |
b / b.in |
import b; b.foo(); |
import c; function foo() { c.bar(); } |
|
|
ทรัพยากร Dependency ที่ประกาศมีค่าใกล้เคียงของการอ้างอิงจริงมากเกินไป ทุกอย่างเรียบร้อยดี
2. การเพิ่มทรัพยากร Dependency ที่ไม่ได้ประกาศ
อันตรายแฝงจะแสดงขึ้นเมื่อมีคนเพิ่มโค้ดใน a
ที่สร้าง
การขึ้นต่อกันจริงโดยตรงใน c
แต่ลืมประกาศในไฟล์บิลด์
a/BUILD
a / a.in |
|
---|---|
import b; import c; b.foo(); c.garply(); |
|
|
|
ทรัพยากร Dependency ที่ประกาศไม่ประเมินจำนวนการพึ่งพาจริงมากเกินไปอีกต่อไป
รูปแบบนี้อาจไม่มีปัญหา เนื่องจากการปิดทางอ้อมของกราฟทั้ง 2 แบบเท่ากัน
แต่มาสก์มีปัญหา: a
มีการขึ้นต่อกันจริงที่ยังไม่ได้ประกาศใน c
3. ความแตกต่างระหว่างกราฟทรัพยากร Dependency ที่ประกาศกับกราฟการอ้างอิงจริง
อันตรายจะถูกเปิดเผยเมื่อมีคนเปลี่ยนโครงสร้างภายในโค้ด b
เพื่อที่จะได้ไม่พึ่งพาอีกต่อไป
c
ทำให้ a
หลุดโดยไม่ตั้งใจ
ความผิดของตัวเอง
b/BUILD |
|
---|---|
rule( name = "b", srcs = "b.in", deps = "//d:d", ) |
|
b / b.in |
|
import d; function foo() { d.baz(); } |
|
|
|
ขณะนี้กราฟทรัพยากร Dependency ที่ประกาศเป็นค่าประมาณที่ต่ำไปของ ทรัพยากร Dependency แม้ว่าจะปิดชั่วคราว บิลด์นั้นมีแนวโน้มว่าจะไม่สำเร็จ
ปัญหาอาจหายไปได้ด้วยการตรวจสอบความเชื่อมโยงจริงจาก
a
ถึง c
ที่แนะนำในขั้นตอนที่ 2 ได้รับการประกาศอย่างถูกต้องในไฟล์ BUILD
ประเภทของทรัพยากร Dependency
กฎการสร้างส่วนใหญ่มีแอตทริบิวต์ 3 แบบสำหรับการระบุประเภทต่างๆ
ทรัพยากร Dependency ทั่วไป: srcs
, deps
และ data
ซึ่งจะมีการอธิบายไว้ด้านล่าง สำหรับ
รายละเอียดเพิ่มเติม โปรดดู
แอตทริบิวต์ที่มีอยู่ในกฎทั้งหมด
กฎจำนวนมากยังมีแอตทริบิวต์เพิ่มเติมสำหรับประเภทของกฎ
ทรัพยากร Dependency เช่น compiler
หรือ resources
ซึ่งจะระบุรายละเอียดไว้ใน
สร้างสารานุกรม
ทรัพยากร Dependency srcs
ไฟล์ที่กฎหรือกฎใช้โดยตรงซึ่งแสดงผลไฟล์ต้นฉบับ
ทรัพยากร Dependency deps
กฎที่ชี้ไปยังโมดูลที่คอมไพล์แยกกันซึ่งระบุไฟล์ส่วนหัว สัญลักษณ์ ไลบรารี ข้อมูล ฯลฯ
ทรัพยากร Dependency data
เป้าหมายของบิลด์อาจต้องมีไฟล์ข้อมูลบางไฟล์เพื่อให้ทํางานได้อย่างถูกต้อง ไฟล์ข้อมูลเหล่านี้ ไม่ใช่ซอร์สโค้ด เพราะจะไม่ส่งผลต่อวิธีสร้างเป้าหมาย ตัวอย่างเช่น การทดสอบหน่วยอาจเปรียบเทียบเอาต์พุตของฟังก์ชันกับเนื้อหาของไฟล์ เมื่อคุณ สร้างการทดสอบหน่วยคุณไม่จำเป็นต้องใช้ไฟล์ แต่คุณต้องใช้ไฟล์เมื่อคุณเรียกใช้ การทดสอบ เช่นเดียวกันกับเครื่องมือที่เปิดขึ้นมาในระหว่างการดำเนินการ
ระบบบิลด์จะทำการทดสอบในไดเรกทอรีที่แยกต่างหากซึ่งมีเฉพาะไฟล์ที่แสดงรายการเป็น
data
ว่างอยู่ ดังนั้น หากไบนารี/ไลบรารี/การทดสอบต้องการไฟล์ที่จะเรียกใช้
ให้ระบุ (หรือกฎบิลด์ที่มีคีย์ดังกล่าว) ใน data
เช่น
# I need a config file from a directory named env:
java_binary(
name = "setenv",
...
data = [":env/default_env.txt"],
)
# I need test data from another directory
sh_test(
name = "regtest",
srcs = ["regtest.sh"],
data = [
"//data:file1.txt",
"//data:file2.txt",
...
],
)
ไฟล์เหล่านี้พร้อมใช้งานโดยใช้เส้นทางที่เกี่ยวข้อง path/to/data/file
ในการทดสอบ
คุณดูไฟล์เหล่านี้ได้โดยรวมเส้นทางของแหล่งที่มาของการทดสอบ
และเส้นทางที่สัมพันธ์กับพื้นที่ทำงาน เช่น
${TEST_SRCDIR}/workspace/path/to/data/file
การใช้ป้ายกำกับเพื่ออ้างอิงไดเรกทอรี
ขณะที่คุณตรวจดูไฟล์ BUILD
ของเรา คุณอาจเห็นว่าป้ายกำกับ data
บางรายการ
อ้างอิงถึงไดเรกทอรี ป้ายกำกับเหล่านี้ลงท้ายด้วย /.
หรือ /
ดังตัวอย่างต่อไปนี้
ที่คุณไม่ควรใช้:
ไม่แนะนำ —
data = ["//data/regression:unittest/."]
ไม่แนะนำ —
data = ["testdata/."]
ไม่แนะนำ —
data = ["testdata/"]
วิธีนี้ดูเหมือนจะสะดวก โดยเฉพาะสำหรับการทดสอบ เนื่องจากช่วยให้การทดสอบ ใช้ไฟล์ข้อมูลทั้งหมดในไดเรกทอรี
แต่อย่าพยายามทำเช่นนั้น เพื่อให้แน่ใจว่ามีการปรับปรุงส่วนเพิ่มอย่างถูกต้อง (และ
ดำเนินการทดสอบซ้ำ) หลังการเปลี่ยนแปลง ระบบบิลด์จะต้องตระหนักถึง
ชุดของไฟล์ที่สมบูรณ์ที่เป็นอินพุตของบิลด์ (หรือทดสอบ) เมื่อคุณระบุ
ไดเรกทอรี ระบบบิลด์จะสร้างใหม่เฉพาะเมื่อไดเรกทอรี
การเปลี่ยนแปลง (เนื่องจากมีการเพิ่มหรือลบไฟล์) แต่ไม่สามารถตรวจหา
แก้ไขแต่ละไฟล์ เนื่องจากการเปลี่ยนแปลงเหล่านั้นจะไม่มีผลกับไดเรกทอรีที่ล้อมรอบอยู่
แทนที่จะระบุไดเรกทอรีเป็นอินพุตไปยังระบบบิลด์ คุณควร
แจกแจงชุดของไฟล์ที่อยู่ในไฟล์เหล่านั้น โดยระบุอย่างชัดเจนหรือโดยใช้ฟังก์ชัน
glob()
(ใช้ **
เพื่อบังคับ
glob()
ให้เกิดซ้ำ)
แนะนำ —
data = glob(["testdata/**"])
อย่างไรก็ตาม อาจมีบางกรณีที่ต้องใช้ป้ายกำกับไดเรกทอรี
ตัวอย่างเช่น ถ้าไดเรกทอรี testdata
มีไฟล์ที่ไม่มีชื่อ
สอดคล้องกับไวยากรณ์ป้ายกำกับ
แจกแจงไฟล์อย่างชัดเจน หรือการใช้
ฟังก์ชัน glob()
สร้างป้ายกำกับที่ไม่ถูกต้อง
คุณต้องใช้ป้ายกำกับไดเรกทอรีในกรณีนี้ แต่โปรดระวัง
ความเสี่ยงที่เกี่ยวข้องในการสร้างใหม่ที่ไม่ถูกต้องตามที่อธิบายไว้ข้างต้น
หากคุณจำเป็นต้องใช้ป้ายกำกับไดเรกทอรี โปรดทราบว่าคุณไม่สามารถอ้างอิง
แพ็กเกจหลักที่มีเส้นทาง ../
แบบสัมพัทธ์ ให้ใช้เส้นทางสัมบูรณ์ เช่น
//data/regression:unittest/.
กฎภายนอกใดๆ เช่น การทดสอบ ที่ต้องใช้หลายไฟล์จะต้อง
ประกาศการพึ่งพากันอย่างชัดเจน คุณสามารถใช้ filegroup()
เพื่อ
จัดกลุ่มไฟล์ไว้ด้วยกันในไฟล์ BUILD
filegroup(
name = 'my_data',
srcs = glob(['my_unittest_data/*'])
)
จากนั้นคุณสามารถอ้างอิงป้ายกำกับ my_data
เป็นทรัพยากร Dependency ในการทดสอบ
สร้างไฟล์ | ระดับการเข้าถึง |