Viết quy tắc trên Windows

Báo cáo sự cố Xem nguồn

Trang này tập trung vào việc viết các quy tắc tương thích với Windows, những vấn đề thường gặp khi viết quy tắc di động và một số giải pháp.

Đường dẫn

Vấn đề:

  • Giới hạn độ dài: độ dài đường dẫn tối đa là 259 ký tự.

    Mặc dù Windows cũng hỗ trợ các đường dẫn dài hơn (tối đa 32767 ký tự), nhưng nhiều chương trình được tạo với giới hạn thấp hơn.

    Hãy lưu ý điều này về các chương trình bạn chạy trong các thao tác.

  • Thư mục hoạt động: cũng giới hạn trong 259 ký tự.

    Các quy trình không được cd vào một thư mục dài hơn 259 ký tự.

  • Phân biệt chữ hoa chữ thường: Đường dẫn Windows không phân biệt chữ hoa chữ thường, đường dẫn Unix phân biệt chữ hoa chữ thường.

    Hãy lưu ý điều này khi tạo dòng lệnh cho các thao tác.

  • Dấu phân tách đường dẫn: là dấu gạch chéo ngược (\`), not forward slash (/`).

    Bazel lưu trữ các đường dẫn theo kiểu Unix với dấu phân tách /. Mặc dù một số chương trình Windows hỗ trợ đường dẫn kiểu Unix, nhưng một số chương trình khác thì không. Một số lệnh tích hợp trong cmd.exe có hỗ trợ các lệnh đó, một số lệnh thì không.

    Bạn nên luôn sử dụng \` separators on Windows: replace/with` khi tạo dòng lệnh và biến môi trường cho các thao tác.

  • Đường dẫn tuyệt đối: không bắt đầu bằng dấu gạch chéo (/).

    Đường dẫn tuyệt đối trên Windows bắt đầu bằng một tên ổ đĩa, chẳng hạn như C:\foo\bar.txt. Không có một gốc hệ thống tệp nào.

    Hãy lưu ý điều này nếu quy tắc của bạn kiểm tra xem đường dẫn có phải là tuyệt đối hay không. Bạn nên tránh sử dụng đường dẫn tuyệt đối vì các đường dẫn này thường không di chuyển được.

