หน้านี้มุ่งเน้นที่การเขียนกฎที่เข้ากันได้กับ Windows, ปัญหาที่พบบ่อยเกี่ยวกับการเขียนกฎแบบพกพา และวิธีแก้ปัญหาบางอย่าง
เส้นทาง
ปัญหา:
ความยาวสูงสุด: ความยาวเส้นทางสูงสุดคือ 259 อักขระ
แม้ว่า Windows จะรองรับเส้นทางที่ยาวกว่า (ไม่เกิน 32,767 อักขระ) แต่ก็มีโปรแกรมจำนวนมากที่สร้างขึ้นด้วยขีดจำกัดต่ำสุด
โปรดคำนึงถึงเรื่องนี้เกี่ยวกับโปรแกรมที่คุณเรียกใช้ด้วยการดำเนินการดังกล่าว
ไดเรกทอรีที่ใช้งานอยู่: จำกัดอักขระไว้ที่ 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
ใช้ทางแยก
Junction หมายถึงลิงก์สัญลักษณ์ของไดเรกทอรี[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
(สคริปต์แบตช์)โปรดทราบว่าสคริปต์เชลล์ (
.sh
) ไม่สามารถเรียกใช้ได้ใน Windows คุณจึงระบุสคริปต์เชลล์เป็นexecutable
ของctx.actions.run
ไม่ได้ นอกจากนี้ ไฟล์จะไม่มีสิทธิ์+x
ด้วย คุณจึงไม่สามารถเรียกใช้ไฟล์ใดก็ได้เหมือนใน Linuxคำสั่ง Bash: โปรดหลีกเลี่ยงการเรียกใช้คำสั่ง Bash โดยตรงในการดำเนินการเพื่อให้ถ่ายโอนได้
Bash มีให้ใช้อย่างแพร่หลายในระบบที่คล้ายกับ Unix แต่มักจะใช้งานไม่ได้ใน Windows Bazel เองก็พึ่งพา Bash (MSYS2) น้อยลงเรื่อยๆ ดังนั้นในอนาคต ผู้ใช้ในอนาคตจึงมีแนวโน้มที่จะติดตั้ง MSYS2 พร้อมกับ Bazel น้อยลง หลีกเลี่ยงการเรียกใช้คําสั่ง Bash ในการดำเนินการเพื่อให้ใช้กฎใน Windows ได้ง่ายขึ้น
ส่วนท้ายบรรทัด: 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()
(source, documentation): เรียกใช้ไบนารี (หรือกฎ*_binary
) ด้วยอินพุตที่ระบุและเอาต์พุตที่คาดไว้เป็นการดำเนินการบิลด์ (นี่คือตัวแฝงกฎการสร้างสำหรับctx.actions.run
)native_binary()
(แหล่งที่มา, เอกสารประกอบ): รวมไบนารีแบบเนทีฟไว้ในกฎ*_binary
ซึ่งคุณสามารถbazel run
หรือใช้ในแอตทริบิวต์tool
ของrun_binary()
หรือแอตทริบิวต์tools
ของnative.genrule()
ตัวอย่างกฎการทดสอบ
diff_test()
(source, documentation): ทดสอบที่เปรียบเทียบเนื้อหาของ 2 ไฟล์native_test()
(source, documentation): รวมไบนารีแบบเนทีฟไว้ในกฎ*_test
ซึ่งคุณbazel test
ได้
ใน Windows ลองใช้
.bat
กับสคริปต์สำหรับเรื่องเล็กๆ น้อยๆคุณแก้ปัญหางานเล็กๆ น้อยๆ ด้วยสคริปต์
.bat
แทนสคริปต์.sh
ได้เช่น หากต้องการสคริปต์ที่ไม่ทำอะไรเลย หรือพิมพ์ข้อความ หรือออกมาพร้อมกับรหัสข้อผิดพลาดที่แก้ไขแล้ว ไฟล์
.bat
ธรรมดาก็เพียงพอแล้ว หากกฎแสดงผลผู้ให้บริการDefaultInfo()
ช่อง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:
โดยหลักการแล้ว ให้ลองปิดแฮนเดิลโดยเร็วที่สุด