Hướng dẫn văn phong .bzl

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

Trang này trình bày các nguyên tắc cơ bản về kiểu cho Starlark, đồng thời bao gồm thông tin về macro và quy tắc.

Starlark là một ngôn ngữ xác định cách xây dựng phần mềm, do đó đây là ngôn ngữ lập trình và cấu hình.

Bạn sẽ sử dụng Starlark để viết các tệp BUILD, macro và các quy tắc xây dựng. Macro và quy tắc về cơ bản là ngôn ngữ meta – chúng xác định cách viết tệp BUILD. BUILD là tệp đơn giản và lặp lại nhiều lần.

Phần mềm được đọc thường xuyên hơn những gì được viết. Điều này đặc biệt đúng với Starlark, vì các kỹ sư đọc tệp BUILD để hiểu các phần phụ thuộc trong mục tiêu và thông tin chi tiết về bản dựng. Việc đọc này thường sẽ xảy ra khi người dùng vượt qua, trong lúc vội vàng hoặc song song với việc hoàn thành một số công việc khác. Do đó, tính đơn giản và dễ đọc là rất quan trọng để người dùng có thể phân tích cú pháp và hiểu nhanh các tệp BUILD.

Khi mở một tệp BUILD, người dùng nhanh chóng muốn biết danh sách mục tiêu trong tệp; hoặc xem lại danh sách nguồn của thư viện C++ đó; hoặc xoá phần phụ thuộc khỏi tệp nhị phân Java đó. Mỗi lần thêm một lớp trừu tượng, bạn sẽ khiến người dùng khó thực hiện các tác vụ này hơn.

Các tệp BUILD cũng được phân tích và cập nhật bằng nhiều công cụ khác nhau. Các công cụ có thể không chỉnh sửa được tệp BUILD nếu tệp đó sử dụng tính năng trừu tượng. Việc giữ cho các tệp BUILD đơn giản sẽ cho phép bạn nhận được công cụ tốt hơn. Khi cơ sở mã phát triển, bạn sẽ càng thường xuyên thay đổi nhiều tệp BUILD để cập nhật thư viện hoặc dọn dẹp.

Lời khuyên chung

Phong cách

Kiểu Python

Nếu nghi ngờ, hãy làm theo Hướng dẫn định kiểu PEP 8 nếu có thể. Cụ thể, hãy sử dụng 4 thay vì 2 dấu cách để thụt lề để tuân theo quy ước Python.

Starlark không phải là Python, nên một số khía cạnh của kiểu Python không áp dụng được. Ví dụ: PEP 8 khuyên rằng bạn nên so sánh với singleton bằng is, vốn không phải là toán tử trong Starlark.

Chuỗi tài liệu

Tệp tài liệu và hàm sử dụng chuỗi chuỗi. Sử dụng chuỗi tài liệu ở đầu mỗi tệp .bzl và chuỗi tài liệu cho mỗi hàm công khai.

Các quy tắc và khía cạnh của tài liệu

Các quy tắc và khía cạnh, cùng với thuộc tính, cũng như nhà cung cấp và trường của chúng, phải được ghi lại bằng đối số doc.

Quy ước đặt tên

  • Biến và tên hàm sử dụng chữ thường với các từ được phân tách bằng dấu gạch dưới ([a-z][a-z0-9_]*), chẳng hạn như cc_library.
  • Giá trị riêng tư cấp cao nhất bắt đầu bằng một dấu gạch dưới. Bazel thực thi rằng không thể sử dụng các giá trị riêng tư từ các tệp khác. Biến cục bộ không nên sử dụng tiền tố dấu gạch dưới.

Chiều dài dòng

Như trong tệp BUILD, không có giới hạn độ dài dòng nghiêm ngặt vì nhãn có thể dài. Khi có thể, hãy cố gắng sử dụng tối đa 79 ký tự trên mỗi dòng (làm theo hướng dẫn kiểu của Python, PEP 8). Bạn không nên thực thi nguyên tắc này một cách nghiêm ngặt: trình chỉnh sửa phải hiển thị hơn 80 cột, các thay đổi tự động sẽ thường xuyên đưa ra các dòng dài hơn và con người không nên dành thời gian để phân tách các dòng đã có thể đọc được.

Đối số từ khóa

Trong các đối số từ khoá, khoảng trắng xung quanh dấu bằng được ưu tiên:

def fct(name, srcs):
    filtered_srcs = my_filter(source = srcs)
    native.cc_library(
        name = name,
        srcs = filtered_srcs,
        testonly = True,
    )

Giá trị boolean

Ưu tiên các giá trị TrueFalse (thay vì 10) cho các giá trị boolean (chẳng hạn như khi sử dụng một thuộc tính boolean trong một quy tắc).

Không sử dụng hàm print() trong mã sản xuất; hàm này chỉ nhằm gỡ lỗi và sẽ spam tất cả người dùng trực tiếp và gián tiếp của tệp .bzl. Trường hợp ngoại lệ duy nhất là bạn có thể gửi mã sử dụng print() nếu mã này bị tắt theo mặc định và chỉ có thể được bật bằng cách chỉnh sửa nguồn – ví dụ: nếu tất cả mục sử dụng print() được bảo vệ bằng if DEBUG:, trong đó DEBUG được mã hoá cứng thành False. Hãy lưu ý xem những câu lệnh này có đủ hữu ích để chứng minh tác động của chúng hay không.

Macro

Macro là một hàm tạo bản sao của một hoặc nhiều quy tắc trong giai đoạn tải. Nói chung, hãy sử dụng quy tắc bất cứ khi nào có thể thay vì macro. Biểu đồ bản dựng mà người dùng nhìn thấy không giống với biểu đồ mà Bazel sử dụng trong quá trình tạo bản dựng – macro được mở rộng trước khi Bazel thực hiện bất kỳ phân tích biểu đồ bản dựng nào.

Do đó, khi xảy ra sự cố, người dùng sẽ cần hiểu cách triển khai macro của bạn để khắc phục sự cố xây dựng. Ngoài ra, các kết quả bazel query có thể khó diễn giải vì các mục tiêu hiển thị trong kết quả đến từ tính năng mở rộng macro. Cuối cùng, các khía cạnh không nhận biết được macro, do đó việc tạo công cụ phụ thuộc vào các khía cạnh (IDE và các thành phần khác) có thể không thành công.

Việc sử dụng macro một cách an toàn là để xác định các mục tiêu bổ sung sẽ được tham chiếu trực tiếp tại Bazel CLI hoặc trong các tệp BUILD: Trong trường hợp đó, chỉ có người dùng cuối của các mục tiêu đó cần biết về chúng và mọi vấn đề về bản dựng do macro gây ra không bao giờ tồn tại cách sử dụng.

Đối với các macro xác định mục tiêu đã tạo (chi tiết triển khai macro không được đề cập tại CLI hoặc phụ thuộc vào các mục tiêu không được khởi tạo bởi macro đó), hãy làm theo các phương pháp hay nhất sau:

  • Macro phải nhận đối số name và xác định mục tiêu có tên đó. Mục tiêu đó sẽ trở thành mục tiêu chính của macro đó.
  • Các mục tiêu đã tạo, tức là tất cả các mục tiêu khác được xác định bằng macro, phải:
    • Đặt tên bằng <name> hoặc _<name>. Ví dụ: sử dụng name = '%s_bar' % (name).
    • Chế độ hiển thị bị hạn chế (//visibility:private) và
    • Có thẻ manual để tránh mở rộng mục tiêu ký tự đại diện (:all, ..., :*, v.v.).
  • Bạn chỉ nên sử dụng name để lấy tên của các mục tiêu do macro xác định, chứ không phải cho bất kỳ mục đích nào khác. Ví dụ: không sử dụng tên này để lấy phần phụ thuộc hoặc tệp đầu vào không do chính macro tạo ra.
  • Tất cả mục tiêu được tạo trong macro đều phải được kết hợp theo một cách nào đó với mục tiêu chính.
  • Duy trì tính nhất quán của các tên thông số trong macro. Nếu một tham số được truyền dưới dạng giá trị thuộc tính đến mục tiêu chính, hãy giữ nguyên tên của tham số đó. Nếu tham số macro phục vụ cùng mục đích như một thuộc tính quy tắc phổ biến, chẳng hạn như deps, thì hãy đặt tên giống như thuộc tính (xem bên dưới).
  • Khi gọi macro, chỉ sử dụng các đối số từ khóa. Điều này nhất quán với các quy tắc và cải thiện đáng kể khả năng đọc.

Các kỹ sư thường viết macro khi API Starlark của các quy tắc liên quan không đủ cho trường hợp sử dụng cụ thể, bất kể quy tắc đó được xác định trong Bazel trong mã gốc hay trong Starlark. Nếu bạn gặp phải vấn đề này, hãy hỏi tác giả quy tắc xem họ có thể mở rộng API để hoàn thành mục tiêu của bạn hay không.

Theo quy tắc chung, càng nhiều macro giống với quy tắc thì càng tốt.

Xem thêm macro.

Quy tắc

  • Quy tắc, khía cạnh và thuộc tính của chúng nên sử dụng tên viết thường (" viết hoa chữ thường").
  • Tên quy tắc là danh từ mô tả loại cấu phần phần mềm chính do quy tắc tạo ra, xét từ người dùng (hoặc đối với quy tắc lá). Đây không nhất thiết là một hậu tố của tệp. Ví dụ: một quy tắc tạo ra các cấu phần phần mềm C++ sẽ được dùng làm tiện ích Python có thể được gọi là py_extension. Đối với hầu hết ngôn ngữ, các quy tắc điển hình bao gồm:
    • *_library – một đơn vị biên dịch hoặc "mô-đun".
    • *_binary – một mục tiêu tạo ra một đơn vị triển khai hoặc đơn vị triển khai.
    • *_test - mục tiêu thử nghiệm. Điều này có thể bao gồm nhiều thử nghiệm. Dự kiến tất cả các kiểm thử trong mục tiêu *_test sẽ là các biến thể về cùng một chủ đề, ví dụ: kiểm thử một thư viện.
    • *_import: một mục tiêu đóng gói một cấu phần phần mềm được biên dịch trước, chẳng hạn như .jar hoặc .dll được sử dụng trong quá trình biên dịch.
  • Sử dụng tên và loại nhất quán cho các thuộc tính. Sau đây là một số thuộc tính thường gặp:
    • srcs: label_list, cho phép các tệp: tệp nguồn, thường do người tạo.
    • deps: label_list, thường không cho phép tệp: phần phụ thuộc biên dịch.
    • data: label_list, cho phép các tệp: tệp dữ liệu, chẳng hạn như dữ liệu thử nghiệm, v.v.
    • runtime_deps: label_list: các phần phụ thuộc không cần thiết cho thời gian chạy để biên dịch.
  • Đối với mọi thuộc tính có hành vi không rõ ràng (ví dụ: các mẫu chuỗi có các lựa chọn thay thế đặc biệt hoặc các công cụ được gọi bằng các yêu cầu cụ thể), hãy cung cấp tài liệu bằng cách sử dụng đối số từ khóa doc cho phần khai báo của thuộc tính (attr.label_list() hoặc tương tự).
  • Các hàm triển khai quy tắc hầu như luôn phải là các hàm riêng tư (được đặt tên bằng dấu gạch dưới ở đầu). Một kiểu phổ biến là đặt tên _myrule_implmyrule cho hàm triển khai.
  • Truyền thông tin giữa các quy tắc bằng cách sử dụng giao diện nhà cung cấp được xác định rõ. Khai báo và ghi nhận các trường nhà cung cấp.
  • Thiết kế quy tắc có lưu ý đến khả năng mở rộng. Cân nhắc rằng các quy tắc khác có thể muốn tương tác với quy tắc của bạn, truy cập vào nhà cung cấp và sử dụng lại các hành động bạn tạo.
  • Tuân thủ nguyên tắc về hiệu suất trong các quy tắc.