Description of the bug:
Under Bazel 8, bazel build expansions of $(location) 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 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 bazel-contrib/rules_scala#1652, and committed the $(rootpath) fix in
bazel-contrib/rules_scala#1678. The message for bazel-contrib/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. @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
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 ?
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):
$ ./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 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.
Description of the bug:
Under Bazel 8,
bazel buildexpansions of$(location)for targets in external repositories match$(execpath)instead of$(rootpath), which breaks some existingBUILDtargets.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_runfilesflag to restore the previous behavior, whereby expansions of$(rootpath),$(execpath), and$(location)are identical.Background
I'd first noticed the problem when working on bazel-contrib/rules_scala#1652, and committed the
$(rootpath)fix inbazel-contrib/rules_scala#1678. The message for bazel-contrib/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. @fmeum mentioned the connection to
--legacy_external_runfilesin 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
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 releasereturnsdevelopment versionor(@non-git), tell us how you built Bazel.No response
What's the output of
git remote get-url origin; git rev-parse HEAD?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.shwill contain the following (edited out from all of the Bazel messages):$ ./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.jarAnalysis
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 withexternal/, whether runningbazel buildorbazel run.Under Bazel 8, by default, expansions of
$(rootpath)now begin with../, and expansions of$(execpath)begin withexternal/. However, expansions of$(location)depend on the Bazel command:$(location)expands tobazel build$(execpath)external/bazel run$(rootpath)../Setting the
--legacy_external_runfilesflag totruewill restore the behavior whereby all expansions are identical and begin withexternal/.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 even mentions:At the same time,
bazel buildshould probably expand$(location)to match$(rootpath), just asbazel runalready does.