Skip to content

Feature request: visibility-like capability for bzl files (rules, aspects, and macros) #11261

@dgoldstein0

Description

@dgoldstein0

Description of the problem / feature request:

Today, if you want to restrict the usage of a bazel target, you can use visibility to do so. A simple example:

filegroup(
  name = "foo",
  visibility = ["//visibility:private"],
  srcs = ...
)

In the above, :foo can only be referenced by other targets in the same package. There are of course ways to indicate other packages and subpackages are allowed to use a target.

bzl files, and their contents (rules, macros, aspects, etc) have no such capability. Any .bzl file in your workspace, can be load()ed by any other bzl file or BUILD file. There is one hack, however, you can use to restrict the effective visibility of a rule: you can add a private attr.label attribute that points to a target of limited visibility. This however is going to give a somewhat confusing error message about that target not being visible when the rule is used somewhere it doesn't belong. But in some cases that may be an ok workaround.

Feature requests: what underlying problem are you trying to solve with this feature?

One particular use case which is not served by this, is the ability to make a macro which is usable anywhere, use a rule that you want restricted. E.g. something like

def foo(name, ...):
  foo_internal(name, ...)
  bar(name + "_bar", ...)

In such a case, you may want to expose the inner rules - foo_internal and bar - so that some of your tests can use them; but you may want all other consumers forced to use foo. Currently, none of bazel's restriction mechanisms support this use case.

some thoughts on a possible solutions

The obvious choice for the api is to mirror existing visibility capabilities somehow, though this has a few problems:

  • terminology wise, .bzl files aren't packages, and shouldn't have their own package() declarations. This is easy enough to work around though if we can agree on an alternate name . Maybe bzl_settings() which could also support default_visibility? and if we wanted to go further and have a way to make rules/macros/aspects testonly, we could throw in default_testonly
  • while aspect and rule could be extended to have a visibility parameter, it's less obvious what to do with macros, as macros just look like functions.
    • A possible, extreme answer would be to introduce a macro function, that takes an implementation pointing to the existing functions. The good news is, this would be easy to adopt via codemods, though is more verbose than the status quo. It may even have benefits for stardoc, as it could give a place to add more metadata about macros, like the expected types of different parameters.
    • An alternative idea is to have some sort of psuedo-rule that could declare the visibility of the macro - e,g, a macro_visibility(...) could declare the effective visibility for the foo macro:
def foo(name, ...):
  macro_visibility(["//visibility:public"])
  foo_internal(...)
  bar(...)

foo_internal = rule(
  visibility = ["//tools/foo/tests:__subpackages__"],
  implementation = ...
  attrs = ...
  doc = "foo_internal does <something useful>.  It's is intended to be used everywhere via the foo() macro",
)

For any version of this api to be useful, the "visibility" of macros would have to be enforced in the loading phase, or load into a rule that could error on visibility during analysis; and the visibility of rules within macros would have to be compared to bzl file that contained the macro, not the package that the rule ends up within after the loading phase.

Metadata

Metadata

Assignees

Labels

P1I'll work on this now. (Assignee required)team-Starlark-IntegrationIssues involving Bazel's integration with Starlark, excluding builtin symbolstype: feature request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions