bazel-contrib / bazel-contrib/bazel-lib

[FR]: `baked_binary()`

Open
#356 3 comments 0 reactions 0 assignees View on GitHub
enhancement help wanted need: funding
Dominant language
Starlark
Stars
182
Forks
134
Avg merge
1d 46m
Merged PRs (30d)
1

Description

### What is the current behavior?

In Bazel by default, executable binaries have a built-in `args` attribute, so `bazel run` will automatically use those arguments. However, the args are dropped if the binary is invoked directly via `bazel-bin/...` or in the runfiles of another binary. Quoting from https://bazel.build/reference/be/common-definitions#common-attributes-binaries:

> `args` - List of strings; optional; subject to [`$(location)`](https://bazel.build/reference/be/make-variables#location) and ["Make variable"](https://bazel.build/reference/be/make-variables) substitution, and [Bourne shell tokenization](https://bazel.build/reference/be/common-definitions#sh-tokenization); [nonconfigurable](https://bazel.build/reference/be/common-definitions#configurable-attributes)

>
> Command line arguments that Bazel will pass to the target when it is executed either by the run command or as a test. These arguments are passed before the ones that are specified on the bazel run or bazel test command line.

>
> NOTE: The arguments are not passed when you run the target outside of Bazel (for example, by manually executing the binary in `bazel-bin/`).

For some rules (such as `js_run_devserver()`) executing a binary from runfiles is required and `args` is effectively useless, since you can't guarantee it will be present. It would be great to have an easy way to ensure hard-coded arguments in the `BUILD` file are _always_ present, regardless of how the binary is executed.

### Describe the feature

I propose a new `baked_binary()` rule which takes a `baked_args` attribute and generates a wrapper binary which hard-codes those arguments, with any subsequent arguments appended after it. This means arguments are "baked" into the binary and will be retained regardless of how the binary is executed. This would look like:

```python
load("@aspect_bazel_lib//lib:baked_binary.bzl", "baked_binary")

sh_binary(
name = "server",
srcs = ["server.sh"],
data = [":site"],
# Can't rely on `args`, because it won't always be there.
# args = ["path/to/site/"],
)

baked_binary(
name = "baked_server",
binary = ":server",
# Bake the args so they are always present.
baked_args = ["path/to/site"],
)

# When this runs `./baked_server --port 1234`, `path/to/site` is already included
# and does not need to be repeated.
sh_test(
name = "test",
srcs = ["test.sh"],
data = [":baked_server"],
)
```

I made my own implementation of this in https://github.com/dgp1130/rules_prerender/commit/c0065dc2598be72120abb9ecc9bea8af20aed1ff#diff-2f9d8f02c056b3df3e9ff8b6fb76b84689e08c39773d3661dcfcd482cf13a267, though it isn't great since it requires Bash, doesn't support Windows, and needed some hacks to be compatible with `js_run_devserver()` (`chdir` messes up Bash runfiles).

### Fund our work

- [ ] Sponsor our open source work by donating a [feature bounty](https://opencollective.com/aspect-build/)

Contributor guide

Open the contributing guide

Research direction

Start by reviewing the Bazel binary args documentation and the linked rules_prerender implementation. Define the rule's expected behavior for direct execution, runfiles, appended arguments, and Windows support, then validate it against the js_run_devserver() use case described in the issue.

Written by the indexing model from the issue text.

Assessment

Tech stack
bash
Domain
build-system, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.