สร้างโปรแกรมด้วย Bazel

รายงานปัญหา ดูแหล่งที่มา รุ่น Nightly · 7.4 7.3 · 7.2 · 7.1 · 7.0 · 6.5

หน้านี้จะกล่าวถึงวิธีสร้างโปรแกรมด้วย Bazel, การสร้างไวยากรณ์คำสั่ง และ ของรูปแบบเป้าหมาย

คู่มือเริ่มใช้งานฉบับย่อ

หากต้องการเรียกใช้ Bazel ให้ไปที่ไดเรกทอรีพื้นที่ทำงานพื้นฐาน หรือไดเรกทอรีย่อยทั้งหมด และประเภท bazel ดูสร้างหากจำเป็นต้องสร้างพื้นที่ทำงานใหม่

bazel help
                             [Bazel release bazel version]
Usage: bazel command options ...

คำสั่งที่ใช้ได้

  • analyze-profile: วิเคราะห์ข้อมูลโปรไฟล์ของบิลด์
  • aquery: ดำเนินการค้นหาในกราฟการดำเนินการหลังการวิเคราะห์
  • build: สร้างเป้าหมายที่ระบุ
  • canonicalize-flags: กำหนดค่าแฟล็ก Bazel เป็นค่า Canonical
  • clean: นำไฟล์เอาต์พุตออกและหยุดเซิร์ฟเวอร์ (ไม่บังคับ)
  • cquery: ดำเนินการค้นหากราฟทรัพยากร Dependency สำหรับหลังการวิเคราะห์
  • dump: ถ่ายโอนสถานะภายในของกระบวนการของเซิร์ฟเวอร์ Bazel
  • help: พิมพ์ความช่วยเหลือสำหรับคำสั่งหรือดัชนี
  • info: แสดงข้อมูลรันไทม์เกี่ยวกับเซิร์ฟเวอร์ bazel
  • fetch: ดึงข้อมูลการอ้างอิงภายนอกทั้งหมดของเป้าหมาย
  • mobile-install: ติดตั้งแอปในอุปกรณ์เคลื่อนที่
  • query: ดำเนินการค้นหากราฟทรัพยากร Dependency
  • run: เรียกใช้เป้าหมายที่ระบุ
  • shutdown: หยุดเซิร์ฟเวอร์ Bazel
  • test: สร้างและเรียกใช้เป้าหมายการทดสอบที่ระบุ
  • version: พิมพ์ข้อมูลเวอร์ชันสำหรับ Bazel

การขอความช่วยเหลือ

  • bazel help command: ความช่วยเหลือและตัวเลือกสำหรับรูปภาพ command
  • bazel helpstartup_options: ตัวเลือกสําหรับ JVM ที่โฮสต์ Bazel
  • bazel helptarget-syntax: อธิบายไวยากรณ์สำหรับการระบุเป้าหมาย
  • bazel help info-keys: แสดงรายการคีย์ที่ใช้โดยคําสั่ง info

เครื่องมือ bazel ทำงานได้หลายอย่าง ซึ่งเรียกว่าคําสั่ง บ่อยที่สุด รายการที่ใช้คือ bazel build และ bazel test คุณสามารถเรียกดูความช่วยเหลือออนไลน์ ข้อความโดยใช้ bazel help

การสร้างเป้าหมาย 1 รายการ

คุณต้องมีเวิร์กスペースก่อนจึงจะเริ่มสร้างได้ พื้นที่ทำงาน โครงสร้างไดเรกทอรีที่มีไฟล์ต้นฉบับทั้งหมดที่ต้องใช้ในการสร้าง แอปพลิเคชัน Bazel ช่วยให้คุณสามารถสร้างจากแบบอ่านอย่างเดียวได้อย่างสมบูรณ์

หากต้องการสร้างโปรแกรมด้วย Bazel ให้พิมพ์ bazel build ตามด้วยเป้าหมายที่ต้องการสร้าง

bazel build //foo

หลังจากออกคำสั่งให้สร้าง //foo คุณจะเห็นเอาต์พุตคล้ายกับตัวอย่างต่อไปนี้

INFO: Analyzed target //foo:foo (14 packages loaded, 48 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
  bazel-bin/foo/foo
INFO: Elapsed time: 9.905s, Critical Path: 3.25s
INFO: Build completed successfully, 6 total actions

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

ในขั้นตอนการดำเนินการของบิลด์ Bazel จะพิมพ์ข้อความความคืบหน้า ข้อความความคืบหน้าจะแสดงขั้นตอนการสร้างปัจจุบัน (เช่น คอมไพเลอร์หรือโปรแกรมลิงก์) เมื่อเริ่มสร้าง และจำนวนที่เสร็จสมบูรณ์เทียบกับจำนวนการดำเนินการสร้างทั้งหมด ตามที่ จำนวนการดำเนินการทั้งหมดมักเพิ่มขึ้นเมื่อ Bazel ค้นพบ กราฟการดำเนินการทั้งหมด แต่ตัวเลขคงที่ภายใน 2-3 วินาที

เมื่อสิ้นสุดการสร้าง Bazel จะพิมพ์เป้าหมายที่ขอ การสร้างเป้าหมายสำเร็จหรือไม่ และหากสำเร็จ ไฟล์เอาต์พุตจะอยู่ที่ใด สคริปต์ที่เรียกใช้บิลด์สามารถแยกวิเคราะห์เอาต์พุตนี้ได้อย่างน่าเชื่อถือ ดู --show_result เพื่อดูรายละเอียดเพิ่มเติม

หากคุณพิมพ์คำสั่งเดิมอีกครั้ง บิลด์นั้นจะเสร็จสิ้นเร็วขึ้นมาก

bazel build //foo
INFO: Analyzed target //foo:foo (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
  bazel-bin/foo/foo
INFO: Elapsed time: 0.144s, Critical Path: 0.00s
INFO: Build completed successfully, 1 total action

นี่เป็นบิลด์ Null เนื่องจากไม่มีการเปลี่ยนแปลงใดๆ จึงไม่มีแพ็กเกจที่จะโหลดซ้ำและไม่มีขั้นตอนการสร้างที่จะดำเนินการ หากมีการเปลี่ยนแปลงใน "foo" หรือข้อกําหนด Bazel จะดําเนินการบางอย่างในบิลด์อีกครั้ง หรือทําบิลด์แบบเพิ่มให้เสร็จสมบูรณ์

การสร้างเป้าหมายหลายรายการ

Bazel มีวิธีระบุเป้าหมายที่จะสร้างได้หลายวิธี รายการเหล่านี้เรียกรวมกันว่ารูปแบบเป้าหมาย ไวยากรณ์นี้จะใช้ในคำสั่งต่างๆ เช่น build, test หรือ query

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

รูปแบบเป้าหมายทั้งหมดที่ขึ้นต้นด้วย // ได้รับการแก้ไขแล้วเมื่อเทียบกับรูปแบบปัจจุบัน Google Workspace ได้อย่างเต็มประสิทธิภาพ

//foo/bar:wiz เพียงเป้าหมายเดียวคือ //foo/bar:wiz
//foo/bar เทียบเท่ากับ //foo/bar:bar
//foo/bar:all เป้าหมายกฎทั้งหมดในแพ็กเกจ foo/bar
//foo/... เป้าหมายกฎทั้งหมดในแพ็กเกจทั้งหมดใต้ไดเรกทอรี foo
//foo/...:all เป้าหมายกฎทั้งหมดในแพ็กเกจทั้งหมดใต้ไดเรกทอรี foo
//foo/...:* เป้าหมายทั้งหมด (กฎและไฟล์) ในแพ็กเกจทั้งหมดภายใต้ไดเรกทอรี foo
//foo/...:all-targets เป้าหมายทั้งหมด (กฎและไฟล์) ในแพ็กเกจทั้งหมดที่อยู่ภายใต้ไดเรกทอรี foo
//... เป้าหมายทั้งหมดในแพ็กเกจในพื้นที่ทํางาน ไม่รวมเป้าหมาย จากที่เก็บภายนอก
//:all เป้าหมายทั้งหมดในแพ็กเกจระดับบนสุด หากมีไฟล์ "BUILD" ที่ รากของพื้นที่ทำงาน

ระบบจะแก้ไขรูปแบบเป้าหมายที่ไม่ได้ขึ้นต้นด้วย // โดยสัมพันธ์กับไดเรกทอรีทํางานปัจจุบัน ตัวอย่างเหล่านี้จะถือว่าไดเรกทอรีทํางานคือ foo

:foo เทียบเท่ากับ //foo:foo
bar:wiz เทียบเท่ากับ //foo/bar:wiz
bar/wiz เทียบเท่ากับ
  • //foo/bar/wiz:wiz หาก foo/bar/wiz เป็นแพ็กเกจ
  • //foo/bar:wiz หาก foo/bar เป็นแพ็กเกจ
  • //foo:bar/wiz เมื่อสั่งซื้อนอกเหนือจากมูลค่าที่กำหนด
bar:all เทียบเท่ากับ //foo/bar:all
:all เทียบเท่ากับ //foo:all
...:all เทียบเท่ากับ //foo/...:all
... เทียบเท่ากับ //foo/...:all
bar/...:all เทียบเท่ากับ //foo/bar/...:all

