bazelbuild / bazelbuild/bazel

Bazel 8 `$(location)` expands to `$(execpath)` under `bazel build`

Open
#25,198 0 comments 0 reactions 0 assignees View on GitHub
team-Core type: bug untriaged
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.