หน้านี้มุ่งเน้นที่การเขียนกฎที่ใช้ได้กับ 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()(source, documentation): คัดลอกไฟล์ไปยังที่อื่น และเลือกทำให้ไฟล์นั้นเรียกใช้งานได้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): เรียกใช้ไบนารี (หรือ*_binaryrule) ด้วยอินพุตที่ระบุและเอาต์พุตที่คาดไว้เป็นการดำเนินการบิลด์ (นี่คือ Wrapper ของกฎบิลด์สำหรับctx.actions.run)native_binary()(source, documentation): wraps a native binary in a*_binaryrule, which you canbazel runor use inrun_binary()'stoolattribute ornative.genrule()'stoolsattribute
ตัวอย่างกฎการทดสอบ
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:ในทางทฤษฎี ให้พยายาม ปิดแฮนเดิลโดยเร็วที่สุด