Hàm

Nội dung

gói hàng

package(default_deprecation, default_testonly, default_visibility, features)

Hàm này khai báo siêu dữ liệu áp dụng cho mọi quy tắc tiếp theo trong gói. Tệp này được sử dụng tối đa một lần trong một gói (tệp BUILD).

Hàm package() phải được gọi ngay sau tất cả các câu lệnh load() ở đầu tệp, trước bất kỳ quy tắc nào.

Đối số

Thuộc tính Nội dung mô tả
default_visibility

List of labels; optional

Chế độ hiển thị mặc định của các quy tắc trong gói này.

Mọi quy tắc trong gói này đều có chế độ hiển thị được chỉ định trong thuộc tính này, trừ phi có quy định khác trong thuộc tính visibility của quy tắc. Để biết thông tin chi tiết về cú pháp của thuộc tính này, vui lòng xem tài liệu về chế độ hiển thị. Chế độ hiển thị mặc định của gói không áp dụng cho exports_files, vốn là chế độ công khai theo mặc định.

default_deprecation

String; optional

Đặt thông báo deprecation mặc định cho tất cả các quy tắc trong gói này.

default_testonly

Boolean; optional; default is False except as noted

Đặt thuộc tính testonly mặc định cho tất cả các quy tắc trong gói này.

Trong các gói dưới javatests, giá trị mặc định là 1.

features

List strings; optional

Đặt các cờ khác nhau ảnh hưởng đến ngữ nghĩa của tệp BUILD này.

Tính năng này chủ yếu được những người làm việc trên hệ thống xây dựng sử dụng để gắn thẻ các gói cần xử lý đặc biệt nào đó. Đừng sử dụng tính năng này trừ phi có yêu cầu rõ ràng của người làm việc trên hệ thống xây dựng.

Ví dụ

Phần khai báo bên dưới khai báo rằng các quy tắc trong gói này chỉ hiển thị cho các thành viên của nhóm gói //foo:target. Từng khai báo chế độ hiển thị trên một quy tắc (nếu có) sẽ ghi đè thông số kỹ thuật này.
package(default_visibility = ["//foo:target"])

package_group

package_group(name, packages, includes)

Hàm này xác định một tập hợp các gói và liên kết một nhãn với tập hợp đó. Nhãn có thể được tham chiếu trong các thuộc tính visibility.

Nhóm gói chủ yếu được dùng để kiểm soát chế độ hiển thị. Một mục tiêu hiển thị công khai có thể được tham chiếu qua mọi gói trong cây nguồn. Một mục tiêu hiển thị riêng tư chỉ có thể được tham chiếu trong gói riêng của nó (không phải trong gói con). Ở giữa các trường hợp này, mục tiêu có thể cho phép truy cập vào gói của chính nó cùng với bất kỳ gói nào được một hoặc nhiều nhóm gói mô tả. Để biết nội dung giải thích chi tiết hơn về hệ thống chế độ hiển thị, hãy xem thuộc tính chế độ hiển thị.

Một gói nhất định được coi là nằm trong nhóm nếu gói đó khớp với thuộc tính packages hoặc đã nằm trong một trong các nhóm gói khác được đề cập ở thuộc tính includes.

Nhóm gói là các mục tiêu về mặt kỹ thuật, nhưng không được tạo bởi quy tắc và bản thân chúng không có bất kỳ biện pháp bảo vệ chế độ hiển thị nào.

Đối số

Thuộc tính Nội dung mô tả
name

Name; required

Tên dành riêng cho mục tiêu này.

packages

List of strings; optional

Danh sách không có hoặc có nhiều thông số kỹ thuật cho gói.

Mỗi chuỗi thông số kỹ thuật của gói có thể có một trong các dạng sau:

  1. Tên đầy đủ của một gói (không có kho lưu trữ) bắt đầu bằng 2 dấu gạch chéo. Ví dụ: //foo/bar chỉ định gói có tên đó và nằm trong cùng một kho lưu trữ với nhóm gói.
  2. Như trên, nhưng có /... đứng sau. Ví dụ: //foo/... chỉ định tập hợp //foo và tất cả các gói con của tập hợp đó. //... chỉ định tất cả các gói trong kho lưu trữ hiện tại.
  3. Các chuỗi public hoặc private sẽ chỉ định tương ứng cho mỗi gói hoặc không có gói nào. (Biểu mẫu này yêu cầu phải đặt cờ --incompatible_package_group_has_public_syntax.)

