I work with quite a few clusters, and in trying to get batch jobs running, I tend to generate many tiny files which are usually almost identical and almost useless. The rare exception is the lone non-identical file, which is invariably critical in solving a problem. Run a test job ten or fifty times, and a directory can fill up rapidly. ls and rm get annoying for large directories. So, I like to have a text-mode file manager on hand to help sort through, mark, and blow away useless cruft while identifying useful cruft.
I grew up with Midnight Commander, and I’m a creature of habit, so I set about trying to compile a copy of mc statically, so I only had to do it once for all the x86_64 clusters I deal with (and incidentally dodge the problems of differing versions of dependency libraries, lack of development libraries, and so on). Turns out that’s not so simple. One would hope that
./configure --disable-shared --enable-static
would do it. Not so much, at least not with mc. The mc binary would still be huge, but would still contain dynamic links to glib, pcre, curses, and a host of other things.
Various mailing list posts circa 2002 were unhelpful, especially those of the form “edit the Makefiles and add -static to LIBS“. Though a scientist, after a few hours the scientific process breaks down and I make more than one change at once. In other words, the following, while it worked, probably contains thoroughly unnecessary duplication of flags:
./configure --with-glib-static --without-x --disable-shared --enable-static \
CC='gcc -static -static-libgcc -fno-exceptions' \
CXX='g++ -static -static-libgcc -fno-exceptions' \
LDFLAGS='-Wl,-static -static -lc' \
LIBS='-lc'
The keys to success were:
- Specifying CC, CXX, LDFLAGS, and LIBS as command-line arguments to configure rather than environment variables. In the latter case, configure only seems to honor them occasionally.
- Putting the static linkage options into what will run as the compiler.
- When -static-libgcc is specified, an -fno-exceptions option may be necessary to avoid pulling in stack unwinding code that seems to be available only in a shared library.
- Adding LIBS='-lc', because otherwise LDFLAGS='-Wl,-static' seemed to cause the linker to miss the crt0 startup routines, which a tailing '-lc' fixes.
That generated a completely static executable. Installation wasn’t terribly straightforward, since I didn’t want to install a second copy of mc on my development box (even in my home directory), tar it up, and then clean it up. (I don’t claim this is logical; just that I simply didn’t want to do it after spending far too long trying to get a static executable.) I wound up pulling everything from my (properly installed, local) copy of mc, both from /etc/mc and /usr/share/mc, pooling it in one directory (~/etc/mc) on the clusters, and pointing mc to it with MC_DATADIR=$HOME/etc/mc (via an export MC_DATADIR=... in my .bashrc).
It should be noted that this hack depends on the presence of static link libraries for glib, ncurses/slang, and perhaps pcre. That took a little doing as well (since my development box runs Gentoo, that meant twiddling with USE flags and re-emerging some packages).