Skip to content

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

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

    team-CoreSkyframe, bazel query, BEP, options parsing, bazelrctype: buguntriagedHas not yet been seen by appropriate subteam

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions