หน้านี้มุ่งเน้นที่การเขียนกฎที่เข้ากันได้กับ 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 เนื่องจากมักใช้ไม่ได้กับแพลตฟอร์มอื่นๆ
วิธีแก้ไข:
ทำให้เส้นทางสั้น
หลีกเลี่ยงชื่อไดเรกทอรีที่ยาว โครงสร้างไดเรกทอรีที่ฝังลึก ชื่อไฟล์ที่ยาว ชื่อเวิร์กスペースที่ยาว ชื่อเป้าหมายที่ยาว
ทั้งหมดนี้อาจกลายเป็นคอมโพเนนต์เส้นทางของไฟล์อินพุตของการดำเนินการ และอาจใช้ความยาวเส้นทางจนหมดขีดจำกัด
ใช้รูทเอาต์พุตสั้นๆ
ใช้ Flag
--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 เป็นลิงก์สัญลักษณ์ของไดเรกทอรี
แทนที่
/
ด้วย "" ในเส้นทางในการดำเนินการ / 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
) ส่วนระบบที่คล้าย Unix ใช้ LF (\n
)โปรดระมัดระวังเรื่องนี้เมื่อเปรียบเทียบไฟล์ข้อความ โปรดคำนึงถึงการตั้งค่า Git โดยเฉพาะการสิ้นสุดบรรทัดเมื่อเช็คเอาต์หรือคอมมิต (ดูการตั้งค่า
core.autocrlf
ของ Git)
วิธีแก้ไข:
ใช้กฎที่เขียนขึ้นเพื่อวัตถุประสงค์โดยเฉพาะซึ่งไม่มี Bash
native.genrule()
เป็นเครื่องมือสำหรับห่อคำสั่ง Bash และมักใช้เพื่อแก้ปัญหาง่ายๆ เช่น การคัดลอกไฟล์หรือเขียนไฟล์ข้อความ คุณไม่จำเป็นต้องใช้ Bash (และไม่ต้องคิดค้นสิ่งใหม่) ให้ดูว่า bazel-skylib มีกฎที่สร้างขึ้นเพื่อวัตถุประสงค์ของคุณหรือไม่ ไม่มีรายการใดที่ต้องใช้ Bash เมื่อสร้าง/ทดสอบใน Windowsตัวอย่างกฎในการสร้าง
copy_file()
(source, documentation): คัดลอกไฟล์ไปยังตำแหน่งอื่น โดยเลือกทำให้ไฟล์เป็นแบบเรียกใช้ได้write_file()
(source, documentation): เขียนไฟล์ข้อความที่มีการตัดบรรทัดที่ต้องการ (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
ที่ว่างเปล่าจะเรียกใช้ไม่ได้ หากต้องการสคริปต์ที่ว่างเปล่า ให้เขียนช่องว่างหนึ่งบรรทัดใช้ 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:
โดยหลักการแล้ว ให้ลองปิดแฮนเดิลโดยเร็วที่สุด