Nhãn

Báo cáo vấn đề Xem nguồn Nightly · 7.4 .

Nhãn là giá trị nhận dạng cho một mục tiêu. Một nhãn thông thường ở dạng chuẩn đầy đủ sẽ có dạng như sau:

@@myrepo//my/app/main:app_binary

Phần đầu tiên của nhãn là tên kho lưu trữ, @@myrepo. Cú pháp @ kép cho biết đây là tên kho lưu trữ chính tắc, là tên duy nhất trong không gian làm việc. Các nhãn có tên kho lưu trữ chính tắc xác định rõ ràng một mục tiêu bất kể chúng xuất hiện trong ngữ cảnh nào.

Thường thì tên kho lưu trữ chính tắc là một chuỗi bí ẩn có dạng như @@rules_java++toolchains+local_jdk. Thông thường, nhãn có tên kho lưu trữ rõ ràng sẽ có dạng như sau:

@myrepo//my/app/main:app_binary

Điểm khác biệt duy nhất là tên kho lưu trữ được đặt tiền tố là một @ thay vì hai. Đây là một kho lưu trữ có tên hiển thị là myrepo. Tên này có thể khác nhau dựa trên ngữ cảnh xuất hiện của nhãn này.

Trong trường hợp thông thường, khi một nhãn tham chiếu đến cùng một kho lưu trữ mà nhãn đó được sử dụng, bạn có thể bỏ qua phần tên kho lưu trữ. Vì vậy, bên trong @@myrepo, nhãn đầu tiên thường được viết là

//my/app/main:app_binary

Phần thứ hai của nhãn là tên gói không đủ điều kiện my/app/main, đường dẫn đến gói tương ứng với thư mục gốc của kho lưu trữ. Tên kho lưu trữ và tên gói không đủ điều kiện cùng tạo thành tên gói đủ điều kiện @@myrepo//my/app/main. Khi nhãn tham chiếu đến cùng một gói mà nhãn đó được sử dụng, bạn có thể bỏ qua tên gói (và dấu hai chấm nếu muốn). Vì vậy, bên trong @@myrepo//my/app/main, bạn có thể viết nhãn này theo một trong hai cách sau:

app_binary
:app_binary

Theo quy ước, dấu hai chấm bị bỏ qua đối với các tệp, nhưng được giữ lại cho các quy tắc, nhưng không có ý nghĩa gì khác.

Phần của nhãn sau dấu hai chấm, app_binary là tên mục tiêu chưa đủ điều kiện. Khi khớp với thành phần cuối cùng của đường dẫn gói, bạn có thể bỏ qua dấu hai chấm và thành phần đó. Do đó, hai nhãn này tương đương nhau:

//my/app/lib
//my/app/lib:lib

Tên của mục tiêu tệp trong thư mục con của gói là đường dẫn của tệp tương ứng với thư mục gốc của gói (thư mục chứa tệp BUILD). Vì vậy, tệp này nằm trong thư mục con my/app/main/testdata của kho lưu trữ:

//my/app/main:testdata/input.txt

Các chuỗi như //my/app@@some_repo//my/app có hai ý nghĩa tuỳ thuộc vào bối cảnh sử dụng: khi Bazel mong đợi một nhãn, các chuỗi này tương ứng có nghĩa là //my/app:app@@some_repo//my/app:app. Tuy nhiên, khi Bazel dự kiến một gói (ví dụ: trong thông số kỹ thuật package_group), các gói này sẽ tham chiếu đến gói chứa nhãn đó.

Một lỗi thường gặp trong tệp BUILD là sử dụng //my/app để tham chiếu đến một gói hoặc tất cả mục tiêu trong một gói. Hãy nhớ rằng lớp này tương đương với //my/app:app, vì vậy, lớp này sẽ đặt tên cho mục tiêu app trong gói my/app của kho lưu trữ hiện tại.

Tuy nhiên, bạn nên sử dụng //my/app để tham chiếu đến một gói trong phần thông số kỹ thuật của package_group hoặc trong tệp .bzl, vì phương thức này cho biết rõ rằng tên gói là tuyệt đối và bắt nguồn từ thư mục cấp cao nhất của không gian làm việc.

