https://github.com/fmeum/rules_runfiles
Compile-time safe runfiles access for Bazel
https://github.com/fmeum/rules_runfiles
bazel rules runfiles
Last synced: 12 months ago
JSON representation
Compile-time safe runfiles access for Bazel
- Host: GitHub
- URL: https://github.com/fmeum/rules_runfiles
- Owner: fmeum
- License: apache-2.0
- Created: 2021-11-21T21:59:18.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2022-12-13T10:50:19.000Z (over 3 years ago)
- Last Synced: 2025-03-20T22:15:17.648Z (about 1 year ago)
- Topics: bazel, rules, runfiles
- Language: Starlark
- Homepage:
- Size: 85 KB
- Stars: 18
- Watchers: 4
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Compile-time safe runfiles access for Bazel
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//runfiles`
or `@rules_///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` is `libbar.so` on Linux, but `bar.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++
and `JavaRunfilesTargetName.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.
## Usage
### Step 0: `WORKSPACE` setup
```starlark
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",
)
```
### Step 1: Declaring a `_runfiles` target
Create a `_runfiles` target with all the data dependencies you would usually specify on your `_binary`
or `_library` and reference it in the `deps` attribute. Here, `` is either `cc` (C++) or `java` (Java).
```starlark
load("@fmeum_rules_runfiles//runfiles:_defs.bzl", "_runfiles")
_runfiles(
name = "foo_runfiles",
data = [
"data/test.txt",
"data/dir",
":other_binary",
"@other_repo//path/to/other:binary",
],
)
_binary(
name = "foo",
deps = [
":foo_runfiles",
...
],
...
)
```
Note:
* Since the code generated by `rules_runfiles` uses the labels listed in the `data` attribute to refer to runfiles,
every label must correspond to exactly one file. Rules such
as [bazel-skylib's `select_file`](https://github.com/bazelbuild/bazel-skylib/blob/6e30a77347071ab22ce346b6d20cf8912919f644/rules/select_file.bzl#L39)
can be used to break up targets into individual files.
* The `data` dependencies should not be repeated on the `_binary` or `_library` target.
* `_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
(https://github.com/bazelbuild/bazel/issues/14336).
### Step 2: Accessing the runfiles constants
**C++**: A `cc_runfiles` target with `name = "foo_runfiles"` provides a generated header `foo_runfiles.h` that can be
included via
```c++
#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.
### Step 3: Using the Bazel runfiles libraries
**C++**:
No additional dependency or include is needed to access the Bazel C++ runfiles library.
See [its main header](https://github.com/bazelbuild/bazel/tree/master/tools/cpp/runfiles/runfiles_src.h) for usage instructions.
**Java**:
No additional dependency is needed to access the Bazel Java runfiles library.
See [its main source file](https://github.com/bazelbuild/bazel/tree/master/tools/java/runfiles/Runfiles.java) for usage instructions.
## Examples
* [cc_runfiles](tests/cc_runfiles)
* [java_runfiles](tests/java_runfiles)