A visitor, Rakkesh, stopped by with a question about Building Emacs 24.4 From Source on the Mac. He had an issue that when he built Emacs on one machine (a Mac-Mini Server) the resulting application would not run on another (his laptop). He wrote:

Is there anyway I can create a self contained Emacs.app bundle which can be redistributed on all my machines without installing any additional dependencies, such as, gnutls, libxml2 - the latest versions from Homebrew, on those machines?

The problem occurs because Emacs’ build process will greedily take advantage of any libraries it can find installed on the build system. If you’ve installed something the build considers useful like gnutls or libxml2, it will link against them. However, results in an executable that always loads those libraries and won’t run on systems that don’t also have them installed.

I replied:

If you’d like to try, look at “install_name_tool”. In theory you could copy the .dylib files you need into the bundle and then use it to change the paths in “Emacs.app/Contents/MacOS/Emacs” to point to the bundled versions.

This idea take advantage of two features of OS X:

First, the existence of install_name_tool. When a program is compiled, the paths to the shared libraries it requires are effectively hardcoded in the binary. (This is an important security feature. On some OSs, the process of executing a binary searched for shared libraries, and it was possible to insert arbitrary code by putting a replacement library ahead of the real one in the search path.) Because the location of shared libraries can change and no one wants to have to recompile everything, install_name_tool exists to change the paths of shared libraries in binaries.

Second, the fact that “application” on OS X are really a specialized directory. If you were to cd /Applications/Emacs.app/Contents and poke around, you see that all of the components of Emacs live there in an arrangement that mirrors the layout of the UNIX file system.

So, that explains my theory. Frankly, I figured that in practice it would turn out to be more trouble than it was worth. However, based on that suggestion Rakkesh found a script emacs-build-macosx which solved the problem.

First, the script builds Emacs as you would from the command line. Then it finds any shared libraries outside of the standard OS X locations, copies them into the application directory. Finally, it uses install_name_tool to update the Emacs executable with the new paths to those libraries.

emacs-build-macosx is opinionated, it installs a few patches the author likes, including ns-toggle-fullscreen patch, which allows you do toggle fullscreen mode from within Emacs. It also builds a installer style DMG to make it easy to install on multiple machines, which is, of course, is the point. If this isn’t to your liking, fork the repo and express your own opinion!

While emacs-build-macosx isn’t something I’d normal need, it’s certainly useful if you want to build a portal Emacs and bundle it in to an easy to distribute package. Perhaps even more importantly, it’s an excellent example of how to make Mac Applications portable by including they shared libraries they depend on.

Comments