bazel: ctx.actions.symlink doesn't make relative symlink, contrary to docs

ctx.actions.symlink always makes absolute symlinks when target_path is used, regardless of whether target_path is absolute.

Bugs: what’s the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.

WORKSAPCE.bazel

BUILD.bazel

load(":rules.bzl", "example")

example(
  name = "example",
)

rules.bzl

def _example_impl(ctx):
    example1 = ctx.actions.declare_symlink("example1")
    ctx.actions.symlink(output = example1, target_path = "../..")

    example2 = ctx.actions.declare_symlink("example2")
    ctx.actions.run(executable = "ln", arguments = ["-s", "../..", example2.path], outputs = [example2])

    return DefaultInfo(
        files = depset([example1, example2])
    )

example = rule(
  implementation = _example_impl
)
$ bazel build --experimental_allow_unresolved_symlinks :example
$ ls -l bazel-bin/
lrwxrwxrwx 1 paul paul 68 Nov  4 01:06 example1 -> /home/paul/.cache/bazel/_bazel_paul/fc54cd89f1e9b3d4a2b86f2842cad4ca
lrwxrwxrwx 1 paul paul  5 Nov  4 01:06 example2 -> ../..

I expected both symlinks to be ‘’…/…" but only the latter (using executable ln) is.

Documentation: https://docs.bazel.build/versions/main/skylark/lib/actions.html#symlink

(Experimental) The exact path that the output symlink will point to. No normalization or other processing is applied. Access to this feature requires setting --experimental_allow_unresolved_symlinks.

What operating system are you running Bazel on?

Ubuntu 18.04

What’s the output of bazel info release?

4.2.1

About this issue

  • Original URL
  • State: open
  • Created 3 years ago
  • Comments: 18 (10 by maintainers)

Commits related to this issue

Most upvoted comments

This is surprising and contrary to documentation, though I will note that making symlinks to paths (as opposed to artifacts) is still experimental.

@fmeum Please see https://docs.google.com/document/d/17YIqUdffxpwcKP-0whHM6TFELN8VohTpjiiEIbbRfts/edit#heading=h.hw82qobcal5z

Basically, creating symlinks on Windows requires some extra privilege, so we decided to always use junction for “directory symlink” and only when --windows_enable_symlinks is on, we try to create file symlink (otherwise, we copy the file).

In generally, I think it’s safe to change the behaviour to what you described (IIUC):

  • If --windows_enable_symlinks is on, create symlink for both file and directory.
  • If --windows_enable_symlinks is off, create junction for directory and copy file.

Yeah, strictly speaking, that’s an alternative, but that one has a larger blast radius than a change localized to FileSystem.

The normalization was forcibly added in a729b9b4c3d with the reasoning that it would help RAM use. I don’t know more history. @meisterT maybe you remember something I don’t?

There is also 775d3a9066cd674f158652ca3c6abf2ed6cd5549 which replaced PathFragment with String specifically to support non-normalized paths, which makes me thing that doing so it the right thing to do here, too.

I ran into this as well. The issue is that, despite the documentation saying otherwise, the first thing SymlinkAction does is to turn the unresolved path into a PathFragment. The first thing a PathFragment does is to normalize the path.

I don’t know what the right answer to fix this is, but I think that’s the reason for the issue.