Hướng dẫn XÂY DỰNG phong cách

Báo cáo vấn đề Xem nguồn Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Việc định dạng tệp BUILD tuân theo phương pháp tương tự như Go, trong đó một công cụ được chuẩn hoá sẽ xử lý hầu hết các vấn đề về định dạng. Buildifier là một công cụ phân tích cú pháp và phát mã nguồn theo kiểu chuẩn. Do đó, mọi tệp BUILD đều được định dạng theo cùng một cách tự động, giúp việc định dạng không còn là vấn đề trong quá trình xem xét mã. Điều này cũng giúp các công cụ dễ hiểu, chỉnh sửa và tạo tệp BUILD hơn.

Định dạng tệp BUILD phải khớp với đầu ra của buildifier.

Ví dụ về định dạng

# Test code implementing the Foo controller.
package(default_testonly = True)

py_test(
    name = "foo_test",
    srcs = glob(["*.py"]),
    data = [
        "//data/production/foo:startfoo",
        "//foo",
        "//third_party/java/jdk:jdk-k8",
    ],
    flaky = True,
    deps = [
        ":check_bar_lib",
        ":foo_data_check",
        ":pick_foo_port",
        "//pyglib",
        "//testing/pybase",
    ],
)

Cấu trúc tệp

Đề xuất: Sử dụng thứ tự sau (mỗi phần tử là tùy chọn):

  • Nội dung mô tả gói (một nhận xét)

  • Tất cả câu lệnh load()

  • Hàm package().

  • Lệnh gọi đến các quy tắc và macro

Trình tạo bản dựng giúp phân biệt giữa nhận xét độc lập và nhận xét đi kèm với một phần tử. Nếu một nhận xét không được đính kèm vào một phần tử cụ thể, hãy sử dụng một dòng trống sau phần tử đó. Sự khác biệt này rất quan trọng khi thực hiện các thay đổi tự động (ví dụ: giữ lại hoặc xoá nhận xét khi xoá một quy tắc).

# Standalone comment (such as to make a section in a file)

# Comment for the cc_library below
cc_library(name = "cc")

Thông tin tham chiếu đến các mục tiêu trong gói hiện tại

Các tệp phải được tham chiếu bằng đường dẫn tương ứng với thư mục gói (mà không bao giờ sử dụng tham chiếu lên, chẳng hạn như ..). Các tệp đã tạo phải có tiền tố ":" để cho biết các tệp này không phải là nguồn. Tệp nguồn không được có tiền tố :. Các quy tắc phải có tiền tố :. Ví dụ: giả sử x.cc là một tệp nguồn:

cc_library(
    name = "lib",
    srcs = ["x.cc"],
    hdrs = [":gen_header"],
)

genrule(
    name = "gen_header",
    srcs = [],
    outs = ["x.h"],
    cmd = "echo 'int x();' > $@",
)

Đặt tên mục tiêu

Tên mục tiêu phải mang tính mô tả. Nếu mục tiêu chứa một tệp nguồn, thì mục tiêu thường phải có tên bắt nguồn từ nguồn đó (ví dụ: cc_library cho chat.cc có thể được đặt tên là chat hoặc java_library cho DirectMessage.java có thể được đặt tên là direct_message).

Mục tiêu cùng tên của một gói (mục tiêu có cùng tên với thư mục chứa) phải cung cấp chức năng được mô tả theo tên thư mục. Nếu không có mục tiêu nào như vậy, đừng tạo mục tiêu cùng tên.

