Định dạng tệp BUILD
tuân theo phương pháp tương tự như Go, trong đó
giải quyết hầu hết các vấn đề về định dạng.
Buildifier là 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
được định dạng theo cách tự động tương tự, khiến việc định dạng trở nên không thành vấn đề trong khoảng thời gian
xem xét mã. Điều này cũng giúp các công cụ dễ dàng hiểu, chỉnh sửa và
tạo tệp BUILD
.
Đị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à tùy chọn):
Mô tả gói (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 phân biệt giữa nhận xét độc lập và nhận xét được đính kèm vào một phần tử. Nếu nhận xét không được đính kèm với một phần tử cụ thể, hãy sử dụng một dòng trống ở sau. Sự khác biệt là quan trọng khi thực hiện thay đổi (ví dụ: để giữ lại hoặc loại bỏ nhận xét khi xoá 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 tệp tham chiếu lên, chẳng hạn như ..
). Các tệp được tạo phải
có tiền tố là ":
" để cho biết rằng chúng 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à 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ột đích 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) sẽ 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 đề cập đến một mục tiêu cùng tên (//x
thay vì //x:x
). Nếu bạn ở trong cùng một gói, hãy ưu tiên lựa chọn
tham chiếu (:x
thay vì //x
).
Tránh sử dụng nhãn "dành riêng" tên mục tiêu có ý nghĩa đặc biệt. bao gồm
all
, __pkg__
và __subpackages__
, những tên này có đặc biệt
ngữ nghĩa và có thể gây nhầm lẫn cũng như các hành vi không mong muốn khi chúng được sử dụng.
Khi không có quy ước nhóm phổ biến, đây là một số trường hợp không có tính ràng buộc đề xuất được sử dụng rộng rãi tại Google:
- Nói chung, hãy sử dụng "snake_case"
- Đối với
java_library
cósrc
, điều này có nghĩa là sử dụng tên không giống như tên tệp không có đuôi - Đối với các quy tắc
*_binary
và*_test
của Java, hãy sử dụng "Upper CamelCase" (Chữ trên CamelCase). Điều này cho phép tên mục tiêu khớp với một trong cácsrc
. Đểjava_test
, điều này giúp thuộc tínhtest_class
có thể suy ra từ tên của mục tiêu.
- Đối với
- Nếu một mục tiêu cụ thể có nhiều biến thể thì hãy thêm hậu tố vào
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ặcTests
vào các mục tiêu_test
- Tránh 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
và_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
cụ thể theo ngôn ngữ phải khớp với ngôn ngữ cơ bản proto nhưng thay thế_proto
bằng một hậu tố của ngôn ngữ cụ thể, 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ị
Tầm nhìn phải được đặt ở 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 ngược. Sử dụng __pkg__
và __subpackages__
làm
phù 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à những thư viện được thiết kế để phụ thuộc vào
được bật trên các dự án hoặc tệp nhị phân bên ngoài mà nhóm dự án bên ngoài có thể sử dụng
quá trình tạo bản dựng.
Phần phụ thuộc
Bạn chỉ được sử dụng các phần phụ thuộc trực tiếp (phần phụ thuộc) cần thiết bởi các nguồn được liệt kê trong quy tắc). Không được liệt kê các phần phụ thuộc bắc cầu.
Các phần phụ thuộc cục bộ của gói phải được liệt kê trước và được tham chiếu theo cách tương thích với 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 của chúng).
Ư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. Đặt "thông tin chung" phần phụ thuộc của một vài mục tiêu vào một biến làm giảm khả năng bảo trì, khiến cho thì công cụ không thể thay đổi được các phần phụ thuộc của mục tiêu và có thể dẫn đến phần phụ thuộc không dùng đến.
Mưa nhỏ
Cho biết "không có mục tiêu" cùng với []
. Không sử dụng hình cầu không khớp với giá trị nào: nó
dễ gặp lỗi hơn 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ụm từ tìm kiếm đệ quy khiến tệp BUILD
khó giải thích vì chúng bỏ qua
các thư mục con chứa tệp BUILD
.
Các hình cầu đệ quy thường kém hiệu quả hơn so với việc có một tệp BUILD
trên mỗi
có biểu đồ phần phụ thuộc được xác định giữa chúng, vì điều này sẽ cho phép
lưu vào bộ nhớ đệm từ xa và song song.
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 chúng.
Không đệ quy
Hình cầu không đệ quy thường được chấp nhận.
Các quy ước khác
Dùng chữ hoa và dấu gạch dưới để khai báo các 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 các biến (chẳng hạn nhưmy_variable
).Tuyệt đối không được chia các 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ể. Rationale: Việc này khiến dễ dàng tìm và thay thế. Điều này cũng giúp nội dung dễ đọc hơn.
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ừ trong macro). Rationale: Các công cụ bên ngoài sử dụng thuộc tính name để tham chiếu đến . 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 các 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 khi cần, nhưng bạn không nên làm như vậy. Rationale:
flaky = 1
có thể bị đọc sai khi nói "loại 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 tra 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 quy tắc Python là một mục tiêu, có một số 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à các chuỗi dài thường được tách đến 79 cột, nhưng không bắt buộc. Không được thực thi chính sách này trong mã xem lại hoặc gửi trước tập lệnh. Rationale: Nhãn có thể dài và vượt quá giới hạn này tối đa. Các công cụ thường tạo hoặc chỉnh sửa tệp
BUILD
không phù hợp với giới hạn độ dài dòng.Không hỗ trợ việc nối chuỗi ngầm ẩn. Sử dụng toán tử
+
. Rationale: Các tệpBUILD
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. Sự cố 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 dấu cách xung quanh dấu
=
cho các đố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 biệt. Dấu cách giúp cải thiện khả năng đọc. Quy ước này đã phổ biến trong một thời gian dài và bạn không cần sửa đổi tất cả tệpBUILD
hiện có.Theo mặc định, hãy sử dụng dấu ngoặc kép cho chuỗi. Rationale: Đây không phải là được chỉ định trong hướng dẫn quy tắc Python, nhưng đề xuất tính nhất quán. Vậy chúng tôi đã quyết định chỉ sử dụng 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 một tệp Python thông thường. Chiến dịch này chỉ có các tuyên bố cấp cao nhất. Việc sử dụng một dòng trống sẽ giúp cho tệpBUILD
ngắn hơn.