Bạn không thể sử dụng nhãn tương đối để tham chiếu đến các mục tiêu trong các gói khác; bạn phải luôn chỉ định giá trị nhận dạng kho lưu trữ và tên gói trong trường hợp này. Ví dụ: nếu cây nguồn chứa cả gói my/app và gói my/app/testdata (mỗi thư mục trong số hai thư mục này đều có tệp BUILD riêng), thì gói sau chứa một tệp có tên testdepot.zip. Dưới đây là hai cách (một cách sai, một cách đúng) để tham chiếu đến tệp này trong //my/app:BUILD:

Saitestdata là một gói khác, vì vậy, bạn không thể sử dụng đường dẫn tương đối

testdata/testdepot.zip

Đúng – tham chiếu đến testdata bằng đường dẫn đầy đủ

//my/app/testdata:testdepot.zip

Các nhãn bắt đầu bằng @@// là tham chiếu đến kho lưu trữ chính. Kho lưu trữ này vẫn hoạt động ngay cả từ các kho lưu trữ bên ngoài. Do đó, @@//a/b/c khác với //a/b/c khi được tham chiếu từ một kho lưu trữ bên ngoài. Phương thức trước tham chiếu lại kho lưu trữ chính, trong khi phương thức sau tìm //a/b/c trong chính kho lưu trữ bên ngoài. Điều này đặc biệt phù hợp khi viết các quy tắc trong kho lưu trữ chính tham chiếu đến các mục tiêu trong kho lưu trữ chính và sẽ được sử dụng từ các kho lưu trữ bên ngoài.

Để biết thông tin về các cách bạn có thể tham chiếu đến mục tiêu, hãy xem phần mẫu mục tiêu.

Quy cách từ vựng của nhãn

Cú pháp nhãn không khuyến khích sử dụng siêu ký tự có ý nghĩa đặc biệt đối với shell. Điều này giúp tránh các vấn đề trích dẫn do vô tình, đồng thời giúp bạn dễ dàng tạo các công cụ và tập lệnh để thao tác với nhãn, chẳng hạn như Ngôn ngữ truy vấn Bazel.

Dưới đây là thông tin chi tiết chính xác về tên mục tiêu được phép.

Tên mục tiêu — package-name:target-name

target-name là tên của mục tiêu trong gói. Tên của quy tắc là giá trị của thuộc tính name trong phần khai báo của quy tắc đó trong tệp BUILD; tên của tệp là tên đường dẫn tương ứng với thư mục chứa tệp BUILD.

Tên mục tiêu phải bao gồm toàn bộ các ký tự lấy từ tập hợp az, AZ, 09 và các ký hiệu dấu câu !%-@^_"#$&'()*-+,;<=>?[]{|}~/..

