Currently, `brew linkage` reports linkage with system frameworks only if
they can be found on the file system. This results in this linkage not
being reported on Big Sur and newer, where system libraries are stored
in the dyld cache instead.
Let's fix that by avoiding silently ignoring system frameworks by moving
them out of `#harmless_broken_link?`. We retain the behaviour desired
from 7228e60da51392b20d55e0c087b2082b86fb3bbf by deferring checking if a
broken library is actually a system framework to just before we add it
to `@broken_dylibs`.
To see how this changes the behaviour of `brew linkage`, here's an
example with this change:
❯ brew linkage neovim
System libraries:
/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices
/usr/lib/libSystem.B.dylib
/usr/lib/libiconv.2.dylib
/usr/lib/libutil.dylib
Homebrew libraries:
/usr/local/opt/gettext/lib/libintl.8.dylib (gettext)
/usr/local/opt/libtermkey/lib/libtermkey.1.dylib (libtermkey)
/usr/local/opt/libuv/lib/libuv.1.dylib (libuv)
/usr/local/opt/luajit/lib/libluajit-5.1.2.dylib (luajit)
/usr/local/opt/luv/lib/libluv.1.dylib (luv)
/usr/local/opt/msgpack/lib/libmsgpackc.2.dylib (msgpack)
/usr/local/opt/tree-sitter/lib/libtree-sitter.0.dylib (tree-sitter)
/usr/local/opt/unibilium/lib/libunibilium.4.dylib (unibilium)
and without this change:
❯ brew linkage neovim
System libraries:
/usr/lib/libSystem.B.dylib
/usr/lib/libiconv.2.dylib
/usr/lib/libutil.dylib
Homebrew libraries:
/usr/local/opt/gettext/lib/libintl.8.dylib (gettext)
/usr/local/opt/libtermkey/lib/libtermkey.1.dylib (libtermkey)
/usr/local/opt/libuv/lib/libuv.1.dylib (libuv)
/usr/local/opt/luajit/lib/libluajit-5.1.2.dylib (luajit)
/usr/local/opt/luv/lib/libluv.1.dylib (luv)
/usr/local/opt/msgpack/lib/libmsgpackc.2.dylib (msgpack)
/usr/local/opt/tree-sitter/lib/libtree-sitter.0.dylib (tree-sitter)
/usr/local/opt/unibilium/lib/libunibilium.4.dylib (unibilium)
This test is causing some rebuilds due to failed linkage upon upgrade.
That's a problem because rebuilds won't fix the problem that the `RPATH`
check identifies.
An executable that links against @rpath-prefixed dylibs must include at least
one runtime path. This will prevent issues like the one resolved in #91485.
Caveats:
1. This won't find executables that have only recursive dylib dependencies with
@rpath prefixes.
2. This makes no attempt to resolve @rpath, @executable_path or @loader_path
dylibs, or to verify the correctness of any LC_RPATH entries, or to
otherwise simulate dlopen logic.
3. Weakly-linked dylibs are still excluded from the search for broken linkage.
The scope is narrow in order to focus on this particular problem. It is meant
only as a sanity check.
There was a previous discussion about making `brew linkage --test` fail
for unrequested dependencies (#9172). I'm not sure what the outcome of
that was, but it still seems like a good idea to try to help us find
cases of opportunistic linkage as they happen rather than when they
cause CI failures in another PR sometime later.
Let's do this by adding a `--strict` flag to `brew linkage --test`. My
intention is for `brew linkage --test --strict` failures to be warnings
rather than errors in CI, which should mitigate some of the concerns
about doing this that were raised in #9172.
The linkage check currently does nothing to check the validity of
variable-referenced libraries (prefixed with an `@`).
We could rectify that by mimicking the dynamic linker in looking up the
variable-referenced library, but this could get quite complicated.
Instead, let's let the linker do the hard work by checking if we can
`dlopen` libraries and bundles that contain variable linkage. The
`dlopen` will fail if the linker cannot resolve the variable reference.
There are at least two disadvantages to this approach relative to the
alternative suggested above:
1. This doesn't work for binary executables.
2. This doesn't identify which variable references are broken.
It's still better than not checking them at all, which is what we do
currently, and saves us from having to carry around code that parses and
verifies variable references directly.
- manually `raise Errno::ENOENT` to ensure that a keg that doesn't exist
isn't flagged as a system dependency.
- remove the inconsistent and incorrect summary messaging.
This makes use of both the existing interfaces and could use the
existing cache file but we'll create a new one and cleanup the old one
to avoid issues and use a more consistent name.
Instead of refusing to install software preemptively by assuming
multiple linkage to differing versions of the same library we now make
`brew linkage --test` verify that we don't have two versions of the
same library linked at the same time.
This will be considerably more permissive whilst checking the actual
problem that we're worried about.
Hopefully put this to bed for once and for all. Add a new method
`runtime_formulae_dependencies` which returns the `runtime_dependencies`
which have only the `Formula` objects that exist. I've checked all the
`runtime_dependencies` callers and updated them accordingly.
Also, fix a few cases where runtime dependencies were being read from
the tab when this wasn't desirable.
Rather than using the name of the keg for the key use the full path.
This provides several advantages:
- there's no need to invalidate the cache on a `brew upgrade` or
`brew switch`
- it's easier to figure out what cache entries can be removed and this
can be done whenever a keg is removed by `brew uninstall` or
`brew cleanup`.
Also, ensure that an `install` (or `reinstall`, `upgrade`) always
results in the cache being rebuilt for that keg (in case different
options were used).
Cache all the non-weak dynamic library links for a keg rather than the
result of running `brew linkage`. This means that we correctly handle
changes to e.g. what non-keg files are present on disk.