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

วันที่ รายงานปัญหา ดูแหล่งที่มา ตอนกลางคืน · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

หน้าเว็บนี้มุ่งเน้นที่การเขียนกฎที่ใช้ได้กับ 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] ซึ่งเป็นลิงก์สัญลักษณ์ของไดเรกทอรี ทางแยกสร้างได้ง่าย และสามารถชี้ไปยังไดเรกทอรี (ในคอมพิวเตอร์เครื่องเดียวกัน) ที่มีเส้นทางยาว หากการดำเนินการของบิลด์สร้าง ทางแยกที่มีเส้นทางสั้นแต่มีเป้าหมายยาว เครื่องมือที่มีขีดจำกัดเส้นทางสั้นจะสามารถเข้าถึงได้ ไฟล์ในไดเรกทอรีของทางแยก

    ในไฟล์ .bat หรือใน cmd.exe คุณสามารถสร้างทางแยกได้ดังนี้

    mklink /J c:\path\to\junction c:\path\to\very\long\target\path
    

    [1]: จะพูดจริงๆ นะ จุดแทนไม่ใช่ลิงก์สัญลักษณ์ แต่สำหรับ การทำงานของบิลด์ที่คุณอาจถือว่า Junction เป็นสัญลักษณ์ลิงก์ไดเรกทอรี

  • แทนที่ / ด้วย "" ในเส้นทางการทำงาน / สภาพแวดล้อม

    เมื่อคุณสร้างบรรทัดคำสั่งหรือตัวแปรสภาพแวดล้อมสำหรับการดำเนินการ ให้สร้างเส้นทาง แบบ 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 หาก action ต้องการตัวแปรสภาพแวดล้อมเพิ่มเติม ใส่ตัวแปรทั้งหมดในพจนานุกรมแล้วส่งผ่านไปยังการดำเนินการ ตัวอย่าง

    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 ตัวบาเซลเองก็ อาศัย Bash (MSYS2) น้อยลงเรื่อยๆ ในอนาคต ผู้ใช้ในอนาคตจึงมีแนวโน้มน้อยลงที่จะมี MSYS2 ที่ติดตั้งมาพร้อมกับ Bazel หากต้องการให้กฎใช้งานใน Windows ได้ง่ายขึ้น โปรดหลีกเลี่ยงการเรียกใช้คำสั่ง Bash ใน การดำเนินการ

  • ส่วนท้ายบรรทัด: Windows ใช้ CRLF (\r\n) ส่วนระบบที่คล้ายกับ Unix ใช้ LF (\n)

    โปรดระมัดระวังเรื่องนี้เมื่อเปรียบเทียบไฟล์ข้อความ คำนึงถึงการตั้งค่า Git ของคุณ โดยเฉพาะบรรทัด สิ้นสุดเมื่อชำระเงินหรือผูกมัด (ดูการตั้งค่า core.autocrlf ของ Git)

วิธีแก้ไข:

  • ใช้กฎที่อิงตามวัตถุประสงค์แบบไม่เป็น Bash

    native.genrule() คือ Wrapper สำหรับคำสั่ง Bash และมักใช้ในการแก้ปัญหาง่ายๆ เช่น คัดลอกไฟล์หรือเขียนไฟล์ข้อความ คุณสามารถหลีกเลี่ยงการพึ่งพา Bash (และคิดค้น Wheel): ดูว่า bazel-skylib มีกฎที่ออกแบบมาเพื่อความต้องการของคุณหรือไม่ ไม่มีข้อใดที่ขึ้นอยู่กับ Bash เมื่อสร้าง/ทดสอบบน Windows

    ตัวอย่างกฎในการสร้าง

    • copy_file() (แหล่งที่มา เอกสารประกอบ): คัดลอกไฟล์ไปที่อื่น และเลือกได้ว่าจะให้เป็นไฟล์ปฏิบัติการหรือไม่

    • write_file() (แหล่งที่มา เอกสารประกอบ): เขียนไฟล์ข้อความโดยมีนามสกุลบรรทัดที่ต้องการ (auto, unix หรือ windows) (ไม่บังคับ) ทำให้เป็นไฟล์ปฏิบัติการ (ถ้าเป็นสคริปต์)

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

    • native_binary() (แหล่งที่มา เอกสารประกอบ): รวมไบนารีดั้งเดิมในกฎ *_binary ซึ่งคุณสามารถ bazel run หรือใช้ใน run_binary() แอตทริบิวต์ tool หรือแอตทริบิวต์ tools ของ native.genrule()

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

  • ใน Windows ลองใช้ .bat กับสคริปต์สำหรับเรื่องเล็กๆ น้อยๆ

    คุณแก้ปัญหางานเล็กๆ น้อยๆ ด้วยสคริปต์ .bat แทนสคริปต์ .sh ได้

    ตัวอย่างเช่น หากคุณต้องการสคริปต์ที่ไม่มีการดำเนินการใดๆ หรือพิมพ์ข้อความ หรือออกจากหน้าเว็บ ให้แค่ไฟล์ .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: โดยหลักการคือ ให้เร็วที่สุด