Tên tệp phải là đường dẫn tương đối ở dạng thông thường, tức là không được bắt đầu hoặc kết thúc bằng dấu gạch chéo (ví dụ: /foofoo/ bị cấm) cũng như không được chứa nhiều dấu gạch chéo liên tiếp làm dấu phân cách đường dẫn (ví dụ: foo//bar). Tương tự, các tệp tham chiếu cấp trên (..) và tệp tham chiếu thư mục hiện tại (./) bị cấm.

Không đúng – Không sử dụng .. để tham chiếu đến các tệp trong các gói khác

Đúng – Sử dụng //package-name:filename

Mặc dù thường sử dụng / trong tên của mục tiêu tệp, nhưng hãy tránh sử dụng / trong tên của các quy tắc. Đặc biệt là khi dạng viết tắt của nhãn được sử dụng, điều này có thể khiến người đọc nhầm lẫn. Nhãn //foo/bar/wiz luôn là viết tắt của //foo/bar/wiz:wiz, ngay cả khi không có gói foo/bar/wiz nào như vậy; nhãn này không bao giờ tham chiếu đến //foo:bar/wiz, ngay cả khi mục tiêu đó tồn tại.

Tuy nhiên, có một số trường hợp việc sử dụng dấu gạch chéo sẽ thuận tiện hoặc đôi khi thậm chí là cần thiết. Ví dụ: tên của một số quy tắc phải khớp với tệp nguồn chính của các quy tắc đó. Tệp này có thể nằm trong thư mục con của gói.

Tên gói — //package-name:target-name

Tên của một gói là tên của thư mục chứa tệp BUILD, tương ứng với thư mục cấp cao nhất của kho lưu trữ chứa. Ví dụ: my/app.

Ở cấp độ kỹ thuật, Bazel thực thi những điều sau:

  • Các ký tự được phép trong tên gói là chữ cái viết thường a đến z, chữ cái viết hoa A đến Z, chữ số 0 đến 9, ký tự ! \"#$%&'()*+,-.;<=>?@[]^_`{|} (có, có một ký tự dấu cách trong đó!) và tất nhiên là dấu gạch chéo lên / (vì đó là dấu phân cách thư mục).
  • Tên gói không được bắt đầu hoặc kết thúc bằng ký tự dấu gạch chéo lên /.
  • Tên gói không được chứa chuỗi con //. Điều này không hợp lý---đường dẫn thư mục tương ứng là gì?
  • Tên gói không được chứa chuỗi con /./ hoặc /../ hoặc /.../, v.v. Việc thực thi này được thực hiện để tránh nhầm lẫn khi dịch giữa tên gói logic và tên thư mục thực, do ý nghĩa ngữ nghĩa của ký tự dấu chấm trong chuỗi đường dẫn.

Ở cấp độ thực tế:

  • Đối với ngôn ngữ có cấu trúc thư mục quan trọng đối với hệ thống mô-đun của ngôn ngữ đó (ví dụ: Java), bạn phải chọn tên thư mục là giá trị nhận dạng hợp lệ trong ngôn ngữ đó. Ví dụ: không bắt đầu bằng chữ số đầu tiên và tránh các ký tự đặc biệt, đặc biệt là dấu gạch dưới và dấu gạch nối.
  • Mặc dù Bazel hỗ trợ các mục tiêu trong gói gốc của không gian làm việc (ví dụ: //:foo), tốt nhất bạn nên để trống gói đó để tất cả các gói có ý nghĩa đều có tên mô tả.

Quy tắc

Quy tắc chỉ định mối quan hệ giữa dữ liệu đầu vào và đầu ra, cũng như các bước để tạo dữ liệu đầu ra. Quy tắc có thể thuộc một trong nhiều loại (đôi khi được gọi là lớp quy tắc), lớp này tạo ra các tệp thực thi và thư viện được biên dịch, tệp thực thi kiểm thử và các dữ liệu đầu ra được hỗ trợ khác như mô tả trong Xây dựng Bách khoa toàn thư.

Tệp BUILD khai báo mục tiêu bằng cách gọi quy tắc.

Trong ví dụ bên dưới, chúng ta thấy phần khai báo my_app mục tiêu bằng cách sử dụng quy tắc cc_binary.

cc_binary(
    name = "my_app",
    srcs = ["my_app.cc"],
    deps = [
        "//absl/base",
        "//absl/strings",
    ],
)

Mỗi lệnh gọi quy tắc đều có một thuộc tính name (phải là một tên mục tiêu hợp lệ), khai báo một mục tiêu trong gói của tệp BUILD.

Mỗi quy tắc đều có một tập hợp thuộc tính; các thuộc tính áp dụng cho một quy tắc nhất định, cũng như tầm quan trọng và ngữ nghĩa của từng thuộc tính là một hàm của loại quy tắc; hãy xem Bách khoa toàn thư về bản dựng để biết danh sách các quy tắc và các thuộc tính tương ứng. Mỗi thuộc tính có một tên và một loại. Một số loại phổ biến mà thuộc tính có thể có là số nguyên, nhãn, danh sách nhãn, chuỗi, danh sách chuỗi, nhãn đầu ra, danh sách nhãn đầu ra. Không phải thuộc tính nào cũng cần được chỉ định trong mọi quy tắc. Do đó, các thuộc tính tạo thành một từ điển từ các khoá (tên) đến các giá trị đã nhập không bắt buộc.

Thuộc tính srcs có trong nhiều quy tắc có loại "danh sách nhãn"; giá trị của thuộc tính này (nếu có) là một danh sách nhãn, mỗi nhãn là tên của một mục tiêu là dữ liệu đầu vào cho quy tắc này.

Trong một số trường hợp, tên của loại quy tắc có phần tuỳ ý và thú vị hơn là tên của các tệp do quy tắc tạo ra, và điều này đúng với genrules. Để biết thêm thông tin, hãy xem phần Quy tắc chung: genrule.

Trong các trường hợp khác, tên này có ý nghĩa quan trọng: đối với các quy tắc *_binary*_test, tên quy tắc sẽ xác định tên của tệp thực thi mà bản dựng tạo ra.

Biểu đồ không chu trình có hướng trên các mục tiêu được gọi là biểu đồ mục tiêu hoặc biểu đồ phần phụ thuộc của bản dựng và là miền mà Công cụ truy vấn Bazel hoạt động.

Mục tiêu BUILD files