การอ้างอิง

รายงานปัญหา ดูแหล่งที่มา /3} /4} {3/4} {3/4} {3/4} {3/4} /4.

A เป้าหมายขึ้นอยู่กับ B เป้าหมาย หาก A จำเป็นต้องใช้ B ในเวลาบิลด์หรือการดำเนินการ ความสัมพันธ์ขึ้นอยู่กับจะทําให้เกิด กราฟแบบ Acyclic โดยตรง (DAG) เหนือเป้าหมาย และเรียกว่ากราฟการขึ้นต่อ

ทรัพยากร Dependency โดยตรงของเป้าหมายคือเป้าหมายอื่นๆ ที่เข้าถึงได้ด้วยเส้นทางความยาว 1 ในกราฟทรัพยากร Dependency ทรัพยากร 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 ด้วย อาจกล่าวได้ว่า D เป็นค่าประมาณที่มากเกินไปของ A

ผู้เขียนไฟล์ BUILD ต้องประกาศการขึ้นต่อกันโดยตรงทั้งหมดอย่างชัดเจนสำหรับกฎทุกข้อกับระบบบิลด์ และจะไม่ต้องมีการประกาศอีก

การไม่ปฏิบัติตามหลักการนี้ทำให้เกิดลักษณะการทำงานที่ไม่ได้กำหนด: บิลด์อาจล้มเหลว แต่ที่แย่กว่านั้นคือ บิลด์อาจขึ้นอยู่กับการดำเนินการก่อนหน้าบางอย่าง หรือขึ้นอยู่กับทรัพยากร Dependency ที่ประกาศแบบสับเปลี่ยนซึ่งเป้าหมายเกิดขึ้น Bazel จะตรวจหาการขึ้นต่อกันที่ขาดหายไปและรายงานข้อผิดพลาด แต่การตรวจสอบนี้อาจไม่เสร็จสมบูรณ์ในทุกกรณี

คุณไม่จำเป็นต้อง (และไม่ควร) พยายามแสดงรายการทุกอย่างที่นำเข้าโดยอ้อม แม้ว่า A จะจำเป็นขณะดำเนินการก็ตาม

ระหว่างบิลด์ของเป้าหมาย X เครื่องมือสร้างจะตรวจสอบการปิดแบบทรานซิชันของทรัพยากร Dependency ทั้งหมดของ X เพื่อให้แน่ใจว่าการเปลี่ยนแปลงในเป้าหมายเหล่านั้นแสดงในผลลัพธ์สุดท้าย แล้วจึงสร้างตัวกลางใหม่ตามที่จำเป็น

ลักษณะการส่งต่อของทรัพยากร 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();
}
      
กราฟการขึ้นต่อกันที่ประกาศมีลูกศรเชื่อมต่อ a, b และ c
กราฟทรัพยากร Dependency ที่ประกาศไว้
กราฟทรัพยากร Dependency จริงที่ตรงกับกราฟทรัพยากร Dependency ที่ประกาศไว้โดยมีลูกศรเชื่อมต่อ a, b และ c
กราฟทรัพยากร Dependency ตามจริง

ทรัพยากร Dependency ที่ประกาศมีค่าใกล้เคียงของการอ้างอิงจริงมากเกินไป ทุกอย่างเรียบร้อยดี

2. การเพิ่มทรัพยากร Dependency ที่ไม่ได้ประกาศ

เกิดอันตรายแฝงเมื่อมีคนเพิ่มโค้ดไปยัง a ที่สร้างทรัพยากร Dependency จริง โดยตรงใน c แต่ลืมประกาศในไฟล์บิลด์ a/BUILD

a / a.in  
        import b;
        import c;
        b.foo();
        c.garply();
      
 
กราฟการขึ้นต่อกันที่ประกาศมีลูกศรเชื่อมต่อ a, b และ c
กราฟทรัพยากร Dependency ที่ประกาศไว้
กราฟทรัพยากร Dependency จริงมีลูกศรเชื่อม a, b และ c ตอนนี้ลูกศรจะเชื่อมต่อ A กับ C ด้วย ซึ่งไม่ตรงกับกราฟทรัพยากร Dependency ที่ประกาศไว้
กราฟทรัพยากร Dependency ตามจริง

ทรัพยากร 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();
      }
      
กราฟการขึ้นต่อกันที่ประกาศและมีลูกศรเชื่อมต่อ a และ b
                  b ไม่เชื่อมต่อกับ c อีกต่อไป ซึ่งจะทำลายการเชื่อมต่อของ a กับ c
กราฟทรัพยากร Dependency ที่ประกาศไว้
กราฟทรัพยากร Dependency จริงที่แสดงการเชื่อมต่อกับ b และ c แต่ b ไม่เชื่อมต่อกับ c แล้ว
กราฟทรัพยากร Dependency ตามจริง

ขณะนี้กราฟทรัพยากร Dependency ที่ประกาศแสดงค่าการขึ้นต่อกันจริงน้อยเกินไปแม้ว่าจะปิดชั่วคราวอยู่ แต่บิลด์มีแนวโน้มที่จะล้มเหลว

ปัญหาอาจได้รับการแก้ไขได้ด้วยการตรวจสอบว่ามีการประกาศทรัพยากร Dependency จริงจาก a ถึง c ในขั้นตอนที่ 2 อย่างถูกต้องในไฟล์ BUILD

ประเภทของทรัพยากร Dependency

กฎการสร้างส่วนใหญ่มีแอตทริบิวต์ 3 แบบสำหรับการระบุทรัพยากร Dependency ทั่วไปประเภทต่างๆ ได้แก่ srcs, deps และ data ซึ่งจะมีการอธิบายไว้ด้านล่าง โปรดดูรายละเอียดเพิ่มเติมที่หัวข้อแอตทริบิวต์ที่มีอยู่ในกฎทั้งหมด

กฎจำนวนมากยังมีแอตทริบิวต์เพิ่มเติมสำหรับประเภทการขึ้นต่อกันที่เจาะจงกฎ เช่น compiler หรือ resources ซึ่งมีรายละเอียดอยู่ใน Build Encyclopedia

ทรัพยากร Dependency srcs

ไฟล์ที่กฎหรือกฎใช้โดยตรงซึ่งแสดงผลไฟล์ต้นฉบับ

ทรัพยากร Dependency deps

กฎที่ชี้ไปยังโมดูลที่คอมไพล์แยกกันจะมีไฟล์ส่วนหัว สัญลักษณ์ ไลบรารี ข้อมูล ฯลฯ

ทรัพยากร Dependency data

เป้าหมายของบิลด์อาจต้องมีไฟล์ข้อมูลบางไฟล์เพื่อให้ทํางานได้อย่างถูกต้อง ไฟล์ข้อมูลเหล่านี้ไม่ใช่ซอร์สโค้ด ซึ่งไม่ส่งผลต่อวิธีสร้างเป้าหมาย เช่น การทดสอบหน่วยอาจเปรียบเทียบเอาต์พุตของฟังก์ชันกับเนื้อหาของไฟล์ เมื่อสร้างการทดสอบ 1 หน่วย คุณไม่จำเป็นต้องใช้ไฟล์ แต่ต้องเรียกใช้เมื่อทำการทดสอบ เช่นเดียวกันกับเครื่องมือที่เปิดขึ้นมาในระหว่างการดำเนินการ

ระบบบิลด์จะทำการทดสอบในไดเรกทอรีที่แยกต่างหากซึ่งมีเฉพาะไฟล์ที่ระบุว่าเป็น 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 ในการทดสอบ

สร้างไฟล์ ระดับการแชร์