Sunday, March 2, 2014

The Path to Homebrew

The home page and documentation for Homebrew show how to install and use Homebrew. However, they currently don't seem to explain exactly how pathing works. This can trip up a lot of newcomers, who might give up on Homebrew or fumble around the internet and land on bad advice - such as using sudo and editing /etc/paths. All of this is unnecessary and potentially dangerous.

You just really need to understand a few basic concepts:
  • Never run brew as sudo. Not "sudo brew install" nor "sudo brew link".
  • The "Cellar" is a place that all your "kegs" go. Homebrew installs packages to their own directory (in the Cellar) and then symlinks their files into /usr/local/.
  • Change /usr/local/* to be owned by $USER, not root, so you can have write permissions and not need sudo.
  • The $PATH entry for /usr/local/bin should occur before /usr/bin.
Here's an example of installing Python and setting paths correctly. I'm using OS X 10.9.2 (Mavericks) and Homebrew 0.9.5:
    
 $ sudo chown -R $USER /usr/local/*
 $ brew doctor
 $ brew update
 $ brew install python --with-brewed-openssl
 $ ls /usr/local/Cellar/python
 2.7.6
 $ python
 >>> 2.7.5
Wait, I expected to see python 2.7.6 now. What happened?
 $ which python
 /usr/bin/python
But the Homebrew docs said we will be using a symlink from /usr/local/bin/ that points at the Cellar instead of using /usr/bin:
 $ ls -l /usr/local/bin/python
 lrwxr-xr-x 1 rkulla admin 33 Mar 2 06:37 /usr/local/bin/python ->
 ../Cellar/python/2.7.6/bin/python
Aha. So it must be a PATH issue:
 $ echo PATH
 /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

 $ cat /etc/paths
 /usr/bin
 /bin
 /usr/sbin
 /sbin
 /usr/local/bin
When using Homebrew, we actually now want to change the position of /usr/local/bin to be before /usr/bin in $PATH. But don't edit /etc/paths. Instead edit ~/.bashrc and prepend /usr/local/bin to $PATH, like:
 PATH=/usr/local/bin:$PATH
Next, run:
 $ source ~/.bashrc
 $ echo $PATH
 $ /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
Don't worry that there's duplicate entries for /usr/local/bin. It doesn't matter. What matters is that you've modified your PATH safely and ultimately cleaner than the other ways.
 $ ls -l $(which python)
 lrwxr-xr-x 1 rkulla admin 33 Mar 2 06:37 /usr/local/bin/python ->
 ../Cellar/python/2.7.6/bin/python
Yay! And if you ever want to use the old python you can just run: /usr/bin/python.

Best of all from now on whenever you need to install anything with brew, you can just run:
 $ brew install whatever
and not have to fumble with permissions or worry about overwriting any global system files.

I also like to source ~/.bashrc from ~/.bash_profile. For why see: .bash_profile vs .bashrc

11 comments:

  1. Very nice article Ryan! I followed your tut exactly and still getting this:
    $ node -v
    v0.10.29
    $ which node
    /usr/local/bin/node
    $ npm install -g grunt-cli
    -bash: npm: command not found

    $ echo $PATH
    /Users/MacBook/.rbenv/shims:~/.rbenv/shims:/usr/local/opt/php55/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/heroku/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Users/MacBook/.rvm/bin

    I install everything via Homebrew. Also, I moved the stuff in my .bash_profile to .bashrc. Any suggestions, please? This thing is driving me crazy! Thanks.

    ReplyDelete
  2. I didn't install node from homebrew, but it this looks like it might help you https://stackoverflow.com/questions/21223168/brew-install-node-error

    Otherwise, try the (still?) recommended way of installing node:
    git clone http://github.com/joyent/node/
    cd node
    ./configure && make && sudo make install

    ReplyDelete
  3. It looks like `brew prune` made the trick:
    I ran `brew uninstall node` and then `brew prune`, then `brew install node` and voilĂ ! Thanks.

    ReplyDelete
  4. Hi Ryan,

    I'm new to homebrew, so am interested - is there any reason why you suggest NOT using homebrew with sudo? I'm from a Linux background, and so any changes to packages require elevation to root.

    It would seem the disadvantage to running homebrew as the current user is that you then have to change permissions on /usr/bin/local. Are there advantages to this approach?

    Thanks

    ReplyDelete
  5. There's always some potential danger in using root level requirements. Whenever it's more secure to avoid it, it's best avoided, even if it's mainly just so you don't have to type a password every time you do something with home brew. From the homebrew faq:

    "Why does Homebrew say sudo is bad?

    tl;dr Sudo is dangerous, and you installed TextMate.app without sudo anyway.

    Homebrew is designed to work without using sudo. You can decide to use it but we strongly recommend not to do so. If you have used sudo and run into a bug then it is likely to be the cause. Please don’t file a bug report unless you can reproduce it after reinstalling Homebrew from scratch without using sudo.

    You should only ever sudo a tool you trust. Of course, you can trust Homebrew ;) But do you trust the multi-megabyte Makefile that Homebrew runs? Developers often understand C++ far better than they understand make syntax. It’s too high a risk to sudo such stuff. It could break your base system, or alter it subtly.

    And indeed, we’ve seen some build scripts try to modify /usr even when the prefix was specified as something else entirely.

    Did you chown root /Applications/TextMate.app? Probably not. So is it that important to chown root wget?

    If you need to run Homebrew in a multi-user environment, consider creating a separate user account especially for use of Homebrew."

    ReplyDelete
  6. I followed the above steps and got the same results however if I open a new shell my $PATH is
    /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/git/bin:/usr/texbin

    Only when I run
    $ source ~/.bashrc

    Is my $PATH
    /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/git/bin:/usr/texbin

    Am I supposed to do $ source ~/.bashrc everytime? Isn't it supposed to load it at start up?

    ReplyDelete
  7. Joonz. Oh no. That's actually the reason why at the end of the article I mentioned that I like to source ~/.bashrc from ~/.bash_profile.

    ReplyDelete
  8. thank you. I was having trouble installing the vips dependency py2cairo and the python path was the reason for failure with No such file for directory.

    ReplyDelete
  9. Thanks - homebrew should put this front and centre on their site! Simple, but very useful info.

    ReplyDelete
  10. Thanks for the blog, wish I read it a few months ago! One question: why /usr/local/bin should occur before /usr/bin? for speed of executing programs installed with Homebrew?

    ReplyDelete
  11. ...I'm running OSX, and use MacPorts. The MacPorts documentation specifically says NOT to install anything in /usr/local because MacPorts uses that...but Homebrew installs in that directory anyway! why...?

    ReplyDelete

Followers