โดยค่าเริ่มต้น ระบบจะตามลิงก์สัญลักษณ์ไดเรกทอรีสำหรับรูปแบบเป้าหมายแบบทําซ้ำ ยกเว้นรูปแบบที่ชี้ไปยังฐานเอาต์พุต เช่น ลิงก์สัญลักษณ์ที่สร้างขึ้นเพื่ออำนวยความสะดวกในไดเรกทอรีรูทของเวิร์กスペース

นอกจากนี้ Bazel ไม่ติดตามลิงก์สัญลักษณ์เมื่อประเมินเป้าหมายที่เกิดซ้ำ รูปแบบในไดเรกทอรีที่มีไฟล์ชื่อดังนี้ DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN

foo/... คือไวลด์การ์ดสำหรับแพ็กเกจ ซึ่งระบุแพ็กเกจทั้งหมดที่เกิดซ้ำใต้ไดเรกทอรี foo (สำหรับรูททั้งหมดของเส้นทางแพ็กเกจ) :all เป็น ไวลด์การ์ดเหนือเป้าหมาย ซึ่งตรงกับกฎทั้งหมดภายในแพ็กเกจ ทั้ง 2 สิ่งนี้อาจ รวมกัน เช่นใน foo/...:all และเมื่อใช้ไวลด์การ์ดทั้ง 2 แบบ เป็น foo/...

นอกจากนี้ :* (หรือ :all-targets) เป็นไวลด์การ์ดที่ตรงกับเป้าหมายทุกรายการในแพ็กเกจที่ตรงกัน ซึ่งรวมถึงไฟล์ที่ไม่ได้สร้างตามกฎใดๆ โดยทั่วไป เช่น ไฟล์ _deploy.jar ที่เชื่อมโยงกับกฎ java_binary

ซึ่งหมายความว่า :* หมายถึงเซตที่ซ้อนกันของ :all แม้ว่าอาจทำให้เกิดความสับสน แต่ไวยากรณ์นี้ช่วยให้ใช้ไวลด์การ์ด :all ที่คุ้นเคยสำหรับบิลด์ทั่วไปได้ ซึ่งไม่ต้องการเป้าหมายการสร้างอย่าง _deploy.jar

นอกจากนี้ Bazel ยังอนุญาตให้ใช้เครื่องหมายทับแทนโคลอนที่จําเป็นตามไวยากรณ์ของป้ายกำกับ ซึ่งมักจะสะดวกเมื่อใช้การขยายชื่อไฟล์ Bash เช่น foo/bar/wiz มีค่าเท่ากับ //foo/bar:wiz (หากมีแพ็กเกจ foo/bar) หรือ //foo:bar/wiz (หากมีแพ็กเกจ foo)

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

bazel build foo/... bar/...

หมายถึง "สร้างเป้าหมายทั้งหมดภายใต้ foo และเป้าหมายทั้งหมดภายใต้ bar" ในขณะที่

bazel build -- foo/... -foo/bar/...

หมายถึง "สร้างเป้าหมายทั้งหมดภายใต้ foo ยกเว้นเป้าหมายที่อยู่ภายใต้ foo/bar" (พารามิเตอร์ ต้องมีอาร์กิวเมนต์ -- เพื่อป้องกันอาร์กิวเมนต์ลำดับต่อมาที่เริ่มต้นด้วย - จากการตีความเป็นตัวเลือกเพิ่มเติม)

อย่างไรก็ตาม โปรดทราบว่าการลบเป้าหมายด้วยวิธีนี้ไม่ได้รับประกันว่าระบบจะไม่สร้างเป้าหมายดังกล่าว เนื่องจากเป้าหมายเหล่านั้นอาจเป็นทรัพยากรของเป้าหมายที่ไม่ได้ถูกลบ ตัวอย่างเช่น หากมีเป้าหมาย //foo:all-apis ที่ขึ้นอยู่กับ //foo/bar:api รายการอื่นๆ ระบบจะสร้าง //foo/bar:api เป็นส่วนหนึ่งของการสร้าง //foo:all-apis

เป้าหมายที่มี tags = ["manual"] จะไม่รวมอยู่ในรูปแบบเป้าหมายไวลด์การ์ด (..., :*, :all ฯลฯ) เมื่อระบุไว้ในคําสั่ง เช่น bazel build และ bazel test (แต่จะรวมอยู่ในรูปแบบเป้าหมายไวลด์การ์ดเชิงลบ ซึ่งก็คือจะมีการลบออก) คุณควรระบุเป้าหมายการทดสอบดังกล่าวด้วยรูปแบบเป้าหมายที่ชัดเจนในบรรทัดคำสั่งหากต้องการให้ Bazel บิลด์/ทดสอบ ในทางตรงกันข้าม bazel query จะไม่กรองข้อมูลดังกล่าวโดยอัตโนมัติ (เพราะจะเป็นการขัดต่อวัตถุประสงค์ของ bazel query)

กำลังดึงข้อมูลทรัพยากร Dependency ภายนอก

โดยค่าเริ่มต้น Bazel จะดาวน์โหลดทรัพยากร Dependency ภายนอกและ symlink ระหว่าง งานสร้าง อย่างไรก็ตาม นี่อาจเป็นสิ่งที่ไม่เป็นที่ต้องการ เนื่องจาก คุณอยากรู้ เมื่อมีการเพิ่มทรัพยากร Dependency ภายนอกใหม่ หรือเมื่อคุณต้องการ "ดึงข้อมูลล่วงหน้า" ทรัพยากร Dependency (เช่น ก่อนเดินทาง ซึ่งคุณจะออฟไลน์) หากคุณ ต้องการป้องกันไม่ให้มีการเพิ่มทรัพยากร Dependency ใหม่ระหว่างบิลด์ สามารถระบุแฟล็ก --fetch=false โปรดทราบว่า Flag นี้มีผลกับกฎของที่เก็บซึ่งไม่ได้ชี้ไปยังไดเรกทอรีในระบบไฟล์ในเครื่องเท่านั้น การเปลี่ยนแปลง เช่น local_repository new_local_repository และกฎที่เก็บ Android SDK และ NDK จะมีผลเสมอโดยไม่คำนึงถึงค่า --fetch

หากคุณไม่อนุญาตให้ดึงข้อมูลระหว่างบิลด์และ Bazel พบภายนอกใหม่ ทรัพยากร Dependency บิลด์ของคุณจะล้มเหลว

คุณสามารถดึงข้อมูล Dependency ด้วยตนเองได้โดยเรียกใช้ bazel fetch หากไม่อนุญาตให้ดึงข้อมูลระหว่างการสร้าง คุณจะต้องเรียกใช้ bazel fetch ดังนี้

  • ก่อนสร้างเป็นครั้งแรก
  • หลังจากเพิ่มทรัพยากร Dependency ภายนอกรายการใหม่แล้ว

เมื่อเรียกใช้แล้ว คุณไม่ควรเรียกใช้อีกครั้งจนกว่าไฟล์ WORKSPACE จะเปลี่ยนแปลง

fetch ใช้รายการเป้าหมายเพื่อดึงข้อมูลการพึ่งพา สำหรับ ตัวอย่างเช่น การดำเนินการนี้จะดึงทรัพยากร Dependency ที่จำเป็นในการสร้าง //foo:bar และ //bar:baz:

bazel fetch //foo:bar //bar:baz

หากต้องการดึงข้อมูล Dependency ภายนอกทั้งหมดสําหรับพื้นที่ทํางาน ให้เรียกใช้คำสั่งต่อไปนี้

bazel fetch //...

คุณไม่จำเป็นต้องเรียกใช้การดึงข้อมูลแบบ Bazel เลย หากมีเครื่องมือทั้งหมด โดยใช้ (จากไลบรารีไลบรารีไปจนถึง JDK) ภายใต้รูทของพื้นที่ทำงาน อย่างไรก็ตาม หากคุณใช้ทรัพยากรใดๆ นอกไดเรกทอรีพื้นที่ทำงาน Bazel จะเรียกใช้ bazel fetch โดยอัตโนมัติก่อนที่จะเรียกใช้ bazel build

แคชที่เก็บ

Bazel จะพยายามหลีกเลี่ยงการดึงข้อมูลไฟล์เดียวกันหลายครั้ง แม้ว่าจะต้องใช้ไฟล์เดียวกันในเวิร์กスペースต่างๆ หรือหากคําจํากัดความของที่เก็บข้อมูลภายนอกมีการเปลี่ยนแปลงแต่ยังคงต้องใช้ไฟล์เดียวกันในการดาวน์โหลด โดยดำเนินการดังนี้ bazel จะแคชไฟล์ทั้งหมดที่ดาวน์โหลดในแคชของที่เก็บ ซึ่งโดยค่าเริ่มต้นแล้ว ตั้งอยู่ที่ ~/.cache/bazel/_bazel_$USER/cache/repos/v1/ คุณเปลี่ยนตำแหน่งได้โดยใช้ตัวเลือก --repository_cache แคชจะแชร์กันระหว่างพื้นที่ทํางานทั้งหมดและ bazel เวอร์ชันที่ติดตั้ง ระบบจะดึงรายการจากแคชหาก Bazel รู้อย่างแน่นอนว่ามีสำเนาของไฟล์ที่ถูกต้อง กล่าวคือ คำขอดาวน์โหลดมีผลรวม SHA256 ของไฟล์ที่ระบุและไฟล์ที่มี อยู่ในแคช ดังนั้น การระบุแฮชสำหรับไฟล์ภายนอกแต่ละไฟล์จึงไม่ใช่แค่แนวคิดที่ดีจากมุมมองด้านความปลอดภัยเท่านั้น แต่ยังช่วยหลีกเลี่ยงการดาวน์โหลดที่ไม่จำเป็นด้วย