Ngoài ra, 2 loại thông số kỹ thuật đầu tiên của gói cũng có thể có tiền tố - để cho biết rằng các thông số đó bị bỏ qua.

Nhóm gói chứa bất kỳ gói nào khớp với ít nhất một trong các thông số kỹ thuật tích cực và không có thông số kỹ thuật tiêu cực nào của gói đó. Ví dụ: giá trị [//foo/..., -//foo/tests/...] bao gồm tất cả các gói con của //foo nhưng không phải là gói con của //foo/tests. (Bản thân //foo được đưa vào trong khi bản thân //foo/tests thì không.)

Ngoài chế độ hiển thị công khai, không có cách nào để chỉ định trực tiếp các gói bên ngoài kho lưu trữ hiện tại.

Nếu thiếu thuộc tính này, việc đặt thuộc tính này thành một danh sách trống cũng giống như việc đặt thuộc tính này thành một danh sách chỉ chứa private.

Lưu ý: Trước Bazel 6.0, thông số kỹ thuật //... có hành vi cũ giống với public. Hành vi này sẽ được khắc phục khi --incompatible_fix_package_group_reporoot_syntax được bật (đây là tuỳ chọn mặc định sau Bazel 6.0).

Lưu ý: Trước Bazel 6.0, khi thuộc tính này được chuyển đổi tuần tự dưới dạng một phần của bazel query --output=proto (hoặc --output=xml), dấu gạch chéo ở đầu sẽ bị bỏ qua. Ví dụ: //pkg/foo/... sẽ xuất dưới dạng \"pkg/foo/...\". Hành vi này được khắc phục khi --incompatible_package_group_includes_double_slash được bật (đây là chế độ mặc định sau Bazel 6.0).

includes

List of labels; optional

Các nhóm gói khác có trong gói này.

Các nhãn trong thuộc tính này phải tham chiếu đến các nhóm gói khác. Các gói trong nhóm gói được tham chiếu sẽ được đưa vào nhóm gói này. Đây là tính năng bắc cầu. Nếu nhóm gói a bao gồm nhóm gói bb bao gồm nhóm gói c, thì mọi gói trong c cũng sẽ là thành viên của a.

Khi sử dụng cùng với thông số kỹ thuật của gói bị bỏ qua, hãy lưu ý rằng trước tiên, tập hợp các gói của mỗi nhóm sẽ được tính toán độc lập, sau đó các kết quả sẽ được hợp nhất với nhau. Điều này có nghĩa là các thông số kỹ thuật bị bỏ qua trong một nhóm sẽ không ảnh hưởng đến các thông số kỹ thuật trong nhóm khác.

Ví dụ

Nội dung khai báo package_group sau đây chỉ định một nhóm gói có tên là "nhiệt đới" chứa các loại trái cây nhiệt đới.

package_group(
    name = "tropical",
    packages = [
        "//fruits/mango",
        "//fruits/orange",
        "//fruits/papaya/...",
    ],
)

Các nội dung khai báo sau đây chỉ định nhóm gói của một ứng dụng hư cấu:

package_group(
    name = "fooapp",
    includes = [
        ":controller",
        ":model",
        ":view",
    ],
)

package_group(
    name = "model",
    packages = ["//fooapp/database"],
)

package_group(
    name = "view",
    packages = [
        "//fooapp/swingui",
        "//fooapp/webui",
    ],
)

package_group(
    name = "controller",
    packages = ["//fooapp/algorithm"],
)

exports_files

exports_files([label, ...], visibility, licenses)

exports_files() chỉ định danh sách các tệp thuộc gói này được xuất sang các gói khác.

Tệp BUILD cho một gói chỉ có thể tham chiếu trực tiếp đến các tệp nguồn thuộc gói khác nếu chúng được xuất một cách rõ ràng bằng câu lệnh exports_files(). Đọc thêm về khả năng hiển thị của tệp.

Là một hành vi cũ, các tệp được đề cập dưới dạng dữ liệu đầu vào cho quy tắc cũng được xuất ở chế độ hiển thị mặc định cho đến khi cờ --incompatible_no_implicit_file_export được lật. Tuy nhiên, bạn không nên dựa vào hành vi này và chủ động di chuyển khỏi hành vi này.

Đối số

Đối số là danh sách tên của các tệp trong gói hiện tại. Bạn cũng có thể chỉ định nội dung khai báo chế độ hiển thị; trong trường hợp này, các tệp sẽ hiển thị với các mục tiêu đã chỉ định. Nếu bạn không chỉ định chế độ hiển thị, các tệp sẽ hiển thị cho mọi gói, ngay cả khi chế độ hiển thị mặc định của gói được chỉ định trong hàm package. Bạn cũng có thể chỉ định giấy phép.

Ví dụ:

Ví dụ sau đây sẽ xuất golden.txt (một tệp văn bản từ gói test_data) để các gói khác có thể sử dụng tệp này, chẳng hạn như trong thuộc tính data của các hoạt động kiểm thử.

# from //test_data/BUILD

exports_files(["golden.txt"])

toàn cầu

glob(include, exclude=[], exclude_directories=1, allow_empty=True)

Glob là một hàm trợ giúp tìm mọi tệp khớp với một số mẫu đường dẫn nhất định và trả về một danh sách đường dẫn mới, có thể thay đổi và được sắp xếp. Glob chỉ tìm kiếm các tệp trong gói riêng và chỉ tìm các tệp nguồn (không phải tệp được tạo cũng như các mục tiêu khác).

Nhãn của tệp nguồn sẽ được đưa vào kết quả nếu đường dẫn tương đối của gói của tệp đó khớp với bất kỳ mẫu include nào và không có mẫu exclude nào.

Danh sách includeexclude chứa các mẫu đường dẫn tương ứng với gói hiện tại. Mỗi mẫu có thể bao gồm một hoặc nhiều phân đoạn đường dẫn. Như thường lệ với đường dẫn Unix, các phân đoạn này được phân tách bằng /. Phân đoạn có thể chứa ký tự đại diện *: ký tự này khớp với bất kỳ chuỗi con nào trong phân đoạn đường dẫn (ngay cả chuỗi con trống), ngoại trừ ký tự phân cách thư mục /. Bạn có thể dùng ký tự đại diện này nhiều lần trong một phân đoạn đường dẫn. Ngoài ra, ký tự đại diện ** có thể khớp với 0 hoặc nhiều phân đoạn đường dẫn đầy đủ, nhưng bạn phải khai báo dưới dạng một phân đoạn đường dẫn độc lập.

Ví dụ:
  • foo/bar.txt khớp chính xác với tệp foo/bar.txt trong gói này
  • foo/*.txt khớp với mọi tệp trong thư mục foo/ nếu tệp đó kết thúc bằng .txt (trừ phi foo/ là một gói con)
  • foo/a*.htm* khớp với mọi tệp trong thư mục foo/ bắt đầu bằng a, sau đó có một chuỗi tuỳ ý (có thể trống), sau đó có .htm và kết thúc bằng một chuỗi tuỳ ý khác; chẳng hạn như foo/axx.htmfoo/a.html hoặc foo/axxx.html
  • **/a.txt khớp với mọi tệp a.txt trong mọi thư mục con của gói này
  • **/bar/**/*.txt khớp với mọi tệp .txt trong mọi thư mục con của gói này, nếu ít nhất một thư mục trên đường dẫn kết quả được gọi là bar, chẳng hạn như xxx/bar/yyy/zzz/a.txt hoặc bar/a.txt (hãy nhớ rằng ** cũng khớp với phân đoạn 0) hoặc bar/zzz/a.txt
  • ** khớp với mọi tệp trong mọi thư mục con của gói này
  • foo**/a.txt là mẫu không hợp lệ vì ** phải tự đứng riêng dưới dạng một phân đoạn

Nếu đối số exclude_directories được bật (đặt thành 1), tệp của thư mục loại sẽ bị loại khỏi kết quả (mặc định là 1).

Nếu bạn đặt đối số allow_empty thành False, hàm glob sẽ bị lỗi nếu kết quả là một danh sách trống.

Có một số giới hạn và cảnh báo quan trọng:

  1. glob() chạy trong quá trình đánh giá tệp BUILD, nên glob() chỉ so khớp các tệp trong cây nguồn của bạn và không bao giờ so khớp các tệp được tạo. Nếu đang xây dựng một mục tiêu yêu cầu cả tệp nguồn và tệp được tạo, bạn phải thêm danh sách rõ ràng các tệp đã tạo vào glob. Hãy xem ví dụ ở bên dưới với :mylib:gen_java_srcs.

  2. Nếu một quy tắc có cùng tên với tệp nguồn trùng khớp, thì quy tắc đó sẽ "ẩn" tệp đó.

    Để hiểu điều này, hãy nhớ rằng glob() trả về danh sách đường dẫn. Vì vậy, việc sử dụng glob() trong thuộc tính của các quy tắc khác (ví dụ: srcs = glob(["*.cc"])) có tác dụng tương tự như việc liệt kê rõ ràng các đường dẫn khớp. Ví dụ: nếu glob() tạo ra ["Foo.java", "bar/Baz.java"] nhưng cũng có một quy tắc trong gói có tên là "Foo.java" (được cho phép mặc dù Bazel cảnh báo về điều này), thì người dùng glob() sẽ sử dụng quy tắc "Foo.java" (kết quả của nó) thay vì tệp "Foo.java". Hãy xem vấn đề #10395 trên GitHub để biết thêm thông tin chi tiết.

  3. Tệp Glob có thể khớp với các tệp trong thư mục con. Đồng thời, tên thư mục con có thể được ký tự đại diện. Tuy nhiên...
  4. Nhãn không được vượt quá ranh giới của gói và toàn bộ không khớp với tệp trong gói con.

    Ví dụ: biểu thức glob **/*.cc trong gói x không bao gồm x/y/z.cc nếu x/y tồn tại dưới dạng một gói (dưới dạng x/y/BUILD hoặc một nơi nào khác trên đường dẫn gói). Điều này có nghĩa là kết quả của biểu thức toàn cầu thực sự phụ thuộc vào sự tồn tại của tệp BUILD – tức là cùng một biểu thức glob sẽ bao gồm x/y/z.cc nếu không có gói nào có tên là x/y hoặc được đánh dấu là đã xoá bằng cờ --deleted_packages.

  5. Quy định hạn chế ở trên áp dụng cho tất cả biểu thức toàn cục, bất kể các biểu thức đó sử dụng ký tự đại diện nào.
  6. Tệp ẩn có tên tệp bắt đầu bằng . hoàn toàn khớp với cả ký tự đại diện ***. Nếu bạn muốn khớp một tệp ẩn với mẫu phức hợp, mẫu của bạn cần bắt đầu bằng .. Ví dụ: *.*.txt sẽ khớp với .foo.txt, nhưng *.txt sẽ không khớp. Các thư mục ẩn cũng được so khớp theo cách tương tự. Các thư mục ẩn có thể bao gồm các tệp không bắt buộc làm dữ liệu đầu vào và có thể làm tăng số lượng tệp tổng hợp không cần thiết cũng như mức sử dụng bộ nhớ. Để loại trừ các thư mục ẩn, hãy thêm các thư mục đó vào đối số danh sách "loại trừ".
  7. Ký tự đại diện "**" có một trường hợp góc: mẫu "**" không khớp với đường dẫn thư mục của gói. Điều này có nghĩa là glob(["**"], exclude_directories = 0) khớp hoàn toàn với tất cả tệp và thư mục trong thư mục của gói hiện tại (nhưng tất nhiên là không chuyển vào các thư mục của gói con – hãy xem ghi chú trước về việc này).

Nói chung, bạn nên thử cung cấp một đuôi thích hợp (ví dụ: *.html) thay vì sử dụng '*' đơn thuần cho mẫu toàn cầu. Tên rõ ràng hơn vừa là quá trình tự ghi lại tài liệu, vừa đảm bảo rằng bạn không vô tình so khớp các tệp sao lưu hoặc tệp tự động lưu emacs/vi/....

Khi viết quy tắc xây dựng, bạn có thể liệt kê các phần tử của toàn cầu. Ví dụ: tính năng này cho phép tạo các quy tắc riêng cho mỗi giá trị đầu vào. Hãy xem phần ví dụ về toàn cầu mở rộng bên dưới.

Ví dụ về tập hợp toàn cầu

Tạo một thư viện Java được xây dựng từ mọi tệp java trong thư mục này và tất cả các tệp được tạo theo quy tắc :gen_java_srcs.

java_library(
    name = "mylib",
    srcs = glob(["*.java"]) + [":gen_java_srcs"],
    deps = "...",
)

genrule(
    name = "gen_java_srcs",
    outs = [
        "Foo.java",
        "Bar.java",
    ],
    ...
)

Bao gồm tất cả các tệp txt trong dữ liệu kiểm thử thư mục, ngoại trừapp.txt. Xin lưu ý rằng các tệp trong thư mục con của testdata sẽ không được đưa vào. Nếu bạn muốn đưa các tệp đó vào, hãy sử dụng toàn bộ đệ quy (**).

sh_test(
    name = "mytest",
    srcs = ["mytest.sh"],
    data = glob(
        ["testdata/*.txt"],
        exclude = ["testdata/experimental.txt"],
    ),
)

Ví dụ về glob đệ quy

Hãy kiểm thử phụ thuộc vào tất cả các tệp txt trong thư mục testdata và bất kỳ thư mục con nào trong thư mục đó (và các thư mục con trong thư mục đó, v.v.). Các thư mục con chứa tệp BUILD sẽ bị bỏ qua. (Xem các giới hạn và cảnh báo ở trên.)

sh_test(
    name = "mytest",
    srcs = ["mytest.sh"],
    data = glob(["testdata/**/*.txt"]),
)

