Site Overlay

Compiling custom packages for OpenWRT

I recently wanted to run duplicity (a wonderful tool which allows rsync-style backups to a remote location with gpg encryption) on my oWRT router. Unfortunately, the tool was not included in the default oWRT packages. The only thing I could find was a 5-year-old feature request which was rejected as “Won’t fix”. So I gave it a shot and tried to cross-compile it by myself. This post will first show the general procedure how to cross-compile packages and will then deal with cross-compiling duplicity.

Deprecation notice

This article contains outdated information:

  • refers to oWRT Barrierer Breaker and not to Chaos Calmer release
  • davfs2 instructions are deprecated, see new article for updated procedure

General procedure for cross-compiling

To be sincere, I have had no clue how cross-compiling worked – and my first attempts just confirmed what was evident from so many postings on the web: cross-compiling software for embedded devices is a nightmare. But once you did it, it’s not that difficult.

Step 1: Get a build environment

If you don’t have a build environment create a directory under your home directory and download the openwrt sources into that directory. I am going to call mine ~/myowrt. We are going to work with the Barrier Breaker release.

git will now shuffle a dozen of mega bytes into your build directory. On top of that, you will need the packages which are already officially endorsed by the oWRT community:

This step will download another dozen of mega bytes into your feeds subdirectory. After this operation, your download directory should look like this:

This step has just downloaded the sources from the package feeds defined in the openwrt/feeds.conf.default file. If you issue the make menuconfig command in the openwrt root directory and navigate through the installation options, you will see, that the additional packages do not yet appear in menuconfig.

menuconfig Language section before installing packages
menuconfig Language section before installing packages

In order to make the packages available to menuconfig, we would have to issue the ./scripts/feeds/install -a commmand. But we will first add our own packages.

 Step 2: Create a directory for your custom packages

Under your ~/myowrt working directory, create an additional directory for your custom packages:

In order to tell oWRT that this directory also contains packages, you have got to edit the feeds.conf.default file. Just uncomment and adapt the last line in that file as follows:

For the sake of example, we would like to install the davfs2 package. It comes in handily that there is already a package under development on the oWRT github page. We can download the package folder with the following command (strangely the most convenient way to download a specific folder from a git repo is to use svn):

Another example – also relating to the webdav file system – is cadaver which is a very useful command line webdav client. Although it is not included in the trunk, I have found an oWRT Makefile provided by a Russian developer / blogger at erinome.net. All you have to do is click on the Get full directory link which will give you a tar file that you can download to your n~/myoowrt/custpacks directory where you hold your own package sources.

Step 3: Prepare the build

We can now issue the ./scripts/feeds install -a command.

Now run make menuconfig from the build root directory, navigate to Network / Filesystem. Select the davfs2 package to be built as a module (M).

Selecting the package for build mode in menuconfig
Selecting the package for build mode in menuconfig

Step 4: Build and enjoy

If this is the first time, you start to build something from the system sources, it is advisable to start with running a full build of the image because this will ensure that all necessary components from the toolchain which does the cross-compiling are built.

We should cd to the build root and run the make command to compile the package.

If the compile fails, make will tell you to re-run the compile with the V=s option to check what is going on. In the case of davfs2, make produces a couple of error messages concerning autoreconf. As autoreconf (a tool which best guesses the configuration for compiling) is not even needed here, we just delete the following line from ~/myowrt/custpacks/davfs2/Makefile (should be line 18 in the file):

We can then run the make package/davfs2/compile again. If the compile works fine, the binary can be found in ~/myowrt/openwrt/bin/<your_target_arch>/packages/custom. You can copy that file to any oWRT device which has the specified target architecture and install it by running opkg install davfs2_1.5.2-1_mpc85xx.ipk.

Cross-compiling duplicity

Compiling duplicity is a bit more complicated, because duplicity is written in Python. That means that we do not only have to run the compile but during the process, the compiler must then internally run the setup.py, produce the relevant duplicity files and finally repackage them into an ipk file for installation.

There is another complication: While in our davfs example, we were lucky enough to find already an oWRT package source with patches and an oWRT Makefile which (almost) ran out of the box, we have to produce these ourselves.

