หน้านี้มุ่งเน้นที่การเขียนกฎที่ใช้ได้กับ Windows ปัญหาที่พบบ่อยในการ เขียนกฎแบบพกพา และโซลูชันบางอย่าง
เส้นทาง
ปัญหา
ขีดจำกัดความยาว: ความยาวเส้นทางสูงสุดคือ 259 อักขระ
แม้ว่า Windows จะรองรับเส้นทางที่ยาวกว่า (สูงสุด 32767 อักขระ) แต่โปรแกรมจำนวนมากสร้างขึ้นโดยมีขีดจำกัดที่ต่ำกว่า
โปรดทราบเกี่ยวกับโปรแกรมที่คุณเรียกใช้ในการดำเนินการ
ไดเรกทอรีการทำงาน: มีอักขระได้ไม่เกิน 259 ตัว
กระบวนการไม่สามารถ
cdลงในไดเรกทอรีที่มีความยาวเกิน 259 อักขระการคำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่: เส้นทางใน Windows ไม่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ ส่วนเส้นทางใน Unix คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่
โปรดทราบถึงข้อจำกัดนี้เมื่อสร้างบรรทัดคำสั่งสำหรับการดำเนินการ
ตัวคั่นเส้นทาง: คือแบ็กสแลช (
\`), not forward slash (/)Bazel จัดเก็บเส้นทางในรูปแบบ Unix โดยใช้ตัวคั่น
/แม้ว่าโปรแกรม Windows บางโปรแกรมจะรองรับเส้นทางรูปแบบ Unix แต่โปรแกรมอื่นๆ ไม่รองรับ คำสั่งในตัวบางคำสั่งใน cmd.exe รองรับ แต่บางคำสั่งไม่รองรับคุณควรใช้
\` separators on Windows: replace/withเสมอเมื่อสร้างบรรทัดคำสั่งและตัวแปรสภาพแวดล้อมสำหรับการดำเนินการเส้นทางแบบสัมบูรณ์: ไม่ขึ้นต้นด้วยเครื่องหมายทับ (
/)เส้นทางแบบสัมบูรณ์ใน Windows จะขึ้นต้นด้วยตัวอักษรของไดรฟ์ เช่น
C:\foo\bar.txtไม่มีรูทของระบบไฟล์เดียวโปรดทราบถึงข้อจำกัดนี้หากกฎของคุณตรวจสอบว่าเส้นทางเป็นเส้นทางแบบสัมบูรณ์หรือไม่ ควรหลีกเลี่ยงการใช้ Absolute Path เนื่องจากมักจะย้ายไม่ได้
วิธีแก้ไข:
เส้นทางควรสั้น
หลีกเลี่ยงชื่อไดเรกทอรีที่ยาว โครงสร้างไดเรกทอรีที่ซ้อนกันลึก ชื่อไฟล์ที่ยาว ชื่อเวิร์กสเปซที่ยาว และชื่อเป้าหมายที่ยาว
ซึ่งทั้งหมดนี้อาจกลายเป็นคอมโพเนนต์เส้นทางของไฟล์อินพุตของการดำเนินการ และอาจทำให้ความยาวเส้นทางเกินขีดจำกัด
ใช้รูทเอาต์พุตแบบสั้น
ใช้แฟล็ก
--output_user_root=<path>เพื่อระบุเส้นทางแบบย่อสำหรับเอาต์พุตของ Bazel ขอแนะนำให้มีไดรฟ์ (หรือไดรฟ์เสมือน) สำหรับเอาต์พุตของ Bazel โดยเฉพาะ (เช่น ไฟล์D:\`), and adding this line to your.bazelrc`)build --output_user_root=D:/หรือ
build --output_user_root=C:/_bzlใช้ทางแยก
พูดอย่างคร่าวๆ[1] จังก์ชันคือลิงก์สัญลักษณ์ของไดเรกทอรี สร้าง Junction ได้ง่ายๆ และสามารถชี้ไปยังไดเรกทอรี (ในคอมพิวเตอร์เครื่องเดียวกัน) ที่มีเส้นทางยาว หากการดำเนินการบิลด์สร้าง จังก์ชันที่มีเส้นทางสั้นแต่มีเป้าหมายยาว เครื่องมือที่มีขีดจำกัดเส้นทางสั้นจะเข้าถึง ไฟล์ในไดเรกทอรีที่เชื่อมต่อได้
ในไฟล์
.batหรือใน cmd.exe คุณสามารถสร้าง Junction ได้ดังนี้mklink /J c:\path\to\junction c:\path\to\very\long\target\path[1]: พูดอย่างเคร่งครัด Junction ไม่ใช่ลิงก์สัญลักษณ์ แต่เพื่อ ประโยชน์ของการดำเนินการบิลด์ คุณอาจถือว่า Junction เป็น Symlink ของไดเรกทอรี
แทนที่
/ด้วย `` ในเส้นทางในการดำเนินการ / ตัวแปรสภาพแวดล้อมเมื่อสร้างบรรทัดคำสั่งหรือตัวแปรสภาพแวดล้อมสำหรับการดำเนินการ ให้ใช้เส้นทางรูปแบบ Windows ตัวอย่าง
def as_path(p, is_windows): if is_windows: return p.replace("/", "\\") else: return p
ตัวแปรสภาพแวดล้อม
ปัญหา
การคำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่: ชื่อตัวแปรสภาพแวดล้อมของ Windows ไม่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่
เช่น ใน Java
System.getenv("SystemRoot")และSystem.getenv("SYSTEMROOT")จะให้ผลลัพธ์เดียวกัน (ซึ่งใช้กับภาษาอื่นๆ ด้วย)Hermeticity: การดำเนินการควรใช้ตัวแปรสภาพแวดล้อมที่กำหนดเองให้น้อยที่สุด
ตัวแปรสภาพแวดล้อมเป็นส่วนหนึ่งของคีย์แคชของการดำเนินการ หากการดำเนินการใช้ตัวแปรสภาพแวดล้อม ที่มีการเปลี่ยนแปลงบ่อยหรือเป็นตัวแปรที่กำหนดเองสำหรับผู้ใช้ จะทำให้กฎแคชน้อยลง
วิธีแก้ไข:
ใช้เฉพาะชื่อตัวแปรสภาพแวดล้อมที่เป็นตัวพิมพ์ใหญ่เท่านั้น
ซึ่งใช้ได้กับ Windows, macOS และ Linux
ลดสภาพแวดล้อมการดำเนินการ
เมื่อใช้
ctx.actions.runให้ตั้งค่าสภาพแวดล้อมเป็นctx.configuration.default_shell_envหาก การดำเนินการต้องการตัวแปรสภาพแวดล้อมเพิ่มเติม ให้ใส่ตัวแปรทั้งหมดในพจนานุกรมแล้วส่งไปยังการดำเนินการ ตัวอย่างload("@bazel_skylib//lib:dicts.bzl", "dicts") def _make_env(ctx, output_file, is_windows): out_path = output_file.path if is_windows: out_path = out_path.replace("/", "\\") return dicts.add(ctx.configuration.default_shell_env, {"MY_OUTPUT": out_path})
การดำเนินการ
ปัญหา
เอาต์พุตที่ปฏิบัติการได้: ไฟล์ที่ปฏิบัติการได้ทุกไฟล์ต้องมีส่วนขยายที่ปฏิบัติการได้
นามสกุลที่พบบ่อยที่สุดคือ
.exe(ไฟล์ไบนารี) และ.bat(สคริปต์ชุดคำสั่ง)โปรดทราบว่าสคริปต์เชลล์ (
.sh) จะเรียกใช้ใน Windows ไม่ได้ คุณจึงระบุเป็นctx.actions.runของexecutableไม่ได้ นอกจากนี้ยังไม่มีสิทธิ์+xที่ไฟล์จะมีได้ ดังนั้นคุณจึง เรียกใช้ไฟล์ใดก็ได้ไม่ได้เหมือนใน Linuxคำสั่ง Bash: เพื่อให้สามารถพกพาได้ ให้หลีกเลี่ยงการเรียกใช้คำสั่ง Bash ในการดำเนินการโดยตรง
Bash มีการใช้งานอย่างแพร่หลายในระบบที่คล้าย Unix แต่โดยทั่วไปจะใช้ไม่ได้ใน Windows Bazel เองก็พึ่งพา Bash (MSYS2) น้อยลงเรื่อยๆ ดังนั้นในอนาคตผู้ใช้จึงมีแนวโน้มที่จะติดตั้ง MSYS2 พร้อมกับ Bazel น้อยลง หากต้องการให้ใช้กฎใน Windows ได้ง่ายขึ้น ให้หลีกเลี่ยงการเรียกใช้คำสั่ง Bash ใน การดำเนินการ
การจบบรรทัด: Windows ใช้ CRLF (
\r\n) ส่วนระบบที่คล้าย Unix ใช้ LF (\n)โปรดทราบถึงข้อจำกัดนี้เมื่อเปรียบเทียบไฟล์ข้อความ โปรดคำนึงถึงการตั้งค่า Git โดยเฉพาะอย่างยิ่งการสิ้นสุดบรรทัดเมื่อชำระเงินหรือคอมมิต (ดู
core.autocrlfการตั้งค่าของ Git)
วิธีแก้ไข:
ใช้กฎที่สร้างขึ้นโดยเฉพาะซึ่งไม่มี Bash
native.genrule()เป็น Wrapper สำหรับคำสั่ง Bash และมักใช้เพื่อแก้ปัญหาเล็กๆ น้อยๆ เช่น การคัดลอกไฟล์หรือการเขียนไฟล์ข้อความ คุณหลีกเลี่ยงการใช้ Bash (และไม่ต้องคิดค้นสิ่งใหม่ๆ) ได้โดยดูว่า bazel-skylib มีกฎที่สร้างขึ้นเพื่อตอบสนองความต้องการของคุณหรือไม่ โดยไม่มีตัวใดขึ้นอยู่กับ Bash เมื่อสร้าง/ทดสอบใน Windowsตัวอย่างกฎการสร้าง
copy_file()(แหล่งที่มา, เอกสารประกอบ): คัดลอกไฟล์ไปยังที่อื่น และเลือกทำให้ไฟล์นั้นเรียกใช้งานได้write_file()(source, documentation): writes a text file, with the desired line endings (auto,unix, orwindows), optionally making it executable (if it's a script)run_binary()(source, documentation): runs a binary (or*_binaryrule) with given inputs and expected outputs as a build action (this is a build rule wrapper forctx.actions.run)native_binary()(แหล่งที่มา เอกสารประกอบ): ห่อหุ้มไบนารีเนทีฟในกฎ*_binaryซึ่งคุณสามารถbazel runหรือใช้ในแอตทริบิวต์toolของrun_binary()หรือแอตทริบิวต์toolsของnative.genrule()
ตัวอย่างกฎการทดสอบ
diff_test()(source, documentation): ทดสอบที่เปรียบเทียบเนื้อหาของไฟล์ 2 ไฟล์native_test()(source, documentation): wraps a native binary in a*_testrule, which you canbazel test
ใน Windows ให้พิจารณาใช้สคริปต์
.batสำหรับสิ่งเล็กๆ น้อยๆคุณสามารถใช้สคริปต์
.batเพื่อทำงานเล็กๆ น้อยๆ แทนการใช้สคริปต์.shได้เช่น หากคุณต้องการสคริปต์ที่ไม่ทำอะไรเลย หรือพิมพ์ข้อความ หรือออกด้วย รหัสข้อผิดพลาดที่แน่นอน ก็ใช้ไฟล์
.batง่ายๆ ก็พอ หากกฎแสดงผลDefaultInfo()provider ฟิลด์executableอาจอ้างอิงถึงไฟล์.batนั้นใน Windowsและเนื่องจากนามสกุลไฟล์ไม่มีผลใน macOS และ Linux คุณจึงใช้
.batเป็นนามสกุลได้เสมอ แม้แต่กับสคริปต์เชลล์โปรดทราบว่าระบบจะเรียกใช้ไฟล์
.batที่ว่างเปล่าไม่ได้ หากต้องการสคริปต์ที่ว่างเปล่า ให้เขียนช่องว่าง 1 ช่อง ในสคริปต์ใช้ Bash อย่างมีหลักการ
ในกฎการสร้างและการทดสอบ Starlark ให้ใช้
ctx.actions.run_shellเพื่อเรียกใช้สคริปต์ Bash และคำสั่ง Bash เป็นการดำเนินการในมาโคร Starlark ให้รวมสคริปต์และคำสั่ง Bash ไว้ใน
native.sh_binary()หรือnative.genrule()Bazel จะตรวจสอบว่า Bash พร้อมใช้งานหรือไม่ และเรียกใช้สคริปต์หรือคำสั่งผ่าน Bashในกฎของที่เก็บ Starlark ให้พยายามหลีกเลี่ยงการใช้ Bash โดยสิ้นเชิง ปัจจุบัน Bazel ยังไม่มีวิธีเรียกใช้คำสั่ง Bash ในกฎของที่เก็บในลักษณะที่เป็นไปตามหลักการ
กำลังลบไฟล์
ปัญหา
ลบไฟล์ขณะเปิดไม่ได้
ระบบจะลบไฟล์ที่เปิดไม่ได้ (โดยค่าเริ่มต้น) และการพยายามลบจะส่งผลให้เกิดข้อผิดพลาด "ปฏิเสธการเข้าถึง" หากลบไฟล์ไม่ได้ อาจเป็นเพราะกระบวนการที่กำลังทำงานยังคงเปิดไฟล์นั้นอยู่
ลบไดเรกทอรีการทำงานของกระบวนการที่กำลังทำงานไม่ได้
กระบวนการมีแฮนเดิลที่เปิดอยู่ไปยังไดเรกทอรีการทำงาน และลบไดเรกทอรีไม่ได้ จนกว่ากระบวนการจะสิ้นสุด
วิธีแก้ไข:
ในโค้ด ให้พยายามปิดไฟล์โดยเร็ว
ใน Java ให้ใช้
try-with-resourcesใน Python ให้ใช้with open(...) as f:โดยหลักการแล้ว ให้พยายาม ปิดแฮนเดิลโดยเร็วที่สุด