Unraveling Homebrew Dependencies: A Handy Guide

Unraveling Homebrew Dependencies: A Handy Guide

May 29, 2023|
4 min read
  • homebrew
  • macOS
  • linux

Have you ever installed something using Homebrew and noticed the command's output updating seemingly unrelated packages? This recently happened to me, and it piqued my curiosity. As a result, I embarked on a journey to understand how package dependencies work within the Homebrew universe. This post is a friendly guide to what I've discovered, which I hope will help others navigate the complex web of package dependencies.

Setting the Scene

I installed bear, a utility that generates compilation databases for the C programming language, and surprisingly, the output indicated an update for teleport, a completely unrelated package I use to connect to our Kubernetes clusters at work. Here's the command I used:

brew install bear

I quickly realized that teleport couldn't possibly be a direct dependency of bear. This led me to hypothesize that they might share common dependencies. But how could I confirm this? Well, this turned out to be a fantastic opportunity to learn some new commands.

The Investigation

I learned about the brew uses command, which is a helpful tool for exploring what packages are using a particular package. I tested this command by checking what depends on openssl@1.1, assuming a large number of packages would. Here's what I found:

brew uses --recursive --installed openssl@1.1
apr-util     exa          gnutls       libgit2      nmap         python@3.11  tmate
autojump     ffmpeg       grpc         libpq        node         rtmpdump     tmux
bear         freetds      krb5         libssh       openldap     ruby         unbound
borgbackup   global       libevent     libssh2      php          srt          yt-dlp
curl         gnupg        libfido2     llvm         pspg         teleport

Interestingly, both bear and teleport depend on openssl@1.1. If bear and teleport share the same dependencies but require different versions, Homebrew will try to resolve this conflict.

Finding Common Ground

I then sought to understand how to use the diff command on Linux to show similarities, not differences. Despite trying many approaches, I found a more effective command that was new to me: comm. The man page for comm reads:

man comm
comm – select or reject lines common to two files

     The following options are available:

     -1      Suppress printing of column 1, lines only in file1.

     -2      Suppress printing of column 2, lines only in file2.

Let's use comm to compare the dependencies between bear and teleport:

comm -12 <(brew deps bear) <(brew deps teleport)

This produces the following output:


During the bear installation, I noticed that c-ares was updated, and Homebrew provided a hint that I had previously overlooked:

==> Upgrading 2 dependents of upgraded formulae:
Disable this behaviour by setting HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
node 19.8.1 -> 20.2.0, teleport 12.1.5 -> 13.0.3

Furthermore, teleport depends on node (which also depends on c-ares), so this could be another reason for the update.

Digging Deeper

Wanting to understand why teleport depends on c-ares, I delved further:

brew deps teleport --tree


├── libfido2
│   ├── libcbor
│   └── openssl@1.1
│       └── ca-certificates
└── node
    ├── brotli
    ├── c-ares
    ├── icu4c
    ├── libnghttp2
    ├── libuv
    └── openssl@1.1
        └── ca-certificates

It turns out that node depends on c-ares, and teleport depends on node. This interdependency was the key!


Through this exploration, I acquired valuable tools that will undoubtedly come in handy for troubleshooting Homebrew package dependencies in the future. If you ever find yourself puzzled by unexpected package updates in Homebrew, I encourage you to use these commands to unravel the mysteries of package dependencies. Remember, a deeper understanding of your tools can only make you a more effective problem-solver. Happy brewing!

Image: Markus Spiske via Unsplash

© 2023, Dorian Karter