Skip to content
Verified Commit e626a39d authored by Matthew Clarkson's avatar Matthew Clarkson
Browse files

fix: walk symlinks on Apple Silicon

We are now using a feature of the APE launcher to use indirect symlinks. This
allows the APE launcher to be symlinked with an `.ape` extension. The APE
launcher will remove the `.ape` extension and then launch the binary at that
path. This works really well under Bazel because it can handle creating the
indirect and direct symlink for a APE binary.

For example:

```
$ ls -l
ape-arm64.macho
awk
$ ape-arm64.macho awk --version
awk version 20240311
$ ln -s ape-arm64.macho awk.ape
$ ./awk.ape # APE launcher removes the `.ape` and executes the `awk` APE binary
awk version 20240311
```

However, Bazel requires that a rule _must_ return files that it has declared
and created. A common pattern is to simply symlink to a previously generated
file and return that through the `DefaultInfo`. This breaks the indirect
symlink because the downstream symlink can remove the `.ape` extension. Even
if the symlink includes the `.ape` extension, unless it also generates a
direct symlink for the APE launcher to find, it will fail to launch.

This patches the APE launcher to walk symlink chains back to the final symlink.

It adds a new function to the APE launcher binary: `WalkToIndirect`. The
function uses two buffers to walk the symlinks until it finds a path that is
not a symlink. The previous path _must_ be the indirect symlink. It needs to
use an additional buffer to read the linkname. It will return zero if the
new path can be stored in the provided buffer. If not, it will return the
number of bytes to allocate. We use this functionality to store the path in
the same character buffer used by the system provided environment. If there
is not enough space, we then allocate on the stack and store it there.

An alternative option is to build a launcher binary that uses runfiles to
find both the APE launcher and binary. The preference was to avoid this to
be resilient against subprocess calls that do not forward on runfiles
information. It would also require a programming language that is hermetic,
which would likely be `rules_go`. This is a heavy dependency for users
just wanting to launch APE binaries on Apple Silicon. We are _already_
requiring the download of a hermetic C toolchain on Apple Silicon so it makes
sense to reuse this download to provide the functionality needed for hermetic
launching on Apple Silicon.

This is an inperfect solution: all other platforms assimilate a single binary
that can be launched on the system. Unfortunately, due to the limitations of
the APE format on Apple Silicon, the APE launcher always needs to be in the
loop as native binaries are assimilated to ELF. The downstream user now needs
to be aware that on Apple Silicon, there are runfiles that need to be
forwarded which limits the simple message that an `ape_assimilate` generates a
native binary that can be launched. If APE learns how to generate launchable
binaries on Apple Silicon, we can switch to `_direct` from `_indirect` and
drop the `ape-m1.patch`.
parent c53415d6
Loading
Loading
Loading
Loading
  • GITLAB_TOKEN @group_3575_bot_1fa64dd2caebb37307063a803b95a420

    mentioned in commit d633a240

    ·

    mentioned in commit d633a240

    Toggle commit list
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment