Trang này đề cập đến 3 hệ thống hiển thị của Bazel: chế độ hiển thị mục tiêu, chế độ hiển thị bắc cầu và chế độ hiển thị tải.
Các loại chế độ hiển thị này giúp các nhà phát triển khác phân biệt giữa API công khai của thư viện và thông tin triển khai của thư viện, đồng thời giúp thực thi cấu trúc khi không gian làm việc của bạn phát triển. Bạn cũng có thể sử dụng chế độ hiển thị khi ngừng sử dụng một API công khai để cho phép người dùng hiện tại trong khi từ chối người dùng mới.
Chế độ hiển thị mục tiêu
Chế độ hiển thị mục tiêu kiểm soát những người có thể phụ thuộc vào mục tiêu của bạn — tức là những người có thể sử dụng nhãn của mục tiêu bên trong một thuộc tính như deps. Một mục tiêu sẽ không thể tạo trong giai đoạn phân tích nếu mục tiêu đó vi phạm chế độ hiển thị của một trong các phần phụ thuộc.
Nhìn chung, mục tiêu A sẽ hiển thị với mục tiêu B nếu chúng ở cùng một vị trí hoặc nếu A cấp quyền hiển thị cho vị trí của B. Nếu không có macro tượng trưng, thuật ngữ "vị trí" có thể được đơn giản hoá thành "gói"; hãy xem phần bên dưới để biết thêm về macro tượng trưng.
Chế độ hiển thị được chỉ định bằng cách liệt kê các gói được cho phép. Việc cho phép một gói không nhất thiết có nghĩa là các gói con của gói đó cũng được cho phép. Để biết thêm thông tin chi tiết về gói và gói phụ, hãy xem phần Khái niệm và thuật ngữ.
Để tạo nguyên mẫu, bạn có thể tắt tính năng thực thi chế độ hiển thị mục tiêu bằng cách đặt cờ --check_visibility=false. Bạn không nên làm việc này cho mục đích sử dụng chính thức trong mã đã gửi.
Cách chính để kiểm soát chế độ hiển thị là sử dụng thuộc tính visibility của quy tắc.
Các tiểu mục sau đây mô tả định dạng của thuộc tính, cách áp dụng thuộc tính này cho nhiều loại mục tiêu, cũng như mối tương tác giữa hệ thống chế độ hiển thị và macro tượng trưng.
Thông số kỹ thuật về chế độ hiển thị
Tất cả mục tiêu quy tắc đều có thuộc tính visibility lấy danh sách nhãn. Mỗi nhãn có một trong các dạng sau. Ngoại trừ biểu mẫu cuối cùng, đây chỉ là các phần giữ chỗ cú pháp không tương ứng với bất kỳ mục tiêu thực tế nào.
"//visibility:public": Cấp quyền truy cập vào tất cả các gói."//visibility:private": Không cấp thêm quyền truy cập; chỉ các mục tiêu trong gói của vị trí này mới có thể sử dụng mục tiêu này."//foo/bar:__pkg__": Cấp quyền truy cập vào//foo/bar(nhưng không cấp quyền truy cập vào các gói con của gói này)."//foo/bar:__subpackages__": Cấp quyền truy cập vào//foo/barvà tất cả các gói con trực tiếp và gián tiếp của gói này."//some_pkg:my_package_group": Cấp quyền truy cập vào tất cả các gói thuộcpackage_groupđã cho.- Nhóm gói sử dụng cú pháp khác để chỉ định gói. Trong một nhóm gói, các biểu mẫu
"//foo/bar:__pkg__"và"//foo/bar:__subpackages__"lần lượt được thay thế bằng"//foo/bar"và"//foo/bar/...". Tương tự,"//visibility:public"và"//visibility:private"chỉ là"public"và"private".
- Nhóm gói sử dụng cú pháp khác để chỉ định gói. Trong một nhóm gói, các biểu mẫu
Ví dụ: nếu //some/package:mytarget có visibility được đặt thành [":__subpackages__", "//tests:__pkg__"], thì mọi mục tiêu thuộc cây nguồn //some/package/... cũng như các mục tiêu được khai báo trong //tests/BUILD đều có thể sử dụng mục tiêu đó, nhưng các mục tiêu được xác định trong //tests/integration/BUILD thì không.
Phương pháp hay nhất: Để hiển thị một số mục tiêu cho cùng một nhóm gói, hãy sử dụng package_group thay vì lặp lại danh sách trong thuộc tính visibility của mỗi mục tiêu. Điều này giúp tăng khả năng đọc và ngăn các danh sách không đồng bộ hoá.
Phương pháp hay nhất: Khi cấp quyền hiển thị cho dự án của một nhóm khác, hãy ưu tiên __subpackages__ hơn __pkg__ để tránh tình trạng hiển thị không cần thiết khi dự án đó phát triển và thêm các gói con mới.
Chế độ hiển thị mục tiêu của quy tắc
Chế độ hiển thị của mục tiêu quy tắc được xác định bằng cách lấy thuộc tính visibility của mục tiêu đó (hoặc giá trị mặc định phù hợp nếu không được cung cấp) và thêm vị trí khai báo mục tiêu. Đối với các mục tiêu không được khai báo trong macro tượng trưng, nếu gói chỉ định default_visibility, thì giá trị mặc định này sẽ được sử dụng; đối với tất cả các gói khác và đối với các mục tiêu được khai báo trong macro tượng trưng, giá trị mặc định chỉ là ["//visibility:private"].
# //mypkg/BUILD
package(default_visibility = ["//friend:__pkg__"])
cc_library(
name = "t1",
...
# No visibility explicitly specified.
# Effective visibility is ["//friend:__pkg__", "//mypkg:__pkg__"].
# If no default_visibility were given in package(...), the visibility would
# instead default to ["//visibility:private"], and the effective visibility
# would be ["//mypkg:__pkg__"].
)
cc_library(
name = "t2",
...
visibility = [":clients"],
# Effective visibility is ["//mypkg:clients, "//mypkg:__pkg__"], which will
# expand to ["//another_friend:__subpackages__", "//mypkg:__pkg__"].
)
cc_library(
name = "t3",
...
visibility = ["//visibility:private"],
# Effective visibility is ["//mypkg:__pkg__"]
)
package_group(
name = "clients",
packages = ["//another_friend/..."],
)
Phương pháp hay nhất: Tránh đặt default_visibility thành công khai. Điều này có thể thuận tiện cho việc tạo bản minh hoạ hoặc trong các cơ sở mã nhỏ, nhưng nguy cơ vô tình tạo mục tiêu công khai sẽ tăng lên khi toàn bộ mã nguồn phát triển. Tốt hơn là bạn nên nêu rõ mục tiêu nào là một phần của giao diện công khai của gói.
Chế độ hiển thị mục tiêu của tệp được tạo
Mục tiêu tệp được tạo có chế độ hiển thị giống như mục tiêu quy tắc tạo ra mục tiêu đó.
# //mypkg/BUILD
java_binary(
name = "foo",
...
visibility = ["//friend:__pkg__"],
)
# //friend/BUILD
some_rule(
name = "bar",
deps = [
# Allowed directly by visibility of foo.
"//mypkg:foo",
# Also allowed. The java_binary's "_deploy.jar" implicit output file
# target the same visibility as the rule target itself.
"//mypkg:foo_deploy.jar",
]
...
)
Chế độ hiển thị mục tiêu của tệp nguồn
Bạn có thể khai báo rõ ràng các mục tiêu tệp nguồn bằng cách sử dụng exports_files hoặc tạo ngầm bằng cách tham chiếu đến tên tệp của chúng trong thuộc tính nhãn của một quy tắc (bên ngoài macro tượng trưng). Giống như với mục tiêu quy tắc, vị trí của lệnh gọi đến exports_files hoặc tệp BUILD tham chiếu đến tệp đầu vào luôn được tự động thêm vào chế độ hiển thị của tệp.
Bạn có thể đặt chế độ hiển thị cho các tệp được khai báo bằng exports_files thông qua tham số visibility cho hàm đó. Nếu bạn không cung cấp tham số này, thì chế độ hiển thị sẽ là công khai.
Đối với các tệp không xuất hiện trong lệnh gọi đến exports_files, chế độ hiển thị sẽ phụ thuộc vào giá trị của cờ --incompatible_no_implicit_file_export:
Nếu cờ là true, thì chế độ hiển thị là riêng tư.
Nếu không, hành vi cũ sẽ được áp dụng: Chế độ hiển thị giống với chế độ hiển thị của tệp
BUILDdefault_visibilityhoặc ở chế độ riêng tư nếu bạn không chỉ định chế độ hiển thị mặc định.
Tránh dựa vào hành vi cũ. Luôn viết nội dung khai báo exports_files bất cứ khi nào mục tiêu tệp nguồn cần chế độ hiển thị không riêng tư.
Phương pháp hay nhất: Nếu có thể, hãy hiển thị mục tiêu quy tắc thay vì tệp nguồn. Ví dụ: thay vì gọi exports_files trên tệp .java, hãy gói tệp đó trong một mục tiêu java_library không riêng tư. Nhìn chung, các mục tiêu quy tắc chỉ nên tham chiếu trực tiếp đến các tệp nguồn nằm trong cùng một gói.
Ví dụ
Tệp //frobber/data/BUILD:
exports_files(["readme.txt"])
Tệp //frobber/bin/BUILD:
cc_binary(
name = "my-program",
data = ["//frobber/data:readme.txt"],
)
Chế độ hiển thị của chế độ cài đặt cấu hình
Trước đây, Bazel không thực thi chế độ hiển thị cho các mục tiêu config_setting được tham chiếu trong khoá của select(). Có hai cờ để xoá hành vi cũ này:
--incompatible_enforce_config_setting_visibilitybật tính năng kiểm tra chế độ hiển thị cho các mục tiêu này. Để hỗ trợ quá trình di chuyển, chế độ này cũng khiến mọiconfig_settingkhông chỉ địnhvisibilityđược coi là công khai (bất kểdefault_visibilityở cấp gói).--incompatible_config_setting_private_default_visibilitykhiếnconfig_settingkhông chỉ địnhvisibilityđể tuân thủdefault_visibilitycủa gói và quay lại chế độ hiển thị riêng tư, giống như mọi mục tiêu quy tắc khác. Đây là một thao tác không hoạt động nếu bạn không đặt--incompatible_enforce_config_setting_visibility.
Tránh dựa vào hành vi cũ. Mọi config_setting dự định được sử dụng bên ngoài gói hiện tại phải có visibility rõ ràng, nếu gói chưa chỉ định default_visibility phù hợp.
Chế độ hiển thị mục tiêu của nhóm gói
Mục tiêu package_group không có thuộc tính visibility. Các bài đánh giá này luôn hiển thị công khai.
Chế độ hiển thị của các phần phụ thuộc ngầm ẩn
Một số quy tắc có phần phụ thuộc ngầm ẩn — phần phụ thuộc không được nêu rõ trong tệp BUILD nhưng vốn có trong mọi thực thể của quy tắc đó. Ví dụ: quy tắc cc_library có thể tạo một phần phụ thuộc ngầm ẩn từ mỗi mục tiêu quy tắc đến một mục tiêu thực thi đại diện cho trình biên dịch C++.
Chế độ hiển thị của một phần phụ thuộc ngầm ẩn như vậy được kiểm tra theo gói chứa tệp .bzl mà quy tắc (hoặc khía cạnh) được xác định. Trong ví dụ của chúng ta, trình biên dịch C++ có thể ở chế độ riêng tư miễn là nó nằm trong cùng một gói với định nghĩa của quy tắc cc_library. Nếu phần phụ thuộc ngầm ẩn không hiển thị trong định nghĩa, thì phần phụ thuộc đó sẽ được kiểm tra theo mục tiêu cc_library.
Nếu bạn muốn hạn chế việc sử dụng một quy tắc cho một số gói nhất định, hãy sử dụng chế độ hiển thị load.
Chế độ hiển thị và macro tượng trưng
Phần này mô tả cách hệ thống chế độ hiển thị tương tác với macro tượng trưng.
Vị trí trong macro tượng trưng
Một chi tiết quan trọng của hệ thống hiển thị là cách chúng tôi xác định vị trí của một nội dung khai báo. Đối với các mục tiêu không được khai báo trong macro tượng trưng, vị trí chỉ là gói chứa mục tiêu – gói của tệp BUILD.
Tuy nhiên, đối với các mục tiêu được tạo trong macro tượng trưng, vị trí là gói chứa tệp .bzl nơi định nghĩa của macro (câu lệnh my_macro = macro(...)) xuất hiện. Khi một mục tiêu được tạo bên trong
nhiều mục tiêu lồng nhau, thì định nghĩa của macro tượng trưng trong cùng luôn được
sử dụng.
Hệ thống tương tự được dùng để xác định vị trí cần kiểm tra dựa trên chế độ hiển thị của một phần phụ thuộc nhất định. Nếu mục tiêu sử dụng được tạo bên trong một macro, chúng ta sẽ xem xét định nghĩa của macro trong cùng thay vì gói chứa mục tiêu sử dụng.
Điều này có nghĩa là tất cả macro có mã được xác định trong cùng một gói sẽ tự động là "bạn bè" với nhau. Bất kỳ mục tiêu nào được tạo trực tiếp bằng một macro
được xác định trong //lib:defs.bzl đều có thể được nhìn thấy từ bất kỳ macro nào khác được xác định trong //lib,
bất kể macro thực sự được tạo thực thể trong gói nào. Tương tự, các mục tiêu này có thể thấy và được thấy bởi các mục tiêu được khai báo trực tiếp trong //lib/BUILD và các macro cũ của nó. Ngược lại, các mục tiêu nằm trong cùng một gói không nhất thiết phải nhìn thấy nhau nếu ít nhất một trong số đó được tạo bằng macro tượng trưng.
Trong hàm triển khai của macro tượng trưng, tham số visibility có giá trị hiệu quả của thuộc tính visibility của macro sau khi thêm vị trí gọi macro. Cách tiêu chuẩn để macro xuất một trong các mục tiêu của macro đó sang phương thức gọi là chuyển tiếp giá trị này đến phần khai báo của mục tiêu, như trong some_rule(..., visibility = visibility). Các mục tiêu bỏ qua thuộc tính này sẽ không hiển thị với phương thức gọi của macro, trừ phi phương thức gọi nằm trong cùng một gói với định nghĩa macro. Hành vi này
kết hợp, theo nghĩa là một chuỗi các lệnh gọi lồng nhau đến các macro phụ có thể truyền
visibility = visibility, xuất lại các mục tiêu đã xuất của macro bên trong cho
người gọi ở mỗi cấp mà không hiển thị bất kỳ thông tin chi tiết nào về cách triển khai của macro.
Uỷ quyền cho macro phụ
Mô hình chế độ hiển thị có một tính năng đặc biệt cho phép macro uỷ quyền cho một macro phụ. Điều này rất quan trọng đối với việc phân tích và soạn macro.
Giả sử bạn có một macro my_macro tạo cạnh phần phụ thuộc bằng quy tắc some_library từ một gói khác:
# //macro/defs.bzl
load("//lib:defs.bzl", "some_library")
def _impl(name, visibility, ...):
...
native.genrule(
name = name + "_dependency"
...
)
some_library(
name = name + "_consumer",
deps = [name + "_dependency"],
...
)
my_macro = macro(implementation = _impl, ...)
# //pkg/BUILD
load("//macro:defs.bzl", "my_macro")
my_macro(name = "foo", ...)
Mục tiêu //pkg:foo_dependency không có visibility được chỉ định, vì vậy, mục tiêu này chỉ hiển thị trong //macro, hoạt động tốt cho mục tiêu sử dụng. Bây giờ, điều gì sẽ xảy ra nếu tác giả của //lib tái cấu trúc some_library để triển khai bằng macro?
# //lib:defs.bzl
def _impl(name, visibility, deps, ...):
some_rule(
# Main target, exported.
name = name,
visibility = visibility,
deps = deps,
...)
some_library = macro(implementation = _impl, ...)
Với thay đổi này, vị trí của //pkg:foo_consumer hiện là //lib thay vì //macro, vì vậy, việc sử dụng //pkg:foo_dependency sẽ vi phạm chế độ hiển thị của phần phụ thuộc. Tác giả của my_macro không thể truyền visibility = ["//lib"] đến phần khai báo phần phụ thuộc chỉ để giải quyết chi tiết triển khai này.
Vì lý do này, khi phần phụ thuộc của một mục tiêu cũng là giá trị thuộc tính của macro đã khai báo mục tiêu, chúng ta sẽ kiểm tra chế độ hiển thị của phần phụ thuộc dựa trên vị trí của macro thay vì vị trí của mục tiêu sử dụng.
Trong ví dụ này, để xác thực xem //pkg:foo_consumer có thể thấy //pkg:foo_dependency hay không, chúng ta thấy rằng //pkg:foo_dependency cũng được truyền dưới dạng dữ liệu đầu vào cho lệnh gọi đến some_library bên trong my_macro, và thay vào đó, hãy kiểm tra chế độ hiển thị của phần phụ thuộc so với vị trí của lệnh gọi này, //macro.
Quá trình này có thể lặp lại đệ quy, miễn là một mục tiêu hoặc khai báo macro nằm bên trong một macro tượng trưng khác lấy nhãn của phần phụ thuộc trong một trong các thuộc tính thuộc loại nhãn của nó.
Trình hoàn thiện
Ngoài việc xem các mục tiêu theo quy tắc hiển thị macro tượng trưng thông thường, các mục tiêu được khai báo trong trình hoàn thiện quy tắc (một macro tượng trưng có finalizer = True) cũng có thể xem tất cả mục tiêu hiển thị với gói của mục tiêu trình hoàn thiện.
Nói cách khác, nếu bạn di chuyển macro cũ dựa trên native.existing_rules() sang một trình hoàn thiện, thì các mục tiêu do trình hoàn thiện khai báo vẫn có thể thấy các phần phụ thuộc cũ của chúng.
Bạn có thể xác định các mục tiêu mà trình hoàn thiện có thể tự kiểm tra bằng cách sử dụng native.existing_rules(), nhưng không thể sử dụng làm phần phụ thuộc trong hệ thống chế độ hiển thị. Ví dụ: nếu một mục tiêu do macro xác định không hiển thị với gói của chính mục tiêu đó hoặc với định nghĩa của macro hoàn thiện và không được uỷ quyền cho trình hoàn thiện, thì trình hoàn thiện sẽ không thể thấy mục tiêu đó. Tuy nhiên, xin lưu ý rằng macro cũ dựa trên native.existing_rules() cũng sẽ không thể thấy mục tiêu như vậy.
Chế độ hiển thị bắc cầu
Chế độ hiển thị bắc cầu là một cách để hạn chế những người có thể phụ thuộc vào một mục tiêu, kể cả khi phần phụ thuộc chỉ là gián tiếp. Quy tắc này áp dụng riêng biệt với hệ thống hiển thị mục tiêu thông thường, vì vậy, lỗi hiển thị bắc cầu có thể xảy ra ngay cả khi mọi đường liên kết trong chuỗi phần phụ thuộc đều hợp lệ. Điều này cho phép tác giả của mục tiêu chia sẻ mục tiêu đó với một nhóm mục tiêu khách hàng đáng tin cậy, đồng thời ngăn chặn việc vô tình làm rò rỉ mục tiêu đó cho phần còn lại của bản dựng.
Chế độ hiển thị bắc cầu được khai báo ở cấp gói, sử dụng tham số transitive_visibility của hàm [package][package]. Nội dung khai báo này áp dụng cho tất cả mục tiêu trong gói. Tham số này lấy một nhãn duy nhất của package_group, chỉ định các gói có mục tiêu có thể phụ thuộc bắc cầu vào mục tiêu của gói này.
# //third_party/sensitive_dep/BUILD
package(
# This must be explicitly listed
transitive_visibility = ":sensitive_dep_users",
)
package_group(
name = "sensitive_dep_users",
packages = [
"//third_party/sensitive_dep/...", # has to include itself
"//allowed",
],
)
sh_library(
name = "sensitive_dep"
)
# //not_allowed/BUILD
sh_binary(
name = "bad",
deps = ["//third_party/sensitive_dep:sensitive_dep"]
)
Việc tạo //not_allowed:bad (phụ thuộc vào //third_party/sensitive_dep:sensitive_dep nhưng không thuộc transitive_visibility) sẽ dẫn đến lỗi sau:
Transitive visibility error: //third_party/sensitive_dep:sensitive_dep is not transitively visible from ///not_allowed:bad. //"//third_party/sensitive_dep:sensitive_dep inherits a transitive_visibility declaration from its package or one of its dependencies that does not allow //not_allowed:bad.
Nhóm gói được dùng trong transitive_visibility không được include nhóm gói khác.
Xin lưu ý rằng nếu một mục tiêu có phần phụ thuộc bắc cầu với quy định hạn chế về chế độ hiển thị bắc cầu, thì chính mục tiêu đó sẽ kế thừa quy định hạn chế và chuyển quy định đó đến các mục tiêu phụ thuộc vào mục tiêu đó. Nếu một mục tiêu có nhiều phần phụ thuộc bắc cầu có các quy định hạn chế về chế độ hiển thị bắc cầu, thì mục tiêu đó phải đáp ứng tất cả các quy định hạn chế.
Chế độ hiển thị bắc cầu cũng áp dụng cho các mục tiêu được khai báo trong macro tượng trưng. Tuy nhiên, không giống như chế độ hiển thị mục tiêu thông thường, chế độ này chỉ xem xét gói mà các mục tiêu này nằm trong đó, chứ không phải gói đã xác định macro tượng trưng.
Chế độ hiển thị tải
Chế độ hiển thị tải kiểm soát việc có thể tải tệp .bzl từ các tệp BUILD hoặc .bzl khác bên ngoài gói hiện tại hay không.
Tương tự như chế độ hiển thị mục tiêu bảo vệ mã nguồn được đóng gói theo mục tiêu, chế độ hiển thị tải bảo vệ logic bản dựng được đóng gói theo tệp .bzl. Ví dụ: tác giả tệp BUILD có thể muốn đưa một số nội dung khai báo mục tiêu lặp lại vào một macro trong tệp .bzl. Nếu không có chế độ bảo vệ của chế độ hiển thị tải, họ có thể thấy macro của mình được những cộng tác viên khác sử dụng lại trong cùng một không gian làm việc, do đó, việc sửa đổi macro sẽ làm hỏng bản dựng của các nhóm khác.
Xin lưu ý rằng tệp .bzl có thể có hoặc không có mục tiêu tệp nguồn tương ứng.
Nếu có, thì không có gì đảm bảo rằng chế độ hiển thị tải và chế độ hiển thị mục tiêu trùng khớp. Nói cách khác, cùng một tệp BUILD có thể tải tệp .bzl nhưng không liệt kê tệp đó trong srcs của filegroup hoặc ngược lại. Đôi khi, điều này có thể gây ra sự cố cho các quy tắc muốn sử dụng tệp .bzl làm mã nguồn, chẳng hạn như để tạo tài liệu hoặc kiểm thử.
Để tạo nguyên mẫu, bạn có thể tắt tính năng thực thi chế độ hiển thị tải bằng cách đặt --check_bzl_visibility=false. Tương tự như --check_visibility=false, bạn không nên làm việc này đối với mã đã gửi.
Chế độ hiển thị tải có sẵn kể từ Bazel 6.0.
Khai báo chế độ hiển thị khi tải
Để đặt chế độ hiển thị tải của tệp .bzl, hãy gọi hàm visibility() từ trong tệp.
Đối số cho visibility() là danh sách thông số kỹ thuật của gói, giống như thuộc tính packages của package_group. Tuy nhiên, visibility() không chấp nhận thông số kỹ thuật gói âm.
Lệnh gọi đến visibility() chỉ được thực hiện một lần cho mỗi tệp, ở cấp cao nhất (không phải bên trong một hàm) và lý tưởng nhất là ngay sau câu lệnh load().
Không giống như chế độ hiển thị mục tiêu, chế độ hiển thị tải mặc định luôn ở chế độ công khai. Các tệp không gọi visibility() luôn có thể tải được từ bất kỳ vị trí nào trong không gian làm việc. Bạn nên thêm visibility("private") vào đầu mọi tệp .bzl mới không dành riêng cho việc sử dụng bên ngoài gói.
Ví dụ
# //mylib/internal_defs.bzl
# Available to subpackages and to mylib's tests.
visibility(["//mylib/...", "//tests/mylib/..."])
def helper(...):
...
# //mylib/rules.bzl
load(":internal_defs.bzl", "helper")
# Set visibility explicitly, even though public is the default.
# Note the [] can be omitted when there's only one entry.
visibility("public")
myrule = rule(
...
)
# //someclient/BUILD
load("//mylib:rules.bzl", "myrule") # ok
load("//mylib:internal_defs.bzl", "helper") # error
...
Các phương pháp hay nhất về chế độ hiển thị khi tải
Phần này mô tả các mẹo quản lý nội dung khai báo về chế độ hiển thị tải.
Xem xét chế độ hiển thị
Khi nhiều tệp .bzl có cùng chế độ hiển thị, bạn nên đưa thông số kỹ thuật của gói vào một danh sách chung. Ví dụ:
# //mylib/internal_defs.bzl
visibility("private")
clients = [
"//foo",
"//bar/baz/...",
...
]
# //mylib/feature_A.bzl
load(":internal_defs.bzl", "clients")
visibility(clients)
...
# //mylib/feature_B.bzl
load(":internal_defs.bzl", "clients")
visibility(clients)
...
Điều này giúp ngăn chặn tình trạng sai lệch ngoài ý muốn giữa chế độ hiển thị của nhiều tệp .bzl. Cách này cũng dễ đọc hơn khi danh sách clients lớn.
Tạo chế độ hiển thị
Đôi khi, một tệp .bzl có thể cần hiển thị cho một danh sách cho phép bao gồm nhiều danh sách cho phép nhỏ hơn. Điều này tương tự như cách một package_group có thể kết hợp các package_group khác thông qua thuộc tính includes.
Giả sử bạn đang ngừng sử dụng một macro được dùng rộng rãi. Bạn chỉ muốn người dùng hiện tại và các gói do nhóm của bạn sở hữu mới thấy được lớp này. Bạn có thể viết:
# //mylib/macros.bzl
load(":internal_defs.bzl", "our_packages")
load("//some_big_client:defs.bzl", "their_remaining_uses")
# List concatenation. Duplicates are fine.
visibility(our_packages + their_remaining_uses)
Loại bỏ trùng lặp bằng nhóm gói
Không giống như chế độ hiển thị mục tiêu, bạn không thể xác định chế độ hiển thị tải theo package_group. Nếu bạn muốn sử dụng lại cùng một danh sách cho phép cho cả chế độ hiển thị mục tiêu và chế độ hiển thị tải, tốt nhất bạn nên di chuyển danh sách thông số kỹ thuật của gói vào tệp .bzl, nơi cả hai loại khai báo đều có thể tham chiếu đến danh sách đó. Dựa trên ví dụ trong phần Tách riêng chế độ hiển thị ở trên, bạn có thể viết:
# //mylib/BUILD
load(":internal_defs", "clients")
package_group(
name = "my_pkg_grp",
packages = clients,
)
Điều này chỉ hoạt động nếu danh sách không chứa bất kỳ thông số kỹ thuật gói phủ định nào.
Bảo vệ từng biểu tượng
Không thể tải bất kỳ biểu tượng Starlark nào có tên bắt đầu bằng dấu gạch dưới từ
một tệp khác. Điều này giúp bạn dễ dàng tạo các ký hiệu riêng tư, nhưng không cho phép bạn chia sẻ các ký hiệu này với một nhóm tệp tin cậy có giới hạn. Mặt khác, chế độ hiển thị tải cho phép bạn kiểm soát những gói khác có thể thấy .bzl file của bạn, nhưng không cho phép bạn ngăn việc tải bất kỳ ký hiệu nào không có dấu gạch dưới.
May mắn là bạn có thể kết hợp hai tính năng này để có được quyền kiểm soát chi tiết.
# //mylib/internal_defs.bzl
# Can't be public, because internal_helper shouldn't be exposed to the world.
visibility("private")
# Can't be underscore-prefixed, because this is
# needed by other .bzl files in mylib.
def internal_helper(...):
...
def public_util(...):
...
# //mylib/defs.bzl
load(":internal_defs", "internal_helper", _public_util="public_util")
visibility("public")
# internal_helper, as a loaded symbol, is available for use in this file but
# can't be imported by clients who load this file.
...
# Re-export public_util from this file by assigning it to a global variable.
# We needed to import it under a different name ("_public_util") in order for
# this assignment to be legal.
public_util = _public_util
Lỗi bzl-visibility Buildifier lint
Có một Buildifier lint đưa ra cảnh báo nếu người dùng tải một tệp từ thư mục có tên internal hoặc private, khi tệp của người dùng không nằm trong thư mục mẹ của thư mục đó. Lỗi tìm lỗi mã nguồn này có trước tính năng hiển thị tải và không cần thiết trong
không gian làm việc nơi các tệp .bzl khai báo chế độ hiển thị.