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

วันที่ รายงานปัญหา ดูแหล่งที่มา ตอนกลางคืน · 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 ตามรูปแบบบัญญัติ
  • clean: นำไฟล์เอาต์พุตออกและเลือกหยุดเซิร์ฟเวอร์หรือไม่ก็ได้
  • cquery: ดำเนินการค้นหากราฟทรัพยากร Dependency สำหรับหลังการวิเคราะห์
  • dump: ถ่ายโอนสถานะภายในของกระบวนการของเซิร์ฟเวอร์ Bazel
  • help: ความช่วยเหลือเกี่ยวกับการพิมพ์สำหรับคำสั่งหรือดัชนี
  • info: แสดงข้อมูลรันไทม์เกี่ยวกับเซิร์ฟเวอร์ bazel
  • fetch: ดึงข้อมูลทรัพยากร Dependency ภายนอกทั้งหมดของเป้าหมาย
  • 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: แสดงรายการคีย์ที่คำสั่งข้อมูลใช้

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

การสร้างเป้าหมายเดียว

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

ในขั้นตอนการดำเนินการของบิลด์ Bazel จะพิมพ์ข้อความความคืบหน้า ความคืบหน้า ข้อความจะมีขั้นตอนบิลด์ปัจจุบัน (เช่น คอมไพเลอร์หรือ Linker) เนื่องจาก และจำนวนที่เสร็จสมบูรณ์จากจำนวนการดำเนินการของบิลด์ทั้งหมด ตามที่ จำนวนการทำงานทั้งหมดมักจะเพิ่มขึ้นเมื่อ 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" หรือ ทรัพยากร Dependency เดิม Bazel จะทำการทำงานบางอย่างอีกครั้ง หรือดำเนินการ บิลด์ที่เพิ่มขึ้น

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

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

แต่จะใช้ป้ายกำกับเพื่อระบุแต่ละรายการ เช่น สำหรับการประกาศทรัพยากร Dependency ในไฟล์ 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

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

นอกจากนี้ 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" (พารามิเตอร์ ต้องมีอาร์กิวเมนต์ -- เพื่อป้องกันอาร์กิวเมนต์ลำดับต่อมาที่เริ่มต้นด้วย - จากการตีความเป็นตัวเลือกเพิ่มเติม)

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

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

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

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

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

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

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

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

fetch จะใช้รายการเป้าหมายเพื่อดึงข้อมูลทรัพยากร Dependency สำหรับ ตัวอย่างเช่น การดำเนินการนี้จะดึงทรัพยากร 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 มีขนาดเล็ก บนเครือข่ายขณะเรียกใช้เป็นครั้งแรก ทรัพยากร Dependency โดยนัยเหล่านี้ มี Toolchains และกฎที่อาจไม่จำเป็นสำหรับทุกคน สำหรับ เช่น เครื่องมือ Android จะเลิกรวมกลุ่มและดึงข้อมูลเฉพาะเมื่อสร้าง Android โปรเจ็กต์

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

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

หากต้องการสร้างทรัพยากร 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 ของคุณ ของคุณ จดบันทึก --strip-components ไว้ เนื่องจากใช้ --distdir ได้ ค่อนข้างซับซ้อนกับระดับการซ้อนไดเรกทอรี:

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

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

build --distdir=path/to/directory

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

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

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

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

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

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

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

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

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

แก้ไขการสร้างใหม่ที่เพิ่มขึ้นเรื่อยๆ

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

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

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

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

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

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

สร้างความสอดคล้องและค่อยๆ เพิ่มขึ้น

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

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

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

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

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

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

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

Bazel ใช้แซนด์บ็อกซ์เพื่อรับประกันว่า การกระทำต่างๆ จะทำงานได้อย่างเต็มประสิทธิภาพ อย่างถูกต้อง Bazel เรียกใช้Spawn (พูดแบบหลวมๆ ว่าการดำเนินการต่างๆ) ในแซนด์บ็อกซ์ที่ ประกอบด้วยชุดไฟล์น้อยที่สุดที่เครื่องมือต้องใช้ในการทำงาน ปัจจุบัน แซนด์บ็อกซ์ใช้งานได้ใน 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 ระยะที่แตกต่างกัน ได้แก่ ในฐานะผู้ใช้ การทำความเข้าใจ ซึ่งจะให้ข้อมูลเชิงลึกเกี่ยวกับตัวเลือกที่ควบคุมบิลด์ (ดูด้านล่าง)

ระยะการโหลด

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

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

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

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

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

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

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

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

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

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