Giải pháp:

  • Đảm bảo lộ trình ngắn gọn.

    Tránh dùng tên thư mục dài, cấu trúc thư mục lồng sâu, tên tệp dài, tên không gian làm việc dài và tên mục tiêu dài.

    Tất cả các dữ liệu này đều có thể trở thành thành phần đường dẫn của tệp đầu vào của hành động và có thể sử dụng hết giới hạn độ dài đường dẫn.

  • Sử dụng một gốc đầu ra ngắn.

    Sử dụng cờ --output_user_root=<path> để chỉ định một đường dẫn ngắn cho đầu ra Bazel. Bạn nên có một ổ đĩa (hoặc ổ ảo) dành riêng cho dữ liệu đầu ra của Bazel (chẳng hạn như tệp D:\`), and adding this line to your.bazelrc`:

    build --output_user_root=D:/
    

    hoặc

    build --output_user_root=C:/_bzl
    
  • Sử dụng nút giao.

    Nói một cách đơn giản[1], điểm nối là các đường liên kết tượng trưng trong thư mục. Các điểm nối rất dễ tạo và có thể trỏ đến các thư mục (trên cùng một máy tính) có đường dẫn dài. Nếu một hành động tạo bản dựng tạo ra một điểm nối có đường dẫn ngắn nhưng mục tiêu dài, thì các công cụ có giới hạn đường dẫn ngắn có thể truy cập vào các tệp trong thư mục đường dẫn tiếp nối.

    Trong tệp .bat hoặc trong cmd.exe, bạn có thể tạo các mối liên kết như sau:

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

    [1]: Nói một cách chính xác, Lệnh cấm không phải là Đường liên kết tượng trưng, nhưng để phục vụ cho các hành động tạo dựng, bạn có thể coi Đường nối là Đường liên kết tương ứng thư mục.

  • Thay thế / bằng `` trong các đường dẫn trong hành động / envvar.

    Khi bạn tạo biến dòng lệnh hoặc biến môi trường cho một thao tác, hãy tạo các đường dẫn kiểu Windows. Ví dụ:

    def as_path(p, is_windows):
        if is_windows:
            return p.replace("/", "\\")
        else:
            return p
    

Biến môi trường

Vấn đề:

  • Phân biệt chữ hoa chữ thường: Tên biến môi trường Windows không phân biệt chữ hoa chữ thường.

    Ví dụ: trong Java, System.getenv("SystemRoot")System.getenv("SYSTEMROOT") sẽ mang lại cùng một kết quả. (Điều này cũng áp dụng cho các ngôn ngữ khác.)

  • Độ mạnh: các hành động nên sử dụng càng ít biến môi trường tuỳ chỉnh càng tốt.

    Các biến môi trường là một phần của khoá bộ nhớ đệm của thao tác. Nếu một thao tác sử dụng các biến môi trường thay đổi thường xuyên hoặc tuỳ chỉnh với người dùng, thì điều đó sẽ khiến quy tắc khó lưu vào bộ nhớ đệm hơn.

Giải pháp:

  • Chỉ sử dụng tên biến môi trường viết hoa.

    Phương thức này hoạt động trên Windows, macOS và Linux.

  • Giảm thiểu môi trường hành động.

    Khi sử dụng ctx.actions.run, hãy đặt môi trường thành ctx.configuration.default_shell_env. Nếu thao tác cần thêm biến môi trường, hãy đặt tất cả vào một từ điển và truyền biến đó vào thao tác. Ví dụ:

    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})
    

Thao tác

Vấn đề:

  • Đầu ra có thể thực thi: Mọi tệp thực thi phải có một phần mở rộng có thể thực thi.

    Các phần mở rộng phổ biến nhất là .exe (tệp nhị phân) và .bat (Tập lệnh hàng loạt).

    Xin lưu ý rằng các tập lệnh shell (.sh) KHÔNG thực thi được trên Windows; bạn không thể chỉ định các tập lệnh này là executable của ctx.actions.run. Các tệp cũng không có quyền +x, vì vậy, bạn không thể thực thi các tệp tuỳ ý như trên Linux.

  • Lệnh Bash: Để có thể di chuyển, hãy tránh chạy lệnh Bash trực tiếp trong các thao tác.

    Bash phổ biến trên các hệ thống giống Unix nhưng thường không có trên Windows. Bản thân Bazel ngày càng ít phụ thuộc vào Bash (MSYS2), vì vậy, trong tương lai, người dùng ít có khả năng cài đặt MSYS2 cùng với Bazel. Để các quy tắc dễ sử dụng hơn trên Windows, hãy tránh chạy các lệnh Bash trong thực tế.

  • Kết thúc dòng: Windows sử dụng CRLF (\r\n), các hệ thống giống Unix sử dụng LF (\n).

    Hãy lưu ý điều này khi so sánh các tệp văn bản. Hãy lưu ý đến các chế độ cài đặt Git của bạn, đặc biệt là về kết thúc dòng khi thanh toán hoặc cam kết. (Xem chế độ cài đặt core.autocrlf của Git.)

