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.ccor //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
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", ], )
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", ], )
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(){:.external} 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! )
Avoid creating top-level directories in a project with the following names:
conditionscommand_line_optionexternalvisibilityBecause 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{:.external}
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.