กฎการเขียนใน Windows

รายงานปัญหา ดูแหล่งที่มา Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

หน้านี้มุ่งเน้นที่การเขียนกฎที่ใช้ได้กับ 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 โดยตรงใน Actions

    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, or windows), optionally making it executable (if it's a script)

    • run_binary() (source, documentation): เรียกใช้ไบนารี (หรือ*_binary rule) ด้วยอินพุตที่ระบุและเอาต์พุตที่คาดไว้เป็นการดำเนินการบิลด์ (นี่คือ Wrapper ของกฎบิลด์สำหรับ ctx.actions.run)

    • native_binary() (source, documentation): wraps a native binary in a *_binary rule, which you can bazel run or use in run_binary()'s tool attribute or native.genrule()'s tools attribute

    ตัวอย่างกฎการทดสอบ

    • diff_test() (source, documentation): ทดสอบที่เปรียบเทียบเนื้อหาของไฟล์ 2 ไฟล์

    • native_test() (source, documentation): wraps a native binary in a *_test rule, which you can bazel 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: ในทางทฤษฎี ให้พยายาม ปิดแฮนเดิลโดยเร็วที่สุด