A Grand Adventure: compiling transmission on my home router

My home router is running a Linux firmware that uses Optware for package management. For various reasons I needed to get Transmission 2.42 running on it. The only pre-built packages I could find were for versions 2.41 and 2.61, so I decided to embark on the grand adventure of compiling C programs on my router.

The ipkg can be downloaded here: transmission_2.42-1_mipsel.ipk

For anyone not familiar with Optware, it's essentially the Debian packaging system set up to install all packages into the /opt directory. This is useful for embedded systems (such as routers) where the root filesystem is backed by nvram. The /opt directory can be placed on a flash or hard drive to avoid writing to nvram too often.

Setting Out For GCC

Understanding how C/C++ development is done under UNIX systems is a key piece of knowledge for systems administrators. The finer points of C programming are not as important in practice, but it behooves nerdlings embarking on the great UNIX Odyssey to know how things work from a bird's eye view. Note to self: this would make a great blog post. For now let's just assume we're all familiar with the standard "./configure; make; make install" stuff.

To get the development toolchain under Optware, I simply installed the optware-devel package. This meta-package got me all the standard UNIX build tools: gcc, make, etc. I started working with the directions provided on the nslu2-linux.org site for compiling packages but ran into a morass of issues-- probably because instead of cross-compiling from a Linux desktop I was attempting to compile packages straight on my router. Why? Because I can! :)

The Dangers of /opt/bin vs. /bin binaries

First I changed my PATH to /opt/sbin:/opt/bin:/sbin:/bin:/usr/sbin:/usr/bin so that the optware binaries would be preferred to the busybox binary in /bin. This got me most of the functionality I wanted, but I noticed that the stripped down busybox programs were still being preferred in some cases. So I took a look in /opt/bin.

I have a feeling that I did something wrong at some point with my installation, because all of the standard GNU binaries that I installed into /opt/bin were prefixed with their package name. For example, instead of /opt/bin/find I have /opt/bin/findutils-find. To work around this I just created the appropriate symlinks as needed. YMMV.

Libraries, libraries everywhere...

One of the things about optware is that it completely avoids touching anything in the standard /bin, /usr/bin, etc. directories and places everything in /opt. For shared libraries this leads to a slightly different configuration where you have some libraries under /lib, and some under /opt/lib. Normally this wouldn't be a problem, but because of the small CPU and RAM footprint of embedded systems the libc in /lib is actually different from the libc in /opt/lib. This can lead to all sorts of weirdness.

You can see how the system is configured for this by looking at the LD_LIBRARY_PATH environment variable. On my system it was set to "/lib:/opt/lib", which seems perfectly reasonable at first glance. But it completely broke my build environment. The solution is simply to "unset LD_LIBRARY_PATH".

With the system's build environment working, it was easy to download and install the version of Transmission that I needed.

Compiling Transmission

These days most UNIXy programs are using GNU autoconf. Autoconf is a set of scripts to help abstract away the differences between different operating systems and allow programs to be compiled for Linux, BSD, Solaris, and so on.

Protip: never run your ./configure command by hand. Inevitably you'll come back to the program later and need to recompile it. Create a shell script with your configure command and keep it in the directory program. I usually call it do_configure.sh.


# The gtk directory was missing from my download, so
# I just hacked around it by touching the required Makefiles.
mkdir -p gtk/icons
touch gtk/Makefile.in
touch gtk/icons/Makefile.in

./configure --build=mips-unknown-linux-gnu --prefix=/opt --disable-nls --enable-lightweight --enable-cli --enable-daemon

The options explained:
  • --build=mips-unknown-linux-gnu -- specify the build architecture
  • --prefix=/opt -- install everything under /opt
  • --disable-nls -- disable native language support (unsupported on this system)
  • --enable-lightweight -- turn on transmission specific options for small systems
  • --enable-cli -- enable the command line interface
  • --enable-daemon -- enable the daemon
Once the configure has completed, it's just a matter of running make.

Building the ipkg

There's a handy script called ipkg-build.sh that you can use to build the actual ipkg. The official Debian package new maintainer's guide may be helpful in explaining how the various files and directories work in more detail. It's also handy to keep around if you run any Debian/Ubuntu systems.

I hope this blog post helps others who decide to embark on the adventure of compiling programs on their embedded systems that use Optware. Which each individual problem that I came across wasn't too complex, the fact that I kept running into issue after issue made the project rather daunting. A home router makes a great file server, VPN server, and firewall combo. And it's much nicer to leave running all the time than a big overclocked gaming PC. :)

No comments: