Skip to content

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

@mbland

Description

@mbland

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions