When writing custom Bazel rules, you spend a lot of time either
reading or writing Bazel File objects.
File objects have two properties for accessing the underlying
file path: File.path and File.short_path. When
writing custom rules, I often chose one of the two properties at
random, and switched to the other if it didn’t work right.
I wrote some simple custom rules to test the various combination
of rule types and file types to determine when I should use path
or short_path. The custom rules used bash script templates
that were populated with file paths, such as:
# my_build.bzl
def _impl(ctx):
exe = ctx.actions.declare_file("{}-build.sh".format(ctx.label.name))
ctx.actions.write(
output = exe,
content = """#!/bin/bash
set -euo pipefail
set -x
cp {src} {out}
""".format(
src = ctx.file.src.path, # .short_path breaks for generated files
out = ctx.outputs.out.path, # .short_path doesn't work
),
is_executable = True,
)
ctx.actions.run(
inputs = ctx.files.src,
outputs = [ctx.outputs.out],
executable = exe,
)
my_build = rule(
implementation = _impl,
attrs = {
"src": attr.label(mandatory = True, allow_single_file = True),
"out": attr.output(mandatory = True),
},
)
Here are the results of the test:
| File Type | Build Rule | Test Rule | Executable Rule |
|---|---|---|---|
| Input file, on-disk | Either path or short_path works |
Either path or short_path works |
Either path or short_path works |
| Input file, generated | path |
short_path |
short_path |
| Output file | path |
N/A | N/A |
The above table can be simplified to the following rules:
| Bazel Rule Type | Always Use |
|---|---|
| build | path |
| test | short_path |
| executable | short_path |
My test code can be found at at https://github.com/sengelha/practical_bazel_examples/tree/master/path_or_short_path