memonic

Brew Your Own

Save

Fork me on GitHub

Brew Your Own

An Experience Report







@mattscilipoti

Formula Cookbook

Save

Formula Cookbook

Basic Instructions

Before contributing, check that the package you are about to create isnt waiting to be merged by doing a search at the issue tracker.

Naturally check it already isnt in Homebrew with a search: brew search foo

Make sure you search thoroughly (all aliases!) We dont want you to waste your time.

Formula we dont accept

The mxcl fork doesnt dupe stuff that comes with OS X or stuff that is provided by RubyGems, CPAN or PyPi. There are good reasons for this:

1. Duplicate libraries regularly break builds
2. Subtle bugs emerge with duplicate libraries, and to a lesser extent, duplicate tools
3. We want you to try harder to make your formula work with what OS X comes with

We currently have a few exceptions:

Ruby People need version 1.9
Python People need version 2.7 and 3.1
Bash Version 4 is cool
Subversion For some tasks Homebrew requires a newer version than OS X 10.5 provides
Zsh This was a mistake, but its a bit late to remove it
libpng The version that is bundled with OS X has some notable crash bugs
libxml2 The version that is bundled with OS X has some notable crash bugs

If you find other dupes they should be reported and removed.

Will your formula be exempted? Possibly. Submit and justify it.

Were hoping other people will maintain forks that contain dupes. Currently AdamV is maintaining a duplicates branch.

Bindings

First check that eg. rubygems dont provide the bindings already.

If not, then put bindings in the formula they bind to. This is more useful to people. Just install the stuff! Having to faff around with foo-ruby foo-perl etc. sucks.

Niche Stuff

The software in question must be 1) maintained 2) known 3) used and 4) have a homepage.

We will reject formula that seem too obscure, partly because they wont get maintained and partly because we have to draw the line somewhere.

Dont forget Homebrew is all git underneath! Maintain your own fork if you have to!

Some Quick Examples Before You Get Started

Formulae arent that complicated. wget is as simple as it gets.

And then Git and flac show more advanced functionality.

Grab the URL

All you need to make a formula is a URL to the tarball.

brew create http://example.com/foo-0.1.tar.gz

This creates:

/usr/local/Library/Formula/foo.rb

And opens it in your $EDITOR. Itll look like:

require 'formula'

class Foo < Formula
  url 'http://example.com/foo-0.1.tar.gz'
  homepage ''
  md5 ''

# depends_on 'cmake'

  def install
    system "./configure", "--prefix=#{prefix}", "--disable-debug", "--disable-dependency-tracking"
#   system "cmake . #{std_cmake_parameters}"
    system "make install"
  end
end

Fill in the Homepage

We dont accept formulae without homepages!

Homebrew doesnt have a description field because the homepage is always up to date, and Homebrew is not. Thus its less maintenance for us. To satisfy the description were going to invent a new packaging microformat and persuade everyone to publish it on their homepage.

Fill in the MD5

 brew install -i foo

This downloads the formula and extracts it to a sandbox. Homebrew tells you the MD5 as it does this. Fill the formula in.

(Note: If brew said Warning: Version cannot be determined from URL when doing the create step, youll need to explicitly add the correct version to the formula with version 'foo' and then save the formula. brew install should then proceed without any trouble.)

Check the build system

Youre now at new prompt with the tarball extracted to a temporary sandbox.

Check the packages README. Does the package install with autotools, cmake or something else? Delete the commented out cmake lines if the package uses autotools (ie. it has a configure script).

Check for dependencies

The README probably tells you about dependencies. Homebrew or OS X probably already has them. You can check for Homebrew deps with brew search. These are the common deps that OS X comes with:

Freetype
libexpat
libGL
libiconv
libpcap
libpng
libxml2
Python
Ruby
X11

There are plenty of others. Check /usr/lib, /usr/X11/lib to see.

We try to never duplicate libraries and complicated tools. We dupe some common tools (eg scons). But generally we avoid dupes because it is a foundation of Homebrew, and because it causes build and usage problems.

We encourage you to maintain your own fork with dupes as you require them.

Specifying other formulae as dependencies

class Foo < Formula
  depends_on 'jpeg'
end

Double-check for dependencies

When you already have a lot of brews installed, its easy to miss a common dependency like glib or gettext.

You can double-check which libraries a binary links to with the otool command:

$ otool -L /usr/local/bin/ldapvi
/usr/local/bin/ldapvi:
/usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8)
/usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.3)
/usr/local/Cellar/glib/2.22.4/lib/libglib-2.0.0.dylib (compatibility version 2201.0.0, current version 2201.4.0)
/usr/local/Cellar/gettext/0.17/lib/libintl.8.dylib (compatibility version 9.0.0, current version 9.2.0)
/usr/local/Cellar/readline/6.0/lib/libreadline.6.0.dylib (compatibility version 6.0.0, current version 6.0.0)
/usr/local/Cellar/popt/1.15/lib/libpopt.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
/System/Library/Frameworks/LDAP.framework/Versions/A/LDAP (compatibility version 1.0.0, current version 2.2.0)
/usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 38.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.0.0)

Specifying gems, etc. as dependencies

Homebrew doesnt package the already packaged. If you formula needs a gem or egg, youll need to check for these external dependencies:

class Foo < Formula
  depends_on 'mg' => :ruby
  depends_on 'json' => :python
end

Check your system calls

If you call OS X provided binaries, such as bsdmake, be sure to use the full system path:
system "/usr/bin/bsdmake"

This will help prevent errors in case another version of the same tool appears in the users PATH.

Test the formula

Exit out of the interactive shell.

brew install -vd foo

The v is for verbose, the d debug. Debug mode dumps you to an interactive shell if the build fails so you can try to figure out what went wrong.

Check the top of the ./configure output, if applicable! Some configure scripts do not recognize --disable-debug. If you see a warning about it, remove the option from the formula.

Manuals

Homebrew expects to find man pages in [prefix]/share/man/... and not in [prefix]/man/....

Some software installs to man instead of share/man, so check the outputs and add a "--mandir=#{man}" to the ./configure line if needed.

Audit the formula

You can run brew audit to test formulae for adherence to Homebrew house style. This includes warnings for trailing whitespace, preferred URLs for certain source hosts, and a lot of other style issues. Fixing these warnings before committing will make the process a lot smoother for us.

Commit

Everything is built on git, so contribution is easy:

brew install git # if you already have git installed, skip this command
brew update  # required in more ways than you think (initializes the brew git repository if you don't already have it)
cd `brew --prefix`
git add Library/Formula/foo.rb
git commit

The established standard with Git is for commit messages to have a first line that is 50 characters or less and then add two newlines, and then explain the commit throughly.

This may seem crazy short, but youll find that forcing yourself to summarise the commit encourages you to be atomic and concise. If you cant summarise it in 50-80 characters, you probably are trying to commit two commits as one.

Ensure you reference any GitHub tickets if relevant in the commit message. Homebrews history is the first thing future contributors will look to when they are trying to understand the current state of formula they are interested in.

Push

Now you just need to push back to Github.

If you havent forked Homebrew yet, go to the repo and hit the fork button.

If you have already forked Homebrew on Github, then you can manually push (just make sure you have been pulling from the mxcl/homebrew master):

git push git@github.com:myname/homebrew.git

Now all that remains is to tell a Homebrew collaborator about your formula so it can be merged.

We prefer that you create a Pull Request for new and changed brews. Do not open both an issue and a Pull Request; Pull Requests automagically create their own issues. One formula to a commit, one commit to a formula. Try to keep merge commits out of the request if possible. If more than one file is touched in a commit, and the commit isnt one logical bug fix, or the same file is touched in multiple commits then we will probably ask you to rebase your commits. For this reason it is usually easier to work on brews in a separate branch, rather than doing it in your master branch mixed in with other commits.

(Keep Issues for reporting bugs, problems and suggestions.)

Managing Unix packages on OS X with Homebrew

Save

Managing Unix packages on OS X with Homebrew

The real win of Homebrew is how packages are defined: in Ruby. Have a look at this hotness for describing how to install redis:

require 'formula'

class Redis < Formula
  url 'http://redis.googlecode.com/files/redis-1.2.5.tar.gz'
  homepage 'http://code.google.com/p/redis/'
  sha1 'f28d840d8100586796cab02ccd8e91545a92179d'

  def install
    %w( run db/redis log ).each do |path|
      (var+path).mkpath
    end

    ENV.gcc_4_2
    system "make"
    bin.install %w( redis-benchmark redis-cli redis-server )
    
    # Fix up default conf file to match our paths
    inreplace "redis.conf" do |s|
      s.gsub! "/var/run/redis.pid", "#{var}/run/redis.pid"
      s.gsub! "dir ./", "dir #{var}/db/redis/"
    end
    
    etc.install "redis.conf"
  end

  def caveats
    "To start redis: $ redis-server #{etc}/redis.conf"
  end