Tạo một thư viện được tạo từ mọi tệp java trong thư mục này và tất cả các thư mục con, ngoại trừ những thư mục có đường dẫn bao gồm thư mục có tên là kiểm thử. Bạn nên tránh sử dụng mẫu này nếu có thể, vì mẫu này có thể làm giảm mức độ gia tăng của bản dựng, từ đó làm tăng thời gian xây dựng.

java_library(
    name = "mylib",
    srcs = glob(
        ["**/*.java"],
        exclude = ["**/testing/**"],
    ),
)

Ví dụ về tập hợp toàn cầu mở rộng

Tạo một quy tắc tạo riêng cho *_test.cc trong thư mục hiện tại để đếm số dòng trong tệp.

# Conveniently, the build language supports list comprehensions.
[genrule(
    name = "count_lines_" + f[:-3],  # strip ".cc"
    srcs = [f],
    outs = ["%s-linecount.txt" % f[:-3]],
    cmd = "wc -l $< >$@",
 ) for f in glob(["*_test.cc"])]

Nếu tệp BUILD ở trên nằm trong gói //foo và gói này chứa ba tệp phù hợp, a_test.cc, b_test.cc và c_test.cc thì việc chạy bazel query '//foo:all' sẽ liệt kê tất cả các quy tắc đã được tạo:

$ bazel query '//foo:all' | sort
//foo:count_lines_a_test
//foo:count_lines_b_test
//foo:count_lines_c_test

chọn

select(
    {conditionA: valuesA, conditionB: valuesB, ...},
    no_match_error = "custom message"
)

select() là hàm trợ giúp tạo thuộc tính quy tắc có thể định cấu hình. Thuộc tính này có thể thay thế phía bên phải của hầu hết mọi thuộc tính được chỉ định, vì vậy, giá trị của thuộc tính này phụ thuộc vào cờ Bazel dòng lệnh. Ví dụ: bạn có thể sử dụng tính năng này để xác định các phần phụ thuộc dành riêng cho nền tảng hoặc nhúng các tài nguyên khác nhau tuỳ thuộc vào việc một quy tắc được tạo ở chế độ "nhà phát triển" hay chế độ "phát hành".

Cách sử dụng cơ bản như sau:

sh_binary(
    name = "mytarget",
    srcs = select({
        ":conditionA": ["mytarget_a.sh"],
        ":conditionB": ["mytarget_b.sh"],
        "//conditions:default": ["mytarget_default.sh"]
    })
)

Điều này giúp thuộc tính srcs của sh_binary có thể định cấu hình bằng cách thay thế việc gán danh sách nhãn thông thường bằng lệnh gọi select ánh xạ các điều kiện cấu hình với các giá trị khớp. Mỗi điều kiện là một tham chiếu nhãn đến config_setting hoặc constraint_value. Điều kiện này "khớp" nếu cấu hình của mục tiêu khớp với một tập hợp giá trị dự kiến. Sau đó, giá trị của mytarget#srcs sẽ trở thành bất kỳ danh sách nhãn nào khớp với lệnh gọi hiện tại.

