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

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Báo cáo sự cố Xem nguồn

Định dạng tệp BUILD tuân theo cùng phương pháp tiếp cận là Go, trong đó công cụ được chuẩn hoá sẽ xử lý hầu hết các vấn đề về định dạng. Buildifier (Công cụ tạo bản dựng) là một công cụ phân tích cú pháp và phát ra mã nguồn theo kiểu chuẩn. Do đó, mọi tệp BUILD đều được định dạng theo cách tự động, giúp định dạng một vấn đề không phải trong quá trình xem xét mã. Việc 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 kết quả 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à không bắt buộc):

  • Mô tả gói (nhận xét)

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

  • Hàm package().

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

Trình tạo tạo sự khác biệt giữa nhận xét độc lập và nhận xét được đính kèm vào phần tử. Nếu không đính kèm nhận xét vào một phần tử cụ thể, hãy sử dụng dòng trống sau nhận xét đó. Việc phân biệt này là quan trọng khi thực hiện các thay đổi tự động (ví dụ như để giữ lại hoặc xoá một 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")

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 đến thư mục gói (mà không bao giờ phải sử dụng tính nă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 đó không phải là nguồn. Các tệp nguồn không được có tiền tố :. Tiền tố phải có tiền tố là :. 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 có 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 cho 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 đó, đừ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ục tiêu cùng tên (//x thay vì //x:x). Nếu bạn đang sử dụng cùng một gói, hãy ưu tiên tệp 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. Bao gồm all, __pkg____subpackages__, những tên này có ngữ nghĩa đặc biệt và có thể gây ra nhầm lẫn cũng như các hành vi không mong muốn khi sử dụng.

Trong trường hợp không có quy ước chung dành cho nhóm, sau đây là một số đề xuất không ràng buộc thường được sử dụng ở Google:

  • Nói chung, hãy sử dụng "snake_case"
    • Đối với java_library có một src, điều này có nghĩa là sử dụng một tên không giống với tên tệp mà không có đuôi
    • Đối với quy tắc Java *_binary*_test, hãy sử dụng "Upper CamelCase". Thao tác 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, thuộc tính này giúp thuộc tính test_class đượ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)
  • Hậu tố mục tiêu _test bằng _test, _unittest, Test hoặc Tests
  • Tránh các hậu tố vô nghĩa như _lib hoặc _library (trừ khi cần thiết để tránh xung đột giữa mục tiêu _library_binary tương ứng của mục tiêu đó)
  • Đối với các mục tiêu liên quan đến proto:
    • proto_library mục tiêu phải có tên kết thúc bằng _proto
    • Các quy tắc *_proto_library dành riêng cho ngôn ngữ phải khớp với nguyên mẫu cơ bản nhưng thay thế _proto bằng một hậu tố cụ thể cho ngôn ngữ 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 phạm vi chặt chẽ nhất có thể, trong khi vẫn cho phép truy cập bằng các kiểm thử và phần phụ thuộc đảo ngược. Hãy sử dụng __pkg____subpackages__ khi thích hợp.

Tránh đặt gói default_visibility thành //visibility:public. Bạn chỉ nên đặt riêng //visibility:public 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ế phụ thuộc vào các dự án hoặc tệp nhị phân bên ngoài có thể được sử dụng trong quy trình xây dựng của dự án bên ngoài.

Phần phụ thuộc

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

Các phần phụ thuộc gói cục bộ phải được liệt kê trước và được tham chiếu theo cách tương thích với Các tham chiếu đến 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. 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 làm giảm khả năng duy trì, khiến các công cụ không thể thay đổi các phần phụ thuộc của mục tiêu và có thể dẫn đến các phần phụ thuộc không dùng đến.

Quả cầu

Cho biết "không có mục tiêu" bằng []. Không sử dụng cụm từ tìm kiếm khớp với nhiều giá trị: URL dễ bị lỗi và ít rõ ràng hơn danh sách trống.

Định kỳ

Không sử dụng nút định kỳ để khớp với các tệp nguồn (ví dụ: glob(["**/*.java"])).

Các chuỗi cầu lặp lại khiến các tệp BUILD trở nên khó giải thích vì chúng bỏ qua các thư mục con chứa tệp BUILD.

Các nút cầu lặp lại 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ó biểu đồ phần phụ thuộc được xác định giữa các phần này vì điều này cho phép lưu vào bộ nhớ đệm từ xa và song song tốt hơn.

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

Không lặp lại

Các trường hợp không liên tục định kỳ thường được chấp nhận.

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 được chia nhỏ nhãn ngay cả khi dài hơn 79 ký tự. Nhãn phải là giá trị cố định kiểu chuỗi bất cứ khi nào có thể. Rationale: Tính năng này giúp bạn dễ dàng tìm thấy và thay thế. Đồng thời, 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 hằng (ngoại trừ trong macro). Rationale: Các công cụ bên ngoài sử dụng thuộc tính tên để tham chiếu đến một quy tắc. Họ cần tìm quy tắc mà không cần phải diễn giải mã.

  • Khi đặt thuộc tính loại boolean, hãy sử dụng giá trị boolean, không phải giá trị số nguyên. Vì các lý do cũ, quy tắc vẫn chuyển đổi số nguyên thành boolean nếu cần. Tuy nhiên, bạn không nên sử dụng quy tắc này. Rationale: flaky = 1 có thể hiểu sai bằng cách nói: "huỷ mục tiêu này bằng cách chạy lại mục tiêu một lần". flaky = True rõ ràng nó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ề kiểu Python là một mục tiêu, nhưng 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 nhận xét dài và chuỗi dài thường được chia thành 79 cột, nhưng không bắt buộc. Bạn không nên thực thi mã này trong các bài đánh giá mã hoặc tập lệnh gửi trước. Rationale: Nhãn có thể dài và vượt quá giới hạn này. Thông thường, các công cụ BUILD sẽ tạo hoặc chỉnh sửa các tệp không phù hợp với giới hạn độ dài dòng.

  • Nối chuỗi ngầm ẩn không được hỗ trợ. Dùng toán tử +. Rationale: 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ả khác hoàn toàn. Điều này đã tạo ra nhiều lỗi trong quá khứ. Xem thêm nội dung thảo luận này.

  • Sử dụng dấu cách quanh dấu = cho các đối số từ khoá trong quy tắc. Rationale: Các đối số được đặt tên thường xuyên hơn trong Python và luôn nằm trên một dòng riêng. Không gian cải thiện khả năng đọc. Quy ước này đã tồn tại từ rất lâu và không đáng để sửa đổi tất cả cá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. Rationale: Điều này không được chỉ định trong hướng dẫn về quy tắc lập trình Python, nhưng bạn nên sử dụng tính nhất quán. Vì vậy, chúng tôi quyết định chỉ sử dụng chuỗi trong dấu ngoặc kép. Nhiều ngôn ngữ sử dụng dấu ngoặc kép cho chuỗi ký tự.

  • Hãy 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ư tệp Python thông thường. Lớp 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ẽ làm cho các tệp BUILD ngắn hơn.