end

Hot right? Whats more is that if you run brew update itll turn your /usr/local into a working git repository where you can tweak these scripts, push to your own fork and contribute back. Compare that to the MacPorts Portfile for redis which took me 5 minutes just to find, let alone tweak or contribute. Homebrew keeps all those files in /usr/local/Library/Formula, so have at it!

For more info on Homebrew check out their wiki or their collection of blog links as Im sure theyre more accurate than anything Id produce.

Installation

Save
github

Installation

We recommend you delete /usr/local/include and /usr/local/lib

Most likely youve done a bit of homebrew installation already. Weve had a lot of bug reports that are first inexplicable and later it turns out that its because the user has some of their own libs and headers in /usr/local. Homebrew cant stop gcc and other build tools from using these libraries. Before you install we strongly recommend you delete the contents of these two directories.

If in doubt, dont delete this stuff, but be aware that this may cause build issues.

Location

You can put Homebrew anywhere, but some choices are better than others:

  1. Avoid directories that contain spaces
    Homebrew tries to make this work, but some build scripts that formula execute dont like spaces.
  2. Avoid /opt/local and /sw
    These directories are already used by MacPorts and Fink. Some tools and build scripts expect to find things there and get confused if something else is there instead.

Do yourself a favour and pick /usr/local

  1. Its easier
    /usr/local/bin is already in your PATH.
  2. Its easier
    Tons of build scripts break if their dependencies arent in either /usr or /usr/local. We fix this for Homebrew formulas (although we dont always test for it), but youll find that many RubyGems and Python setup scripts break which is something outside our control.
  3. Its safe
    Apple has conformed to POSIX and left this directory for us. Which means there is no /usr/local directory by default, so there is no need to worry about messing up existing tools.
If you plan to install gems that depend on brews then save yourself a bunch of hassle and install to /usr/local!

It is not trivial to tell gem to look in non-standard directories for headers and dylibs. If you choose /usr/local, everything just works!

Installing to /usr/local for Developers

Homebrew will happily coexist with any existing stuff you have installed in /usr/local.

This script is the recommended way to install to /usr/local. It does a lot of checks, and makes the minimum of permissions changes to ensure you can brew without sudo.

If youre the DIY sort and know what you are doing then you can just run this:

sudo chown -R $USER /usr/local
curl -Lsf http://github.com/mxcl/homebrew/tarball/master | tar xz --strip 1 -C/usr/local

If you install via tarball and would like to track the upstream source repository via git after the fact you can do so easily. This works even if you chose to use brew to install git.

brew install git

Note you have to already have Git installed for these steps to work:
git clone http://github.com/mxcl/homebrew.git /tmp/homebrew

You should actually create a fork of the homebrew repository and maintain your own fork

git clone http://github.com/YOURGITHUBUSERNAME/homebrew.git /tmp/homebrew
mv /tmp/homebrew/.git /usr/local/
rm -rf /tmp/homebrew
cd /usr/local
git status

Sudo

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 dont 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. Its too high a risk to sudo such stuff. It could break your base system, or alter it subtly.

And indeed, I have 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?

Uninstallation

cd `brew --prefix`
rm -rf Cellar
brew prune
rm -rf Library .git .gitignore bin/brew README.md share/man/man1/brew
rm -rf ~/Library/Caches/Homebrew

It is worth noting that if you installed somewhere like /usr/local then these uninstallation steps will leave that directory exactly like it was before Homebrew was installed. Unless you manually (ie. without brew) added new stuff there, in which case those things will still be there too.

Homebrew MacPorts driving you to drink? Try Homebrew!

Save

Homebrew is the easiest and most flexible way to install the UNIX tools Apple didn't include with OS X.

$ brew install wget

Packages are installed into their own isolated prefixes and then symlinked into /usr/local.

$ cd /usr/local
$ find Cellar
Cellar/wget/1.12
Cellar/wget/1.12/bin/wget
Cellar/wget/1.12/share/man/man1/wget.1

$ ls -l bin
bin/wget -> ../Cellar/wget/1.12/bin/wget

Just extract the tarball and straight away you have a working Homebrew installation.

Create new Homebrew packages in seconds.

$ brew create http://foo.com/bar-1.0.tgz
Created /usr/local/Library/Formula/bar.rb