การอ้างอิง

รายงานปัญหา ดูแหล่งที่มา

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

ทรัพยากร Dependency แบบโดยตรง คือเป้าหมายอื่นๆ ที่เข้าถึงได้ด้วยเส้นทางความยาว 1 ในกราฟทรัพยากร Dependency ทรัพยากร Dependency เปลี่ยนผ่าน คือเป้าหมาย ที่ขึ้นอยู่กับเส้นทางความยาวใดก็ได้ผ่านกราฟ

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

ทรัพยากร Dependency จริงและที่ประกาศ

เป้าหมาย X จริงๆ แล้วอยู่ในเป้าหมาย Y หาก Y ต้องมีอยู่ สร้าง และเป็นปัจจุบันเพื่อให้ X สร้างได้อย่างถูกต้อง สร้าง หมายถึงงานที่สร้างขึ้น ประมวลผล รวบรวม ลิงก์ เก็บ บีบอัด ดําเนินการ หรืองานประเภทอื่นๆ ที่เกิดขึ้นเป็นประจําในระหว่างการสร้าง

เป้าหมาย X มีทรัพยากร Dependency ที่ประกาศในเป้าหมาย Y หากมีทรัพยากร Dependency จาก X ไปยัง Y ในแพ็กเกจ X

สําหรับบิลด์ที่ถูกต้อง กราฟของทรัพยากร Dependency จริง A ต้องเป็นประเภทย่อยของกราฟของทรัพยากร Dependency ที่ประกาศ D กล่าวคือ ทุกโหนดที่เชื่อมต่อโดยตรง x --> y ใน A ต้องเชื่อมต่อโดยตรงใน D ด้วย อาจกล่าวได้ว่า D เป็นการประมาณของ A

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

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

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

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

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

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

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

กฎจํานวนมากยังมีแอตทริบิวต์เพิ่มเติมสําหรับทรัพยากร Dependency เฉพาะกฎ เช่น compiler หรือ resources ดูรายละเอียดได้ในสร้างสารานุกรม

srcs ทรัพยากร Dependency

ไฟล์ที่กฎโดยตรงใช้หรือกฎที่ส่งออกไฟล์แหล่งที่มา

deps ทรัพยากร Dependency

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

data ทรัพยากร Dependency

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

ไฟล์ที่สร้าง ระดับการเข้าถึง