หน้านี้จะเน้นการเขียนกฎที่ใช้กับ 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
ใช้ทางแยก
ทางแยกคือลิงก์สัญลักษณ์ของไดเรกทอรี[1] ทางแยกที่สร้างง่ายและสามารถชี้ไปยังไดเรกทอรี (ในคอมพิวเตอร์เครื่องเดียวกัน) ที่มีเส้นทางยาวได้ หากการทำงานของบิลด์สร้าง Junction ที่มีเส้นทางสั้นๆ แต่เป้าหมายยาว เครื่องมือที่มีขีดจำกัดเส้นทางสั้นจะสามารถเข้าถึง ไฟล์ในไดเรกทอรีของ Junction ได้
คุณสามารถสร้างทางแยกใน
.bat
ไฟล์หรือใน cmd.exe ได้ดังต่อไปนี้mklink /J c:\path\to\junction c:\path\to\very\long\target\path
[1]: พูดให้ตรงมากๆ Junction เป็นลิงก์สัญลักษณ์ แต่เพื่อ ดำเนินการสร้าง คุณอาจถือว่า Junction เป็น Symlink ของไดเรกทอรี
แทนที่
/
ด้วย "" ในเส้นทางในการดําเนินการ / envvarsเมื่อสร้างบรรทัดคำสั่งหรือตัวแปรสภาพแวดล้อมสำหรับการดำเนินการ ให้สร้างเส้นทางสไตล์ 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
) ระบบคล้ายยูนิกซ์ใช้ LF (\n
)โปรดระวังเรื่องนี้เมื่อเปรียบเทียบไฟล์ข้อความ โปรดคำนึงถึงการตั้งค่า Git โดยเฉพาะการสิ้นสุดบรรทัด เมื่อชำระเงินหรือดำเนินการ (ดูการตั้งค่า
core.autocrlf
ของ Git)
วิธีแก้ไข:
ใช้กฎที่สร้างขึ้นแบบไม่ใช้ Bash
native.genrule()
คือ Wrapper สำหรับคำสั่ง Bash และมักใช้ในการแก้ปัญหาง่ายๆ เช่น การคัดลอกไฟล์หรือการเขียนไฟล์ข้อความ คุณหลีกเลี่ยงการใช้ Bash (และพลิกโฉมวงล้อ) ได้ โดยดูว่า Bazel-skylib มีกฎที่สร้างขึ้นมาสำหรับความต้องการของคุณโดยเฉพาะหรือไม่ ซึ่งทั้ง 2 อย่างนี้ขึ้นอยู่กับ 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
สำหรับสิ่งเล็กๆ น้อยๆแทนที่จะใช้สคริปต์
.sh
คุณสามารถแก้ปัญหาเล็กๆ น้อยๆ ได้ด้วยสคริปต์.bat
รายการเช่น หากคุณต้องการสคริปต์ที่ไม่ต้องดำเนินการใดๆ หรือพิมพ์ข้อความ หรือออกโดยใช้รหัสข้อผิดพลาดที่แก้ไขแล้ว แค่ใช้ไฟล์
.bat
ธรรมดาก็เพียงพอแล้ว หากกฎแสดงผลผู้ให้บริการDefaultInfo()
ช่องexecutable
อาจหมายถึงไฟล์.bat
นั้นใน Windowsและเนื่องจากนามสกุลไฟล์ไม่ใช่เรื่องสำคัญใน macOS และ Linux คุณจึงใช้
.bat
เป็นส่วนขยายได้เสมอ แม้แต่สำหรับสคริปต์ Shell ก็ตามโปรดทราบว่าคุณจะดำเนินการไฟล์
.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:
โดยหลักการแล้ว ให้ลอง ปิดแฮนเดิลโดยเร็วที่สุด