Building a Portable Emacs for Mac
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