เมื่อมีการเรียกใช้แคชแต่ละครั้ง ระบบจะอัปเดตเวลาแก้ไขของไฟล์ในแคช ด้วยวิธีนี้ การใช้งานไฟล์ในไดเรกทอรีแคชครั้งล่าสุดจะสามารถ ได้ เช่น ล้างแคชด้วยตนเอง ระบบจะไม่ล้างแคชโดยอัตโนมัติ เนื่องจากอาจมีสำเนาของไฟล์ที่ต้นทางไม่มีแล้ว

ไดเรกทอรีไฟล์การเผยแพร่

ไดเรกทอรีการกระจายเป็นอีกกลไกหนึ่งของ Bazel เพื่อหลีกเลี่ยงที่ไม่จำเป็น ดาวน์โหลด Bazel จะค้นหาไดเรกทอรีการกระจายก่อนแคชของที่เก็บ ความแตกต่างหลักๆ คือไดเรกทอรีการเผยแพร่ต้องเตรียมด้วยตนเอง

เมื่อใช้ตัวเลือก --distdir=/path/to-directory คุณจะสามารถระบุไดเรกทอรีแบบอ่านอย่างเดียวเพิ่มเติมเพื่อค้นหาไฟล์แทนการดึงข้อมูลได้ ระบบจะนําไฟล์จากไดเรกทอรีดังกล่าวหากชื่อไฟล์เท่ากับชื่อฐานของ URL และนอกจากนี้ แฮชของไฟล์ก็เท่ากับแฮชที่ระบุในคําขอดาวน์โหลด โดยจะใช้ได้เฉพาะเมื่อ มีการระบุแฮชของไฟล์ในการประกาศ WORKSPACE

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

เรียกใช้ Bazel ในสภาพแวดล้อมที่มีการแยกเครือข่าย

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

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

ในการเตรียมไดเรกทอรีการกระจาย ให้ใช้เมธอด --distdir แจ้ง คุณจะต้องทําเช่นนี้ 1 ครั้งสําหรับไบนารี Bazel เวอร์ชันใหม่ทุกเวอร์ชัน เนื่องจากความเกี่ยวข้องโดยนัยอาจแตกต่างกันไปในแต่ละรุ่น

หากต้องการสร้างทรัพยากร Dependency เหล่านี้นอกสภาพแวดล้อม Airgapp ของคุณ ก่อนอื่นให้ ชำระเงินแผนผังแหล่งที่มาของ Bazel ในเวอร์ชันที่ถูกต้อง

git clone https://github.com/bazelbuild/bazel "$BAZEL_DIR"
cd "$BAZEL_DIR"
git checkout "$BAZEL_VERSION"

จากนั้นสร้าง tarball ที่มีทรัพยากร Dependency ของรันไทม์โดยนัยสำหรับสิ่งนั้น เวอร์ชัน Bazel ที่เฉพาะเจาะจง:

bazel build @additional_distfiles//:archives.tar

ส่งออก tarball นี้ไปยังไดเรกทอรีที่สามารถคัดลอกไปยัง Airgapp ของคุณ ของคุณ โปรดสังเกต Flag --strip-components เนื่องจาก --distdir อาจทำงานได้ไม่ดีนักกับระดับการซ้อนไดเรกทอรี

tar xvf bazel-bin/external/additional_distfiles/archives.tar \
  -C "$NEW_DIRECTORY" --strip-components=3

สุดท้าย เมื่อใช้ Bazel ในสภาพแวดล้อมที่มีการป้องกันอากาศ ให้ส่ง Flag --distdir ที่ชี้ไปยังไดเรกทอรี คุณสามารถเพิ่มเป็น.bazelrc รายการได้เพื่อความสะดวก

build --distdir=path/to/directory

การกำหนดค่าและการคอมไพล์แบบข้ามระบบ

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