Giải pháp:

  • Sử dụng quy tắc không có mục đích Bash.

    native.genrule() là một trình bao bọc cho các lệnh Bash và thường được dùng để giải quyết các vấn đề đơn giản như sao chép tệp hoặc ghi tệp văn bản. Bạn có thể tránh dựa vào Bash (và phát minh lại bánh xe): xem bazel-skylib có quy tắc dành riêng cho nhu cầu của bạn hay không. Không có yếu tố nào trong số đó phụ thuộc vào Bash khi được tạo/kiểm thử trên Windows.

    Ví dụ về quy tắc tạo:

    • copy_file() (nguồn, tài liệu): sao chép tệp ở một nơi khác, nếu muốn tệp có thể thực thi

    • write_file() (nguồn, tài liệu): viết một tệp văn bản, với các phần cuối cùng của dòng mong muốn (auto, unix hoặc windows), tuỳ ý có thể thực thi tệp đó (nếu là tập lệnh)

    • run_binary() (nguồn, tài liệu): chạy một tệp nhị phân (hoặc quy tắc *_binary) với dữ liệu đầu vào nhất định và kết quả dự kiến dưới dạng một hành động tạo bản dựng (đây là trình bao bọc quy tắc bản dựng cho ctx.actions.run)

    • native_binary() (nguồn, tài liệu): gói tệp nhị phân gốc trong quy tắc *_binary mà bạn có thể bazel run hoặc sử dụng trong thuộc tính tool của run_binary() hoặc thuộc tính tools của native.genrule()

    Ví dụ về quy tắc kiểm thử:

    • diff_test() (nguồn, tài liệu): kiểm thử so sánh nội dung của hai tệp

    • native_test() (nguồn, tài liệu): gói một tệp nhị phân gốc trong một quy tắc *_test mà bạn có thể bazel test

  • Trên Windows, hãy cân nhắc sử dụng tập lệnh .bat cho những việc đơn giản.

    Thay vì tập lệnh .sh, bạn có thể giải quyết các nhiệm vụ đơn giản bằng tập lệnh .bat.

    Ví dụ: nếu bạn cần một tập lệnh không thực hiện thao tác nào hoặc in thông báo hoặc thoát với mã lỗi cố định, thì bạn chỉ cần sử dụng tệp .bat đơn giản. Nếu quy tắc của bạn trả về nhà cung cấp DefaultInfo(), thì trường executable có thể tham chiếu đến tệp .bat đó trên Windows.

    Ngoài ra, vì đuôi tệp không quan trọng trên macOS và Linux, nên bạn luôn có thể sử dụng .bat làm đuôi tệp, ngay cả đối với các tập lệnh shell.

    Xin lưu ý rằng bạn không thể thực thi các tệp .bat trống. Nếu bạn cần một tập lệnh trống, hãy ghi một khoảng trắng trong tập lệnh đó.

  • Sử dụng Bash theo nguyên tắc.

    Trong các quy tắc kiểm thử và xây dựng Starlark, hãy sử dụng ctx.actions.run_shell để chạy tập lệnh Bash và lệnh Bash dưới dạng hành động.

    Trong macro Starlark, hãy gói các tập lệnh và lệnh Bash trong một native.sh_binary() hoặc native.genrule(). Bazel sẽ kiểm tra xem Bash có sẵn hay không và chạy tập lệnh hoặc lệnh thông qua Bash.

    Trong các quy tắc kho lưu trữ Starlark, hãy thử tránh hoàn toàn Bash. Bazel hiện không cung cấp cách chạy các lệnh Bash theo nguyên tắc trong các quy tắc kho lưu trữ.

Đang xóa tệp

Vấn đề:

  • Bạn không thể xoá tệp khi đang mở.

    Bạn không thể xoá (theo mặc định) các tệp đang mở, những lần thử sẽ dẫn đến lỗi "Quyền truy cập bị từ chối". Nếu bạn không thể xoá một tệp, thì có thể là có thể quá trình đang chạy vẫn giữ cho tệp đó mở.

  • Bạn không thể xoá thư mục đang hoạt động của một quy trình đang chạy.

    Các quy trình có tên người dùng đang mở trong thư mục đang làm việc của chúng và thư mục đó sẽ không xoá được cho đến khi quy trình kết thúc.

Giải pháp:

  • Trong mã của bạn, hãy cố gắng đóng các tệp một cách nhanh chóng.

    Trong Java, hãy sử dụng try-with-resources. Trong Python, hãy sử dụng with open(...) as f:. Theo nguyên tắc, hãy thử đóng ô điều khiển càng sớm càng tốt.