`brew unlink` doesn't unlink opt paths #15990

Closed
staticfloat opened this Issue Nov 12, 2012 · 13 comments

Projects

None yet

3 participants

@staticfloat
Contributor

I'm playing around with a keg-only library (openblas) that has both a stable and a HEAD version. I'm linking against the opt_paths because of #15981, but I noticed that brew unlink openblas doesn't remove the opt paths:

$ brew unlink openblas
Unlinking /Users/sabae/.homebrew/Cellar/openblas/0.2.3... 0 links removed
$ ls -l ~/.homebrew/opt/openblas/lib/
total 61064
lrwxr-xr-x  1 sabae  staff        77 Nov 11 14:29 libopenblas.a -> /Users/sabae/.homebrew/Cellar/openblas/0.2.3/lib/libopenblas_penrynp-r0.2.3.a
lrwxr-xr-x  1 sabae  staff        81 Nov 11 14:29 libopenblas.dylib -> /Users/sabae/.homebrew/Cellar/openblas/0.2.3/lib/libopenblas_penrynp-r0.2.3.dylib
-r--r--r--  1 sabae  staff  19102504 Nov 11 14:29 libopenblas_penrynp-r0.2.3.a
-r--r--r--  1 sabae  staff  12149128 Nov 11 14:29 libopenblas_penrynp-r0.2.3.dylib

The paths are, however, replaced if I brew install openblas --HEAD:

$ brew install openblas --HEAD
==> Cloning https://github.com/xianyi/OpenBLAS.git
Updating /Library/Caches/Homebrew/openblas--git
==> Checking out branch develop
==> Using Homebrew-provided fortran compiler.
This may be changed by setting the FC environment variable.
==> make CC=/usr/bin/clang -Os -w -pipe -march=native -Qunused-arguments -mmacosx-version-min=10.8 FC=/Users/sabae/.homebrew/bin/gfortran
==> make PREFIX=/Users/sabae/.homebrew/Cellar/openblas/HEAD install
==> Caveats
This formula is keg-only: so it was not symlinked into /Users/sabae/.homebrew.

Mac OS X already provides this software and installing another version in
parallel can cause all kinds of trouble.

Generally there are no consequences of this for you. If you build your
own software and it requires this formula, you'll need to add to your
build variables:

    LDFLAGS:  -L/Users/sabae/.homebrew/opt/openblas/lib
    CPPFLAGS: -I/Users/sabae/.homebrew/opt/openblas/include

==> Summary
/Users/sabae/.homebrew/Cellar/openblas/HEAD: 13 files, 31M, built in 10.9 minutes

$ ls -l ~/.homebrew/opt/openblas/lib/
total 61080
lrwxr-xr-x  1 sabae  staff        76 Nov 11 18:13 libopenblas.a -> /Users/sabae/.homebrew/Cellar/openblas/HEAD/lib/libopenblas_penrynp-r0.2.4.a
lrwxr-xr-x  1 sabae  staff        80 Nov 11 18:13 libopenblas.dylib -> /Users/sabae/.homebrew/Cellar/openblas/HEAD/lib/libopenblas_penrynp-r0.2.4.dylib
-r--r--r--  1 sabae  staff  19074992 Nov 11 18:13 libopenblas_penrynp-r0.2.4.a
-r--r--r--  1 sabae  staff  12186040 Nov 11 18:13 libopenblas_penrynp-r0.2.4.dylib

And I can swap between them by using brew link openblas and brew link openblas --HEAD. So I think the only thing weird here is that brew unlink doesn't remove the opt symlinks.

Contributor

opt paths are never removed, only replaced; they have to exist for unlinked things for keg-only deps to work right.

Contributor

opt paths are never removed, only replaced; they have to exist for unlinked things for keg-only deps to work right.

This makes sense. However there's a few oddities about working with keg-only's and optpaths:

  • When switching, one must use brew link, there's no brew optlink as far as I can find. This causes a keg-only formula to get linked into both the opt path and the HOMEBREW_PREFIX.
  • Even though there's nothing in the HOMEBREW_PREFIX, and the opt path files are overwritten, one cannot simply brew link one formula over another; there's some internal logic that forces you to brew unlink one version before you can brew link the other version. This makes sense for non-keg-only formulae, but for keg-only where brew unlink has no visible effect, I feel this could be done automatically.
Contributor

The purist in me cringes at the thought of treating kegs differently because they happen to map to a keg-only formula, because kegs are really the core layer of Homebrew. Everything else, even formulae, are just abstractions for manipulating them. Keg-onliness is enforced in the formula layer; the actual keg machinery has no such concept. This decoupling is what allows the brew command line tools (link, unlink, uninstall, etc.) to manipulate kegs without a corresponding formula.

Previously, the idea of an "active" version of a keg-only formula didn't really exist, because everything linked to keg-only libraries through the raw prefix. The opt paths changed that, and though we gained the ability to do keg-only upgrades, we obviously lost some flexibility here.

one cannot simply brew link one formula over another; there's some internal logic that forces you to brew unlink one version before you can brew link the other version. This makes sense for non-keg-only formulae, but for keg-only where brew unlink has no visible effect, I feel this could be done automatically.

I don't think what should happen here is well-defined. I'm not sure how we can discern between "I want to link this keg-only thing into the prefix" and "I want to switch the thing that the opt path points to?". And using link/unlink to manipulate keg-onlies in this way seems wrong.

Here is one potential way forward. An augmented brew switch could do the following:

  • If a keg maps to a regular formula, or does not map to a formula at all, perform a normal switch.
  • If a keg maps to a keg-only formula, AND that formula has been linked into HOMEBREW_PREFIX, perform a normal switch.
  • Otherwise, if a keg maps to a keg-only formula, only switch the opt link.
Contributor
adamv commented Nov 12, 2012

What Would Homebrew Two Do

Contributor

Yeah, basically. We should probably be keeping a list of these problems somewhere so that we do not forget them during the v2 design phase.

@ghost
ghost commented Nov 12, 2012

May I ask what is advantage of opt/#{keg_name} layout vs opt/include, opt/lib, opt/bin ... ?

Contributor

One advantage is that sometimes a keg_only library conflicts with others (hence why it is keg_only), so with a opt/#{keg_name} layout it will never conflict with any other formula.

Contributor

"opt/{lib,bin,include,...}" really already exists: HOMEBREW_PREFIX/{lib,bin,include,...} ;)

@ghost
ghost commented Nov 13, 2012

Wouldn't it be cleaner to only pass single C/CPP/LDFLAG location for all kegs ?

Contributor

That would defeat the purpose of things being keg-only, and also nullify one of the main benefits of superenv: insulating builds from undeclared dependencies.

Contributor

People who build their own software outside of Homebrew can use HOMEBREW_PREFIX/{bin,lib,include,...} for this, just as they always have, of course. That's not going away.

Contributor

Sorry this reply has been so long in coming:

Here is one potential way forward. An augmented brew switch could do the following:

  • If a keg maps to a regular formula, or does not map to a formula at all, perform a normal switch.
  • If a keg maps to a keg-only formula, AND that formula has been linked into HOMEBREW_PREFIX, perform a normal switch.
  • Otherwise, if a keg maps to a keg-only formula, only switch the opt link.

This seems like a decent fix to me, and would solve the issue at hand.

Contributor
adamv commented Nov 12, 2013

Will review a PR to change brew switch behavior.

@adamv adamv closed this Nov 18, 2013
@xu-cheng xu-cheng locked and limited conversation to collaborators Feb 16, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.