A key concept of Bazel is that of runfiles: the collection of files that a binary needs to have access to at runtime.
Runfiles are usually declared using the data
attribute and are automatically propagated from dependencies.
How a binary can find its runfiles at runtime depends on the OS: While Bazel uses a tree of symlinks on Unix systems, it
usually falls back to a manifest file on Windows. Thus, the recommended way to look up runfiles is through the runfiles
libraries provided for all major languages under @bazel_tools//tools/<lang>/runfiles
or @rules_<lang>//<lang>/runfiles
. These libraries all offer an rlocation
function that maps the runfiles path of a
file, which is of the form repository/path/to/pkg/filename
, to the actual location of the file at runtime.
This ruleset offers a convenient wrapper around the runfiles libraries that has the following advantages over using the libraries directly:
-
Compile-time safety: If your Bazel target compiles, it will find its runfiles at runtime.
-
Automatic cross-platform support:
//foo:bar
islibbar.so
on Linux, butbar.dll
on Windows? With rules_runfiles, the runfiles path of the file will be available as a constant named after the label//foo:bar
, which is independent of the particular target platform. -
IDE completions: rules_runfiles translates the Bazel package structure into generated, language-specific structures that work well with IDEs. For example,
//foo:bar
is available as::runfiles::current_repo::foo::bar
(nested namespaces) in C++ andJavaRunfilesTargetName.current_repo.foo.bar
(nested classes) in Java. -
Required for Bazel modules: With Bazel's new module system (also known as bzlmod), the internal names of repositories depend on their declared versions as well as the particular way they are loaded. Since the names are part of the runfiles paths, these paths are no longer static and thus can no longer be hardcoded. rules_runfiles uses code generation together with a naming scheme that carefully avoids the internal names of repositories to allow consistent runfiles access from modules.
The following languages are currently supported:
- C++
- Java
Support for other languages is planned, suggestions and contributions are very welcome.
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "fmeum_rules_runfiles",
sha256 = "057f42a28cccc4a27ba3d65f1b49ef734e95bd74f10c5a98d8812e7a0e663e00",
strip_prefix = "rules_runfiles-0.1.1",
url = "https://github.com/fmeum/rules_runfiles/archive/refs/tags/v0.1.1.tar.gz",
)
Create a <lang>_runfiles
target with all the data dependencies you would usually specify on your <lang>_binary
or <lang>_library
and reference it in the deps
attribute. Here, <lang>
is either cc
(C++) or java
(Java).
load("@fmeum_rules_runfiles//runfiles:<lang>_defs.bzl", "<lang>_runfiles")
<lang>_runfiles(
name = "foo_runfiles",
data = [
"data/test.txt",
"data/dir",
":other_binary",
"@other_repo//path/to/other:binary",
],
)
<lang>_binary(
name = "foo",
deps = [
":foo_runfiles",
...
],
...
)
Note:
- Since the code generated by
rules_runfiles
uses the labels listed in thedata
attribute to refer to runfiles, every label must correspond to exactly one file. Rules such as bazel-skylib'sselect_file
can be used to break up targets into individual files. - The
data
dependencies should not be repeated on the<lang>_binary
or<lang>_library
target. <lang>_runfiles
targets are only visible from the package in which they are defined. Since they contain generated code that refers to the "current package", exposing them to other packages would lead to very confusing situations. If there is a larger list of data dependencies shared between multiple targets in different packages, consider exporting the list via a Starlark constant in a.bzl
file instead.- Use of Bazel 5.1.0 or higher is recommended as lower versions of Bazel include runfiles libraries that do not always find runfiles contained in directories that are themselves runfiles when using a manifest (bazelbuild/bazel#14336).
C++: A cc_runfiles
target with name = "foo_runfiles"
provides a generated header foo_runfiles.h
that can be
included via
#include "path/to/pkg/foo_runfiles.h"
This file contains a string constant for every label in the data
attribute of the cc_runfiles
rule, organized in
namespaces. When deriving the fully-qualified name of a constant, Bazel repositories and packages map to namespaces and
non-alphanumeric characters are replaced by underscores. There are also special namespaces for the current package, the
current repository and the main repository.
Bazel label | C++ constant |
---|---|
:foo |
::runfiles::current_pkg::foo |
:dir/some-File.txt |
::runfiles::current_pkg::dir_some_File_txt |
//path/to/pkg:foo |
::runfiles::current_repo::path::to::pkg::foo |
@foobar//path/to/pkg:foo |
::runfiles::foobar::path::to::pkg::foo |
@//path/to/pkg:foo |
::runfiles::main_repo::path::to::pkg::foo |
The fully-qualified names of these constants can be shortened with using
and using namespace
directives.
Java: A java_runfiles
target with name = "foo_runfiles"
provides a generated class FooRunfiles
(name converted
to CamelCase with special characters replaced with underscores). By default, this class is contained in a package
determined from the containing Bazel package by the same rules as java_binary
's main_class
. It can be overriden with
the package
attribute on java_runfiles
.
This class contains a String
constant for every label in the data
attribute of the java_runfiles
rule, organized
in nested classes. When deriving the fully-qualified name of a constant, Bazel repositories and packages map to nested
classes and non-alphanumeric characters are replaced by underscores. There are also special nested classes for the
current package, the current repository and the main repository.
Bazel label | Java constant |
---|---|
:foo |
FooRunfiles.current_pkg.foo |
:dir/some-File.txt |
FooRunfiles.current_pkg.dir_some_File_txt |
//path/to/pkg:foo |
FooRunfiles.current_repo.path.to.pkg.foo |
@foobar//path/to/pkg:foo |
FooRunfiles.foobar.path.to.pkg.foo |
@//path/to/pkg:foo |
FooRunfiles.main_repo.path.to.pkg.foo |
The fully-qualified names of these constants can be shortened with import static
directives.
C++: No additional dependency or include is needed to access the Bazel C++ runfiles library. See its main header for usage instructions.
Java: No additional dependency is needed to access the Bazel Java runfiles library. See its main source file for usage instructions.