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 currentBUILD.bazelfile). 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.ccor//src/lib:foo, the package names aresrcandsrc/librespectively.This can be empty, e.g.
//:BUILD.bazelpoints 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.ccor//src:extra/extra.cc, the target name ismain.ccandextra/extra.ccrespectively.For other items,
<target_name>corresponds to an item (build artifact, build setting, configuration condition, etc) defined in aBUILD.bazelfile.By convention, its
nameattribute should not include a directory separator, except in very rare cases, to avoid confusion with sources.This can be confusing to developers coming from other build systems which differentiate the type of items in their build graph (e.g.
GNuses "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/foois 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 insrc/foo/BUILD.bazelare equivalent to//src/foo:barand//src/foo:extra/bar.ccrespectively.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" insrc/foo/BUILD.bazelalways 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:
# 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:
# 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:
# 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():
# 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:
# 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()
directive to change the default visibility of all items defined in a package:
# 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:
conditionscommand_line_optionexternalvisibility
Because Bazel uses a number of hard-coded "virtual packages" in labels within
BUILD.bazel files. For example:
//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
Canonical repository names
Since Bazel 6.0, repository names in labels can also begin with @@.
When the optional 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.