Ưu tiên sử dụng tên ngắn khi tham chiếu đến một mục tiêu cùng tên (//x thay vì //x:x). Nếu bạn đang ở cùng một gói, hãy ưu tiên tham chiếu cục bộ (:x thay vì //x).

Tránh sử dụng tên mục tiêu "đã đặt trước" có ý nghĩa đặc biệt. Các tên này bao gồm all, __pkg____subpackages__. Các tên này có ngữ nghĩa đặc biệt và có thể gây nhầm lẫn cũng như hành vi không mong muốn khi được sử dụng.

Trong trường hợp không có quy ước phổ biến dành cho nhóm, sau đây là một số đề xuất không mang tính ràng buộc được sử dụng rộng rãi tại Google:

  • Nói chung, hãy sử dụng "secure_case"
    • Đối với java_library có một src, điều này có nghĩa là sử dụng tên không giống với tên tệp mà không có đuôi
    • Đối với các quy tắc *_binary*_test của Java, hãy sử dụng "Upper CamelCase". Điều này cho phép tên mục tiêu khớp với một trong các src. Đối với java_test, điều này giúp thuộc tính test_class có thể được suy ra từ tên của mục tiêu.
  • Nếu có nhiều biến thể của một mục tiêu cụ thể, hãy thêm hậu tố để phân biệt (chẳng hạn như :foo_dev, :foo_prod hoặc :bar_x86, :bar_x64)
  • Thêm _test, _unittest, Test hoặc Tests vào các mục tiêu _test
  • Tránh sử dụng các hậu tố vô nghĩa như _lib hoặc _library (trừ phi cần thiết để tránh xung đột giữa mục tiêu _library_binary tương ứng)
  • Đối với các mục tiêu liên quan đến proto:
    • Mục tiêu proto_library phải có tên kết thúc bằng _proto
    • Các quy tắc *_proto_library cụ thể đối với ngôn ngữ phải khớp với proto cơ bản nhưng thay thế _proto bằng một hậu tố dành riêng cho ngôn ngữ, chẳng hạn như:
      • cc_proto_library: _cc_proto
      • java_proto_library: _java_proto
      • java_lite_proto_library: _java_proto_lite

Chế độ hiển thị

Chế độ hiển thị nên được đặt trong phạm vi càng chặt chẽ càng tốt, trong khi vẫn cho phép truy cập bằng cách kiểm thử và các phần phụ thuộc đảo ngược. Hãy sử dụng __pkg____subpackages__ khi phù hợp.

Tránh đặt gói default_visibility thành //visibility:public. Bạn chỉ nên đặt //visibility:public riêng lẻ cho các mục tiêu trong API công khai của dự án. Đây có thể là các thư viện được thiết kế để các dự án bên ngoài phụ thuộc vào hoặc các tệp nhị phân có thể được sử dụng trong quá trình xây dựng của một dự án bên ngoài.

Phần phụ thuộc

Các phần phụ thuộc phải được giới hạn ở các phần phụ thuộc trực tiếp (các phần phụ thuộc mà nguồn cần có trong quy tắc). Không liệt kê các phần phụ thuộc bắc cầu.

Bạn nên liệt kê các phần phụ thuộc cục bộ của gói trước và tham chiếu theo cách tương thích với phần Tham chiếu đến các mục tiêu trong gói hiện tại ở trên (không phải theo tên gói tuyệt đối).

Ưu tiên liệt kê các phần phụ thuộc trực tiếp dưới dạng một danh sách duy nhất. Việc đặt các phần phụ thuộc "phổ biến" của một số mục tiêu vào một biến sẽ làm giảm khả năng bảo trì, khiến các công cụ không thể thay đổi các phần phụ thuộc của một mục tiêu và có thể dẫn đến các phần phụ thuộc không được sử dụng.

Glob

Cho biết "không có mục tiêu" bằng []. Không sử dụng khối cầu mà không khớp với giá trị nào: khối này dễ gặp lỗi và khó rõ ràng hơn so với danh sách trống.

đệ quy

Không sử dụng khối cầu lặp đệ quy để so khớp với tệp nguồn (ví dụ: glob(["**/*.java"])).

Các cụm cầu kỳ gây khó khăn cho việc giải thích tệp BUILD vì chúng bỏ qua các thư mục con chứa tệp BUILD.

Các cụm cầu đệ quy thường kém hiệu quả hơn so với việc có một tệp BUILD cho mỗi thư mục có một biểu đồ phần phụ thuộc được xác định giữa chúng, vì điều này cho phép lưu vào bộ nhớ đệm và tính năng lưu song song từ xa hiệu quả hơn.

Bạn nên tạo một tệp BUILD trong mỗi thư mục và xác định một biểu đồ phần phụ thuộc giữa các thư mục đó.

Không đệ quy

Hình cầu không đệ quy thường được chấp nhận.

Các quy ước khác

  • Sử dụng chữ hoa và dấu gạch dưới để khai báo hằng số (chẳng hạn như GLOBAL_CONSTANT), sử dụng chữ thường và dấu gạch dưới để khai báo biến (chẳng hạn như my_variable).

  • Không bao giờ được tách nhãn, ngay cả khi nhãn dài hơn 79 ký tự. Nhãn phải là giá trị cố định dạng chuỗi bất cứ khi nào có thể. Lý do: Giúp tìm và thay thế dễ dàng. Điều này cũng giúp cải thiện khả năng đọc.

  • Giá trị của thuộc tính tên phải là một chuỗi hằng số cố định (ngoại trừ ở dạng macro). Rationale: Các công cụ bên ngoài sử dụng thuộc tính name để tham chiếu một quy tắc. Học sinh cần tìm các quy tắc mà không cần phải diễn giải mã.

  • Khi đặt thuộc tính kiểu boolean, hãy sử dụng giá trị boolean chứ không phải giá trị số nguyên. Vì lý do cũ, các quy tắc vẫn chuyển đổi số nguyên thành boolean nếu cần, nhưng bạn không nên làm như vậy. Rationale: flaky = 1 có thể bị hiểu nhầm là "tiêu bỏ mục tiêu này bằng cách chạy lại mục tiêu một lần". flaky = True nói rõ ràng "bài kiểm thử này không ổn định".

Điểm khác biệt với Hướng dẫn quy tắc Python

Mặc dù khả năng tương thích với hướng dẫn về phong cách Python là một mục tiêu, nhưng vẫn có một số điểm khác biệt:

  • Không có giới hạn nghiêm ngặt về độ dài dòng. Các ghi chú dài và chuỗi dài thường được phân tách thành 79 cột, nhưng điều này là không bắt buộc. Bạn không nên thực thi chính sách này trong quá trình xem xét mã hoặc tập lệnh gửi trước. Lý do: Nhãn có thể dài và vượt quá giới hạn này. Thông thường, các tệp BUILD được tạo hoặc chỉnh sửa bằng các công cụ, điều này không phù hợp với giới hạn độ dài dòng.

  • Không hỗ trợ nối chuỗi ngầm ẩn. Sử dụng toán tử +. Lý do: Tệp BUILD chứa nhiều danh sách chuỗi. Rất dễ quên dấu phẩy, dẫn đến một kết quả hoàn toàn khác. Điều này đã gây ra nhiều lỗi trong quá khứ. Xem thêm cuộc thảo luận này.

  • Sử dụng khoảng trắng xung quanh dấu = cho đối số từ khoá trong quy tắc. Rationale: Đối số được đặt tên xuất hiện thường xuyên hơn nhiều so với trong Python và luôn nằm trên một dòng riêng. Dấu cách giúp cải thiện khả năng đọc. Quy ước này đã tồn tại từ lâu và không đáng để sửa đổi tất cả tệp BUILD hiện có.

  • Theo mặc định, hãy sử dụng dấu ngoặc kép cho chuỗi. Lý do: Điều này không được chỉ định trong hướng dẫn về phong cách Python, nhưng bạn nên sử dụng nhất quán. Do đó, chúng tôi quyết định chỉ sử dụng các chuỗi được trích dẫn kép. Nhiều ngôn ngữ sử dụng dấu ngoặc kép cho giá trị cố định kiểu chuỗi.

  • Sử dụng một dòng trống giữa hai định nghĩa cấp cao nhất. Rationale: Cấu trúc của tệp BUILD không giống như một tệp Python thông thường. API này chỉ có các câu lệnh cấp cao nhất. Việc sử dụng một dòng trống sẽ giúp cho tệp BUILD ngắn hơn.