บิลด์หนึ่งๆ อาจมีการกำหนดค่ามากกว่า 1 รายการ ลองใช้การคอมไพล์ข้าม ซึ่งคุณสร้าง//foo:binไฟล์ปฏิบัติการสำหรับสถาปัตยกรรม 64 บิต แต่เวิร์กสเตชันเป็นคอมพิวเตอร์ 32 บิต เห็นได้ชัดว่าบิลด์ กำหนดให้สร้าง //foo:bin โดยใช้เครื่องมือเชนที่สร้างได้ 64 บิต ไฟล์ปฏิบัติการ แต่ระบบบิลด์ยังต้องสร้างเครื่องมือต่างๆ ที่ใช้ในระหว่าง สร้างตนเอง เช่น เครื่องมือที่สร้างขึ้นจากแหล่งที่มา แล้วต่อมา เช่น การสร้างกฎเกณฑ์ (Genrule) และกฎเหล่านี้ต้องสร้างขึ้นเพื่อให้ทำงานบนเวิร์กสเตชันของคุณได้ ดังนั้น เราจะระบุการกำหนดค่าได้ 2 แบบ ได้แก่ การกำหนดค่าการดำเนินการ ซึ่งใช้ สำหรับเครื่องมือสร้างที่ทำงานระหว่างบิลด์ และการกำหนดค่าเป้าหมาย (หรือขอการกำหนดค่า แต่เราใช้คำว่า "การกำหนดค่าเป้าหมาย" บ่อยกว่า แต่คำนั้นมีหลายความหมายอยู่แล้ว) ซึ่งใช้สำหรับการสร้าง ไบนารีที่คุณขอในท้ายที่สุด

