Bazel 8 `$(location)` expands to `$(execpath)` under `bazel build`
- Dominant language
- Java
- Stars
- 25.8k
- Forks
- 4.6k
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 75
Description
### Description of the bug:
Under Bazel 8, `bazel build` expansions of [`$(location)`](https://bazel.build/reference/be/make-variables#predefined_label_variables) for targets in external repositories match `$(execpath)` instead of `$(rootpath)`, which breaks some existing `BUILD` targets.
Under `bazel run`, expansions of `$(location)` match `$(rootpath)` instead.
There are two workarounds:
- Update all affected `$(location)` expansions to use `$(rootpath)` instead. This is backwards compatible to Bazel 6.5.0.
- Apply the [`--legacy_external_runfiles`](https://bazel.build/reference/command-line-reference#flag--legacy_external_runfiles) flag to restore the previous behavior, whereby expansions of `$(rootpath)`, `$(execpath)`, and `$(location)` are identical.
#### Background
I'd first noticed the problem when working on bazelbuild/rules_scala#1652, and committed the `$(rootpath)` fix in
bazelbuild/rules_scala#1678. The message for bazelbuild/rules_scala@08ab275 contains notes on my investigation at the time.
Then @shs96c mentioned that he'd encountered the same problem in [a #general thread in the Bazel Slack workspace on 2025-02-03](https://bazelbuild.slack.com/archives/CA31HN1T3/p1738598104277129). @fmeum mentioned the connection to `--legacy_external_runfiles` in the same thread.
### Which category does this issue belong to?
External Dependency
### What's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.
Repro repo: [mbland/bazel-8-location](https://github.com/mbland/bazel-8-location)
```txt
git clone https://github.com/mbland/bazel-8-location.git
cd bazel-8-location
./run-reproduction.sh
```
### Which operating system are you running Bazel on?
macOS Sequoia 15.3 (24D60)
### What is the output of `bazel info release`?
release 8.0.1
### If `bazel info release` returns `development version` or `(@non-git)`, tell us how you built Bazel.
_No response_
### What's the output of `git remote get-url origin; git rev-parse HEAD` ?
```text
```
### If this is a regression, please try to identify the Bazel commit where the bug was introduced with bazelisk --bisect.
_No response_
### Have you found anything relevant by searching the web?
_No response_
### Any other information, logs, or outputs that you want to share?
The output from `run-reproduction.sh` will contain the following (edited out from all of the Bazel messages):
```txt
$ ./run-reproduction.sh
-----------
Bazel 7.5.0
-----------
From `bazel build //:build-expansions`:
execpath: external/_main~_repo_rules~org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
rootpath: external/_main~_repo_rules~org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
location: external/_main~_repo_rules~org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
From `bazel run //:run-expansions`:
execpath: external/_main~_repo_rules~org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
rootpath: external/_main~_repo_rules~org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
location: external/_main~_repo_rules~org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
-----------
Bazel 8.0.1
-----------
From `bazel build //:build-expansions`:
execpath: external/+_repo_rules+org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
rootpath: ../+_repo_rules+org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
location: external/+_repo_rules+org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
From `bazel run //:run-expansions`:
execpath: external/+_repo_rules+org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
rootpath: ../+_repo_rules+org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
location: ../+_repo_rules+org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
-------------------------------------------
Bazel 8.0.1 with --legacy_external_runfiles
-------------------------------------------
From `bazel build //:build-expansions`:
execpath: external/+_repo_rules+org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
rootpath: external/+_repo_rules+org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
location: external/+_repo_rules+org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
From `bazel run //:run-expansions`:
execpath: external/+_repo_rules+org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
rootpath: external/+_repo_rules+org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
location: external/+_repo_rules+org_apache_commons_commons_lang3_3_5/commons-lang3-3.5.jar
```
#### Analysis
All of the expansions in question are for targets in external repositories.
The reproduction shows that prior to Bazel 8, expansions of `$(location)`, `$(rootpath)`, and `$(execpath)` are identical. All of them begin with `external/`, whether running `bazel build` or `bazel run`.
Under Bazel 8, by default, expansions of `$(rootpath)` now begin with `../`, and expansions of `$(execpath)` begin with `external/`. However, expansions of `$(location)` depend on the Bazel command:
| Command | `$(location)` expands to | which starts with |
| :-: | :-: | :-: |
| `bazel build` | `$(execpath)` | `external/` |
| `bazel run` | `$(rootpath)` | `../` |
Setting the `--legacy_external_runfiles` flag to `true` will restore the behavior whereby all expansions are identical and begin with `external/`.
#### Conclusion
Arguably, users should always use `$(rootpath)` to expand targets in external repositories (unless they're using `$(rlocationpath)` with a runfiles library). The [predefined source/output path variable documentation](https://bazel.build/reference/be/make-variables#predefined_label_variables) even mentions:
> The `rootpath` of a file in an external repository `repo` will start with `../repo/`, followed by the repository-relative path.
At the same time, `bazel build` should probably expand `$(location)` to match `$(rootpath)`, just as `bazel run` already does.
Contributor guide
Research direction
Start with the linked mbland/bazel-8-location reproduction and run run-reproduction.sh to compare Bazel 7.5.0 and 8.0.1 under bazel build and bazel run, including --legacy_external_runfiles. Trace the external-repository $(location) expansion behavior; done means the build and run results follow the intended rootpath semantics or the documented behavior is corrected.
Written by the indexing model from the issue text.
Assessment
- Domain
- build-system
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100