การอ้างอิง

วันที่ รายงานปัญหา ดูแหล่งที่มา ตอนกลางคืน · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

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

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

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

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

a / a.in  
        import b;
        import c;
        b.foo();
        c.garply();
      
 
วันที่ กราฟการขึ้นต่อกันที่ประกาศมีลูกศรเชื่อมต่อ a, b และ c
กราฟทรัพยากร Dependency ที่ประกาศแล้ว
วันที่ กราฟทรัพยากร Dependency จริงมีลูกศรเชื่อม a, b และ c CANNOT TRANSLATE
                  ตอนนี้ลูกศรเชื่อมต่อ A กับ C ด้วย ซึ่งไม่ตรงกับ
                  กราฟทรัพยากร 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 แม้ว่าจะปิดชั่วคราว บิลด์นั้นมีแนวโน้มว่าจะไม่สำเร็จ

ปัญหาอาจหายไปได้ด้วยการตรวจสอบความเชื่อมโยงจริงจาก 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 ในการทดสอบ

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