Lưu ý:

  • Chọn đúng một điều kiện cho bất kỳ lệnh gọi nào.
  • Nếu có nhiều điều kiện trùng khớp và một điều kiện là chuyên môn của các điều kiện khác, thì chuyên môn đó sẽ được ưu tiên. Điều kiện B được coi là một trường hợp đặc biệt của điều kiện A nếu B có tất cả cờ và giá trị ràng buộc giống như A và một số cờ hoặc giá trị ràng buộc bổ sung. Điều này cũng có nghĩa là việc phân giải chuyên môn không được thiết kế để tạo ra một thứ tự như đã trình bày trong Ví dụ 2 dưới đây.
  • Nếu nhiều điều kiện trùng khớp và một điều kiện không phải là chuyên môn của tất cả các điều kiện còn lại, thì Bazel sẽ gặp lỗi.
  • Nhãn giả đặc biệt //conditions:default sẽ được xem là khớp nếu không có điều kiện nào khác khớp. Nếu bạn không chọn điều kiện này, thì một số quy tắc khác phải khớp để tránh xảy ra lỗi.
  • Bạn có thể nhúng select bên trong một phần gán thuộc tính lớn hơn. Vì vậy, srcs = ["common.sh"] + select({ ":conditionA": ["myrule_a.sh"], ...}) srcs = select({ ":conditionA": ["a.sh"]}) + select({ ":conditionB": ["b.sh"]}) là các biểu thức hợp lệ.
  • select hoạt động với hầu hết (nhưng không phải tất cả) thuộc tính. Các thuộc tính không tương thích được đánh dấu là nonconfigurable trong tài liệu.

    gói con

    subpackages(include, exclude=[], allow_empty=True)

    subpackages() là một hàm trợ giúp, tương tự như hàm glob() liệt kê các gói con thay vì tệp và thư mục. Tệp này sử dụng các mẫu đường dẫn giống như glob() và có thể khớp với bất kỳ gói con nào là thành phần con trực tiếp của tệp BUILD hiện đang tải. Hãy xem toàn bộ để biết nội dung giải thích chi tiết và ví dụ về các mẫu bao gồm và loại trừ.

    Danh sách các gói con được trả về được sắp xếp theo thứ tự và chứa các đường dẫn tương ứng với gói tải hiện tại, khớp với các mẫu đã cho trong include chứ không phải các mẫu trong exclude.

    Ví dụ:

    Ví dụ sau đây liệt kê tất cả các gói con trực tiếp của gói foo/BUILD

    # The following BUILD files exist:
    # foo/BUILD
    # foo/bar/baz/BUILD
    # foo/sub/BUILD
    # foo/sub/deeper/BUILD
    #
    # In foo/BUILD a call to
    subs = subpackages(include = ["**"])
    
    # results in subs == ["sub", "bar/baz"]
    #
    # 'sub/deeper' is not included because it is a subpackage of 'foo/sub' not of
    # 'foo'
    

    Nói chung, thay vì gọi trực tiếp hàm này, người dùng nên sử dụng mô-đun "gói con" của skylib.