blob: 78b4e593b0127b0b20c684ec7776004b3ee2b539 [file] [view]
# Bazel labels
Bazel labels are _string references_ to source files and items defined in
`BUILD.bazel` files. Their general format is:
```
@<repository_name>//<package_name>:<target_name>
```
Where:
- `@<repository_name>//` designates the directory of a named Bazel workspace.
As a convenience, this can be abbreviated as simply **`//`** for the current
workspace (the one that contains the current `BUILD.bazel` file). Note also
that **`@//`** is used to designate the project's root workspace, even when
used in external repositories.
- `<package_name>` is the package's directory path, relative to the
workspace directory. For example, in the labels `//src:main.cc` or
`//src/lib:foo`, the package names are `src` and `src/lib` respectively.
This can be empty, e.g. `//:BUILD.bazel` points to the build file in the
current workspace's top-level directory.
- For source files, `<target_name>` is the file path relative to its parent
package's directory, and may include a sub-directory part. For example for
`//src:main.cc`or `//src:extra/extra.cc`, the target name is `main.cc` and
`extra/extra.cc` respectively.
Note: Bazel _target names_ can include sub-directories, which are always
relative to the package they belong to.
- For other items, `<target_name>` corresponds to an item (build artifact,
build setting, configuration condition, etc) defined in a `BUILD.bazel`
file.
By convention, its `name` attribute _should not include a directory
separator_, except in very rare cases, to avoid confusion with sources.
Note: The Bazel documentation uses the term _target_ to refer to _any_
item that can be reached with a label. Many of these _do not correspond to_
_buildable artifacts_ (source files, build variable definitions,
configuration conditions, platform constraints, and many more).
This can be confusing to developers coming from other build systems which
differentiate the type of items in their build graph (e.g. `GN` uses
"Targets", "Configs", "Toolchains" and "Pools" to designate different
things).
Shortened expressions for labels are also supported:
- If the label begins with a repository name and does not include a colon,
it is a package path, and points to an item with the same name.
For example `//src/foo` is equivalent to `//src/foo:foo`.
- If the label begins with a colon, it is a name relative to the current
package. For example "`:bar`" and "`:extra/bar.cc`" that appear in
`src/foo/BUILD.bazel` are equivalent to `//src/foo:bar` and
`//src/foo:extra/bar.cc` respectively.
- If the label has no repository name and no colon, it is always a name
relative to the current package, even if it includes a directory separator.
E.g. "`bar/bar.cc`" in `src/foo/BUILD.bazel` always refer to
`//src/foo:bar/bar.cc`.
Note that this is not the same as `//src/foo/bar:bar.cc`
## Relative labels and package ownership
Since each source file can only belong to a single package, relative labels can
be invalid. For example, in a project that looks like the following:
```
/home/user/project/
WORKSPACE.bazel
src/
BUILD.bazel
main.cc
extra/
extra.cc
lib/
BUILD.bazel
foo.cc
foo.h
```
The `foo.cc` file belongs to the package `src/lib`, so its label _must be_
`//src/lib:foo.cc`.
Using a label like `src:lib/foo.cc` in `src/BUILD.bazel` is an error:
```py
# From src/BUILD.bazel
cc_binary(
name = "program",
srcs = [
"extra/extra.cc",
"lib/foo.cc", # Error: Label '//src:lib/foo.cc' is invalid because 'src/lib' is a subpackage
"lib/foo.h" # Error: Label '//src:lib/foo.h' is invalid because 'src/lib' is a subpackage
"main.cc",
],
)
```
## Source file access from other packages
By default, the source files of a given package cannot be accessed from
other packages, and _relative package labels are invalid_, as in:
```py
# From src/BUILD.bazel
cc_binary(
name = "program",
srcs = [
"extra/extra.cc",
"lib:foo.cc", # Error: invalid label 'lib:foo.cc': absolute label must begin with '@' or '//'
"lib:foo.h" # Error: invalid label 'lib:foo.h': absolute label must begin with '@' or '//'
"main.cc",
],
)
```
And even when using the right absolute label, and error happens:
```py
# From src/BUILD.bazel
cc_binary(
name = "program",
srcs = [
"extra/extra.cc",
"//src/lib:foo.cc", # Error: no such target '//src/lib:foo.cc': target 'foo.h' not declared in package 'src/lib'
"//src/lib:foo.h" # Error: no such target '//src/lib:foo.h': target 'foo.h' not declared in package 'src/lib'
"main.cc",
],
)
```
Direct access to files across package boundaries can be granted by `export_files()`:
```py
# From src/lib/BUILD.bazel
export_files([
"foo.cc" ,
"foo.h" ,
])
# From src/BUILD.bazel
cc_binary(
name = "program",
srcs = [
"extra/extra.cc",
"//src/lib:foo.cc", # OK
"//src/lib:foo.h" # OK
"main.cc",
],
)
```
## Target access from other packages
Labelled items defined in a `BUILD.bazel` file that are not source files
need no export, but their `visibility` attribute must allow their use
outside of their own package:
```py
# From src/lib/BUILD.bazel
cc_library(
name = " lib" ,
srcs = [ " foo.cc" ],
hdrs = [ " foo.h" ],
visibility = [ " //visibility:public" ], # Anyone can reference this directly!
)
# From src/BUILD.bazel
cc_binary(
name = "program",
srcs = [
"extra/extra.cc",
"main.cc",
],
deps = [ "lib" ], # OK!
)
```
By default, items are only visible to other items in the same package.
This can be changed by using a [`package()`][bazel-package]{:.external}
directive to change the default visibility of all items defined in a package:
```py
# From src/lib/BUILD.bazel
# Ensure that all items defined in this file are visible to anyone
package(default_visibility = ["//visibility:public"])
cc_library(
name = " lib" ,
srcs = [ "foo.cc" ],
hdrs = [ "foo.h" ],
)
# From src/BUILD.bazel
cc_binary(
name = "program",
srcs = [
"extra/extra.cc",
"main.cc",
],
deps = [ "lib" ], # OK!
)
```
## A warning about virtual packages
Avoid creating top-level directories in a project with the following names:
- `conditions`
- `command_line_option`
- `external`
- `visibility`
Because Bazel uses a number of _hard-coded "virtual packages"_ in labels within
`BUILD.bazel` files. For example:
```py
//visibility:public
//conditions:default
//command_line_option:copt
```
The case of `external` is a bit different: it does not appear in
`BUILD.bazel` files, but used internally to manage external repositories.
[This confuses Bazel when used as a project directory][bazel-external-bug]{:.external}
## Canonical repository names
Since Bazel 6.0, repository names in labels can also begin with **`@@`**.
When the optional [BzlMod][bzlmod] feature is enabled, these labels
are used as alternative but _unique_ label names for external repositories,
which becomes important when complex transitive dependency trees are used in a
project.
For example, `@@com_acme_anvil.1.0.3` could be a canonical name for the
workspace directory identified by `@anvil` in the project's own `BUILD.bazel`
files, and by `@acme_anvil` when it appears in an external repository
(e.g. inside `@foo//:BUILD.bazel`). All three labels would refer to the content
of the same directory.
Canonical repository names do not appear in `BUILD.bazel` files, however, they
will appear during the analysis phase (when executing Starlark functions that
look at label values), or when looking at the result of Bazel queries.
[bazel-package]: https://bazel.build/reference/be/functions#package
[bazel-external-bug]: https://github.com/bazelbuild/bazel/issues/16220
[bzlmod]: https://bazel.build/external/overview#bzlmod