โดยทั่วไปแล้ว จะมีไลบรารีหลายรายการที่เป็นข้อกําหนดเบื้องต้นของทั้งเป้าหมายการสร้างที่ขอ (//foo:bin) และเครื่องมือ exec อย่างน้อย 1 รายการ เช่น ไลบรารีพื้นฐานบางรายการ ไลบรารีดังกล่าวต้องสร้างขึ้น 2 ครั้ง โดยครั้งหนึ่งสำหรับผู้บริหาร และอีกครั้งสำหรับการกำหนดค่าเป้าหมาย Bazel จะตรวจสอบว่ามีการสร้างตัวแปรทั้ง 2 รายการ และเก็บไฟล์ที่ดึงข้อมูลไว้แยกกันเพื่อหลีกเลี่ยงการรบกวน โดยปกติแล้วเป้าหมายดังกล่าวจะสร้างพร้อมกันได้เนื่องจากไม่เกี่ยวข้องกัน หากคุณเห็นข้อความความคืบหน้าที่ระบุว่ามีการสร้างเป้าหมายหนึ่งๆ 2 ครั้ง ข้อความนี้อาจเป็นคำอธิบาย

การกำหนดค่า exec มาจากการกำหนดค่าเป้าหมาย ดังนี้

  • ใช้ Crosstool (--crosstool_top) เวอร์ชันเดียวกับที่ระบุในการกําหนดค่าคําขอ เว้นแต่จะมีการระบุ --host_crosstool_top
  • ใช้ค่าของ --host_cpu สำหรับ --cpu (ค่าเริ่มต้น: k8)
  • ใช้ค่าของตัวเลือกเหล่านี้เหมือนกับที่ระบุในการกำหนดค่าคําขอ --compiler, --use_ijars และหากใช้ --host_crosstool_top ระบบจะใช้ค่าของ --host_cpu เพื่อค้นหา default_toolchain ใน Crosstool (ไม่สนใจ --compiler) สําหรับการกําหนดค่า exec
  • ใช้ค่าของ --host_javabase สําหรับ --javabase
  • ใช้ค่าของ --host_java_toolchain สําหรับ --java_toolchain
  • ใช้บิลด์ที่เพิ่มประสิทธิภาพสำหรับโค้ด C++ (-c opt)
  • ไม่สร้างข้อมูลการแก้ไขข้อบกพร่อง (--copt=-g0)
  • ตัดข้อมูลการแก้ไขข้อบกพร่องออกจากไฟล์ปฏิบัติการและไลบรารีที่แชร์ (--strip=always)
  • วางไฟล์ที่ดึงมาทั้งหมดในตำแหน่งพิเศษ ซึ่งแตกต่างจากไฟล์ที่ใช้โดย การกำหนดค่าคำขอที่เป็นไปได้
  • ระงับการสร้างไบนารีด้วยข้อมูลบิลด์ (ดูตัวเลือก --embed_*)
  • ค่าอื่นๆ ทั้งหมดจะยังเป็นค่าเริ่มต้น

มีเหตุผลหลายประการที่ควรเลือกผู้บริหารที่ไม่ซ้ำกัน จากการกำหนดค่าคำขอ สิ่งสำคัญที่สุด

ประการแรก การใช้ไบนารีที่ผ่านการลบข้อมูลและเพิ่มประสิทธิภาพแล้วจะช่วยประหยัดเวลาในการลิงก์และเรียกใช้เครื่องมือ พื้นที่ดิสก์ที่เครื่องมือใช้ และเวลา I/O ของเครือข่ายในบิลด์แบบกระจาย

ข้อ 2 การแยกการกำหนดค่า exec และคำขอในบิลด์ทั้งหมดออก เพื่อหลีกเลี่ยงการสร้างใหม่ซึ่งมีราคาแพงมาก ซึ่งจะเป็นเพราะการเปลี่ยนแปลงเล็กๆ น้อยๆ ส่งคำขอการกำหนดค่า (เช่น การเปลี่ยนตัวเลือกตัวลิงก์) ตามที่อธิบายไว้ ก่อนหน้านี้

แก้ไขการสร้างใหม่แบบเพิ่มทีละส่วน

เป้าหมายหลักอย่างหนึ่งของโครงการ Bazel คือการดูแลส่วนเพิ่มที่ถูกต้อง สร้างใหม่ เครื่องมือสร้างก่อนหน้านี้ โดยเฉพาะเครื่องมือที่ทำงานตามแบรนด์ สมมติฐานที่ไม่สมเหตุสมผลในการใช้งานบิลด์ที่เพิ่มขึ้น

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

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

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

Bazel หลีกเลี่ยงสมมติฐานเหล่านี้และเรื่องอื่นๆ ด้วย Bazel จะดูแลฐานข้อมูลของงานทั้งหมดที่ทำก่อนหน้านี้ และจะข้ามขั้นตอนการสร้างเฉพาะในกรณีที่พบว่าชุดไฟล์อินพุต (และการประทับเวลา) ของขั้นตอนการสร้างนั้น และคำสั่งคอมไพล์สำหรับขั้นตอนการสร้างนั้นตรงกับรายการในฐานข้อมูลทุกประการ และชุดไฟล์เอาต์พุต (และการประทับเวลา) ของรายการฐานข้อมูลตรงกับการประทับเวลาของไฟล์ในดิสก์ทุกประการ การเปลี่ยนแปลงใดๆ ในไฟล์อินพุตหรือเอาต์พุต หรือกับคำสั่งนั้น จะทำให้เกิดการดำเนินการขั้นตอนบิลด์อีกครั้ง

ประโยชน์สำหรับผู้ใช้ของบิลด์ที่เพิ่มขึ้นที่ถูกต้องคือ การเสียเวลาน้อยลงเนื่องจาก ความสับสน (นอกจากนี้ ยังใช้เวลาน้อยลงในการรอการสร้างใหม่ที่เกิดจากการใช้ make clean ไม่ว่าจะจําเป็นหรือต้องมีการเตรียมการ)

สร้างความสอดคล้องและบิลด์ที่เพิ่มขึ้น

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

ยังมีความไม่สอดคล้องกันอีกประเภทหนึ่งที่ร้ายแรง นั่นคือเวอร์ชันเสถียร ความไม่สอดคล้องกัน หากบิลด์มีสภาวะที่ไม่สอดคล้องกันแบบคงที่ ระบบจะทำซ้ำ การเรียกใช้เครื่องมือสร้างสำเร็จไม่กู้คืนความสอดคล้อง: บิลด์ "ค้าง" และเอาต์พุตยังคงไม่ถูกต้อง สถานะที่คงที่แต่ไม่สอดคล้องกันเป็นตัวแปรหลักที่ทำให้ผู้ใช้ Make (และเครื่องมือสร้างอื่นๆ) พิมพ์ make clean และพบว่าเครื่องมือสร้างล้มเหลวในลักษณะนี้ (และทำการกู้คืนหลังจากนั้น จาก URL) อาจใช้เวลานานและน่าหงุดหงิดอย่างมาก

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

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

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

หากตรวจพบสถานะที่ไม่สอดคล้องกันและเสถียรของ Bazel โปรดรายงานข้อบกพร่อง

การดำเนินการที่แซนด์บ็อกซ์

Bazel ใช้แซนด์บ็อกซ์เพื่อรับประกันว่าการดำเนินการจะทำงานอย่างถูกต้องและปลอดภัย Bazel เรียกใช้spawns (พูดง่ายๆ คือการดำเนินการ) ในแซนด์บ็อกซ์ที่ ประกอบด้วยชุดไฟล์น้อยที่สุดที่เครื่องมือต้องใช้ในการทำงาน ปัจจุบัน Sandboxing ใช้งานได้ใน Linux 3.12 ขึ้นไปที่เปิดใช้ตัวเลือก CONFIG_USER_NS และใน macOS 10.11 ขึ้นไป

Bazel จะพิมพ์คำเตือนหากระบบไม่รองรับแซนด์บ็อกซ์ เพื่อแจ้งเตือน ข้อเท็จจริงที่ว่างานสร้างไม่รับประกันว่าสูญเปล่าไม่ได้และอาจส่งผลกระทบต่อ ระบบโฮสต์ในรูปแบบที่ไม่รู้จัก หากต้องการปิดคำเตือนนี้ คุณสามารถส่งผ่าน --ignore_unsupported_sandboxing แจ้งไปที่ Bazel

ในบางแพลตฟอร์ม เช่น Google Kubernetes เครื่องมือโหนดคลัสเตอร์หรือ Debian เนมสเปซของผู้ใช้จะถูกปิดใช้งานโดยค่าเริ่มต้นเนื่องจากความปลอดภัย ของ Google ตรวจสอบได้โดยดูที่ไฟล์ /proc/sys/kernel/unprivileged_userns_clone: หากมีไฟล์ดังกล่าวและมี 0 อยู่ แสดงว่าเปิดใช้งานเนมสเปซของผู้ใช้ได้ด้วย sudo sysctl kernel.unprivileged_userns_clone=1

ในบางกรณี แซนด์บ็อกซ์ Bazel ไม่สามารถดำเนินการตามกฎได้เนื่องจากระบบ การตั้งค่า ลักษณะปัญหาโดยทั่วไปคือความล้มเหลวที่แสดงข้อความคล้ายกับ namespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory ในกรณีนี้ ให้ลองปิดใช้งานแซนด์บ็อกซ์สำหรับ Genrule ด้วย --strategy=Genrule=standalone และสำหรับกฎอื่นๆ ที่มี --spawn_strategy=standalone และโปรดรายงานข้อบกพร่องใน เครื่องมือติดตามปัญหาและระบุว่าคุณกำลังใช้งาน Linux ใดอยู่เพื่อให้เรา ตรวจสอบและทำการแก้ไขในรุ่นต่อๆ ไป

ขั้นของบิลด์

ใน Bazel การก่อสร้างจะเกิดขึ้นใน 3 ระยะที่แตกต่างกัน ได้แก่ ในฐานะผู้ใช้ การทำความเข้าใจ ซึ่งจะให้ข้อมูลเชิงลึกเกี่ยวกับตัวเลือกที่ควบคุมบิลด์ (ดูด้านล่าง)

ระยะการโหลด

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

สำหรับบิลด์แรกหลังจากเริ่มเซิร์ฟเวอร์ Bazel ระยะการโหลดมักจะใช้เวลาหลายวินาทีเนื่องจากมีการโหลดไฟล์ BUILD จำนวนมากจากระบบไฟล์ ในบิวด์ต่อๆ ไป โดยเฉพาะหากไม่มีการเปลี่ยนแปลงไฟล์ BUILD การโหลดจะเกิดขึ้นอย่างรวดเร็ว

ข้อผิดพลาดที่รายงานในระยะนี้ ได้แก่ ไม่พบแพ็กเกจ ไม่พบเป้าหมาย ข้อผิดพลาดด้านภาษาและไวยากรณ์ในไฟล์ BUILD และข้อผิดพลาดการประเมิน

ช่วงการวิเคราะห์

ขั้นที่ 2 การวิเคราะห์จะเกี่ยวข้องกับการวิเคราะห์เชิงอรรถศาสตร์และการตรวจสอบความถูกต้องของ กฎบิลด์แต่ละรายการ การสร้างกราฟทรัพยากร Dependency ของบิลด์ และ การกำหนดสิ่งที่ต้องทำในแต่ละขั้นตอนของการสร้าง

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

ข้อผิดพลาดที่รายงานในระยะนี้ ได้แก่ Dependency ที่ไม่เหมาะสม อินพุตที่ไม่ถูกต้องของกฎ และข้อความแสดงข้อผิดพลาดเฉพาะกฎทั้งหมด

ระยะการโหลดและการวิเคราะห์จะรวดเร็วเนื่องจาก Bazel หลีกเลี่ยง I/O ของไฟล์ที่ไม่จำเป็นในระยะนี้ โดยจะอ่านเฉพาะไฟล์ BUILD เพื่อกำหนดงานที่จะทำ การดำเนินการนี้เป็นไปตามการออกแบบและทำให้ Bazel เป็นรากฐานที่ดีสำหรับเครื่องมือวิเคราะห์ เช่น คำสั่ง query ของ Bazel ซึ่งติดตั้งใช้งานในเฟสการโหลด

ระยะการดำเนินการ

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