หน้านี้มุ่งเน้นที่การเขียนกฎที่ใช้กับ 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
ไม่มีรากระบบไฟล์เดียวโปรดระมัดระวังเรื่องนี้หากกฎตรวจสอบว่าเส้นทางสมบูรณ์หรือไม่ ควรหลีกเลี่ยงเส้นทางสัมบูรณ์ เนื่องจากมักจะเป็นแบบเคลื่อนย้ายไม่ได้
วิธีแก้ไข:
ทำให้เส้นทางสั้น
หลีกเลี่ยงการใช้ชื่อไดเรกทอรีแบบยาว โครงสร้างไดเรกทอรีแบบซ้อนหลายระดับ ชื่อไฟล์ยาว ชื่อพื้นที่ทำงานแบบยาว และชื่อเป้าหมายแบบยาว
ทั้งหมดนี้อาจกลายเป็นคอมโพเนนต์เส้นทางของไฟล์อินพุตของการดำเนินการ และอาจทำให้ความยาวเส้นทางเกินขีดจำกัด
ใช้รูทเอาต์พุตสั้นๆ
ใช้แฟล็ก
--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] ซึ่งเป็นลิงก์สัญลักษณ์ของไดเรกทอรี ตัวคั่นนั้นสร้างง่ายและชี้ไปยังไดเรกทอรี (ในคอมพิวเตอร์เครื่องเดียวกัน) ที่มีเส้นทางยาวได้ หากการดำเนินการของบิลด์สร้างทางแยกที่มีเส้นทางสั้น แต่เป้าหมายยาว เครื่องมือที่มีขีดจำกัดเส้นทางสั้นจะสามารถเข้าถึงไฟล์ในไดเรกทอรีของทางแยกได้
ในไฟล์
.bat
หรือใน cmd.exe คุณสามารถสร้างทางแยกได้ดังนี้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")
จะให้ผลลัพธ์เดียวกัน (กรณีนี้จะใช้กับภาษาอื่นๆ ด้วยเช่นกัน)ความแน่นอน: การดำเนินการควรใช้ตัวแปรสภาพแวดล้อมที่กำหนดเองให้น้อยที่สุดเท่าที่จะเป็นไปได้
ตัวแปรสภาพแวดล้อมเป็นส่วนหนึ่งของคีย์แคชของการดำเนินการ หากการดำเนินการใช้ตัวแปรสภาพแวดล้อมที่เปลี่ยนแปลงบ่อยหรือกำหนดให้กับผู้ใช้ กฎจะทำให้แคชได้น้อยลง
วิธีแก้ไข:
ใช้ชื่อตัวแปรสภาพแวดล้อมตัวพิมพ์ใหญ่เท่านั้น
วิธีนี้ใช้ได้ใน 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
(สคริปต์แบบกลุ่ม)โปรดทราบว่าสคริปต์ Shell (
.sh
) เรียกใช้ใน Windows ไม่ได้ คุณจึงระบุให้เป็นexecutable
ของctx.actions.run
ไม่ได้ นอกจากนี้ ไฟล์ก็ไม่มีสิทธิ์+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()
(แหล่งที่มา เอกสารประกอบ): เขียนไฟล์ข้อความที่มีนามสกุลบรรทัดตามที่ต้องการ (auto
,unix
หรือwindows
) หรือจะเลือกทำให้เป็นไฟล์ปฏิบัติการก็ได้ (หากเป็นสคริปต์)run_binary()
(แหล่งที่มา เอกสารประกอบ): เรียกใช้ไบนารี (หรือกฎ*_binary
) ที่มีอินพุตที่กำหนดและเอาต์พุตที่คาดหวังเป็นการดำเนินการของบิลด์ (นี่คือ Wrapper ของกฎบิลด์สำหรับctx.actions.run
)native_binary()
(แหล่งที่มา, เอกสารประกอบ): รวมไบนารีดั้งเดิมในกฎ*_binary
ซึ่งคุณสามารถbazel run
หรือใช้ในแอตทริบิวต์tool
ของrun_binary()
หรือแอตทริบิวต์tools
ของnative.genrule()
ตัวอย่างกฎการทดสอบ
diff_test()
(แหล่งที่มา, เอกสารประกอบ): ทดสอบที่เปรียบเทียบเนื้อหาของไฟล์ 2 ไฟล์native_test()
(แหล่งที่มา เอกสารประกอบ): รวมไบนารีดั้งเดิมในกฎ*_test
ซึ่งคุณสามารถbazel test
ใน Windows ลองใช้
.bat
กับสคริปต์สำหรับเรื่องเล็กๆ น้อยๆคุณแก้ปัญหางานเล็กๆ น้อยๆ ด้วยสคริปต์
.bat
แทนสคริปต์.sh
ได้เช่น หากคุณต้องการสคริปต์ที่ไม่มีอะไรหรือพิมพ์ข้อความ หรือออกไปพร้อมรหัสข้อผิดพลาดที่แก้ไขแล้ว การใช้ไฟล์
.bat
ง่ายๆ ก็เพียงพอ หากกฎแสดงผลผู้ให้บริการDefaultInfo()
ช่องexecutable
อาจอ้างถึงไฟล์.bat
นั้นใน Windowsและเนื่องจากนามสกุลไฟล์ไม่ใช่ส่วนสำคัญใน macOS และ Linux คุณจึงใช้
.bat
เป็นส่วนขยายได้เสมอ แม้จะเป็นสคริปต์ Shell ก็ตามโปรดทราบว่าไฟล์
.bat
ที่ว่างเปล่าจะเรียกใช้ไม่ได้ หากคุณต้องการสคริปต์ที่ว่างเปล่า ให้เขียนช่องว่างหนึ่งบรรทัดใช้ 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:
โดยหลักการแล้ว ให้ลองปิดแฮนเดิลโดยเร็วที่สุด