One handy alternative would be to install python-setuptools or python-pip, which are also available as oWRT sources from github and then just issue a command like pip install duplicity and let pip do the rest. Unfortunately, this never worked for me, so we have to go the hard way and build our duplicity package with our own Makefile and

Step 1: Inspect the package sources

Normally, it is not even necessary to have the package sources on your local compiling machine. Instead, the oWRT Makefile only contains information from where it should be downloaded. This can be seen from the first lines of the Makefile in the previous davfs2 example:

If any kind of oWRT specific adaptions of the sources are needed, this is done by patchfiles which internally modify the downloaded sources before they are compiled.

If we have to set up a Makefile and maybe some patches ourselves, the first thing we should look at are the package sources. So we just download and untar them in a temp directory to see what they include.

Step 2: Patch the setup.py file

The setup.py file is the probably most interesting one among the sources, as it would normally constitute the point of entry in a regular installation on a fully loaded Debian machine. We will create a copy of that file as setup.new and see what we can adapt.

Replace setuptools

The first thing which is going to cause trouble when cross-compiling is the import of the setuptools module in lines 25-28. The python environment which the cross-compiler offers only has the setuptools predecessor which is called distutils. Fortunately both modules have identical APIs so that we can simply replace all occurences of setuptools against distutils in these lines.

The only line in which this is not going to work is line 26, because distutils did not have any test submodule. We will therefore delete line 26 completely from the original file. After we are done with that section, it should look as follows:

Remove any references to setuptools.command.test

Given that we have completely removed the line which imported setuptools.command.test, we also have to remove any code which relies on that import. We therefore delete the whole TestCommand class in lines 72-97 (line numbers in the original file).

Additionally the packages list in lines 137-140 (line numbers in original file) contains some references to the testing class which we also delete. We will also delete any reference to the test module in lines 150-152 (line numbers in original file). After the cleanup, the final part of the setup.new file should look like this:

We can now save our modified setup.new file and run diff to produce a patch file:

The only thing we still have to change in the patch file is the header. Change the first lines so that they look as follows:

We can now create a patch directory under our duplicity custom package directory and copy that file there:

Step 3: Write an oWRT Makefile

Now comes the tricky part – at least for me as I do not have any in-depth experience with oWRT Makefiles. What I did was trying some Makefiles from the python modules which already ship with the oWRT packages. Adapting the Makefile from pysqlite worked best (though it’s not yet perfect, as we will see later). Your final Makefile should look like this:

The pysqlite package which I used as the boiler plate for creating my Makefile also contained a files subdirectory with a setup.cfg.in file. Im am not sure if we really need this file and was too lazy to read the python reference. Instead, I left it in the files subdirectory after adapting it as follows:

Step 4: Prepare the target device

As duplicity’s Python code imports the Python lockfile module, we have to make sure that this module is installed on the target device. Unfortunately, the lockfile module is – again – not included in the oWRT package repositories and we have to find a way to get them onto our oWRT device.

I also tried to compile those from source as presented above. Make will compile the lockfile sources but the resulting ipk package has a size of less then 1 kB – so something must be wrong in my configuration and I cannot find out what.

Fortunately, we can get the lockfile package on the target device the easy way this time. Simply issuing easy_install lockfile on the target device will install the package directly from the net.

Step 5: Compile and adapt the result

We are now ready to compile the package:

We can then copy the resulting ipk file from the bin/<your-arch>/packages/custom directory to the target oWRT device and install it with the opkg install command.

After the package is installed locally, there are two minor problems remaining. Firstly, the main duplicity front end file is missing in the /usr/bin directory of the target device. As the duplicity file is nothing more than an executable Python file, we can just copy that file into the /usr/bin directory from any running installation.

The second problem is that the duplicity file in this version throws an error on the target device when launched:

There is an easy solution to get rid of that Error – just delete the lines 1328-1334 from the duplicity file as suggested in this post. For those keen on a short-cut, just download the patched duplicity file from here and copy it to the /usr/bin directory on your oWRT device.