Cross Compiling For OpenWRT On Linux
1. Introduction
A recent project involved the development of some C code to be run on a TP-LINK TL-WR703N
router running OpenWRT. Due to the router’s limited resources, using it to compile the code was not really feasable (although probably would work, albeit slowly). It was decided to install a cross-platform development environment on a PC running Ubuntu Linux.
The process was refreshingly simple and relatively painless and is well documented in great detail on the OpenWRT website here and here.
This article summarises the steps involved for getting setting up to cross-compile specifically for the mips
platform using the OpenWRT 12.09 trunk 'Attitude Adjustment'
release, but the steps involved can be easily applied to other platforms/releases.
2. Building The OpenWRT Cross-Compilation Environment
2.1. Download The Source Files
The cross-compiler environment will be installed in /usr/local/crosscompile/openwrt
so the first step is to use the git
utility to copy the files from the OpenWRT git repository
~>cd /usr/local/crosscompile/
/usr/local/crosscompile>git clone git://git.openwrt.org/12.09/openwrt.git
You can also install the package sources with:
/usr/local/crosscompile>git clone git://git.openwrt.org/12.09/packages.git
To save space, we’ll just install the packages as required, on an individual basis. Doing this is described further on.
2.2. Doing the Build
2.2.1. Configuration
Configuration is via a menu driven UI, this is done with the command:cd /usr/local/crosscompile/openwrt
make menuconfig
The options can be left as the defaults, but ensure that you have the correct target system specified. For the TL-WR703N router, the target is Atheros AR7xxx/AR9xxx
To reset back to the default options, use the command:
make defconfig
2.2.2. Building
Now, to compile the gcc toolchain, the kernel, and the OpenWRT image and its packages, issue the command
make
If the PC has multiple cores, the process can be sped up by telling make to run multiple processes, for example:
make -j 3
It is recommended that optimally, the -j option should be specified as the number of cores plus one, so 3 for a dual core machine etc.
make
will take some time to complete (probably several hours) as it compiles the the gcc cross-compiler tools, as well as the kernel and utilites required for the OpenWRT squash-fs image that can be flashed to the router.
Once it is done, everything will be found in the /usr/local/cross-compile/openwrt/staging_dir
diretory. The gcc tools, include files and shared libraries are found in /usr/local/cross-compile/openwrt/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2
(given the Atheros AR7xxx/AR9xxx
that was used).
3. Cross Compiling
3.1. Compiling Hello World
Now that everything is in place, we can test that everything works by cross compiling the standard helloworld.c
program.
3.1.1. Setting Up The Environment
Several environment variables can be set to tell gcc where everything is, using a script is the easiest way to do this:
# Set up paths and environment for cross compiling for openwrt
export STAGING_DIR=/usr/local/cross-compile/openwrt/staging_dir
export TOOLCHAIN_DIR=$STAGING_DIR/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2
export LDCFLAGS=$TOOLCHAIN_DIR/usr/lib
export LD_LIBRARY_PATH=$TOOLCHAIN_DIR/usr/lib
export PATH=$TOOLCHAIN_DIR/bin:$PATH
Then source this script prior to doing any cross-compiling:
~>. ~/bin/openwrt.config
3.1.2. Compiling
The bog standard helloworld.c
#include <stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
is compiled with:
~>mips-openwrt-linux-gcc -o helloworld helloworld.c
and the cross-compiled executable has been created:
~>file helloworld
helloworld: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1, dynamically linked (uses shared libs),
with unknown capability 0x41000000 = 0xf676e75, with unknown capability 0x10000 = 0x70403, not stripped
This can now be copied over to the router and executed to ensure that everything has worked.
3.2. Using a Makefile
Here’s an example of a Makefile used for cross compilation:
/*
Ensure that openwrt cross-compile environment variables are set prior to calling make:
~/bin/openwrt.config
*/
TOOLCHAIN_DIR=/usr/local/cross-compile/openwrt/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2
INCLUDE_DIR=$(TOOLCHAIN_DIR)/usr/include
CC=mips-openwrt-linux-gcc
CFLAGS= -std=gnu99
LDFLAGS=-lbluetooth
SOURCES=test.c sb.c logger.c btcom.c
OBJS=$(SOURCES:.c=.o)
all: test
test.o: test.c
$(CC) -c $(CFLAGS) -I $(INCLUDE_DIR) -o $@ $<
%.o: %.c %.h
$(CC) -c $(CFLAGS) -I $(INCLUDE_DIR) -o $@ $<
test: $(OBJS)
$(CC) $(LDFLAGS) $(CFLAGS) -o test $(OBJS)
clean:
rm *.o test
Note:
- The cross-compiler is specified with the line:
CC=mips-openwrt-linux-gcc
- The bluetooth library is being linked to (this has already been cross-compiled and installed), and hence the include directory for the bluetooth header files is being explicity specified:
-I $(INCLUDE_DIR)
Also, an existing Make file can be used by specifying the flags on the command line:
make CC=mips-openwrt-linux-uclibc-gcc LD=mips-openwrt-linux-uclibc-ld
3.3. Compiling an Source Package
My recent project required linking to the Bluez Linux Bluetooth library, this is not included in the standard OpenWRT image so I needed to compile it from source.
After downloading and extracting the source archive bluez-libs-3.36.tar.gz
from the OpenWRT source code repository, it was built and installed as follows:
./configure --prefix=$TOOLCHAIN_DIR --build=mips-openwrt-linux-gnu --host=mips-openwrt-linux-uclibc
make
make install
Where mips
is the architecture. See here for further details.
I could now link with the bluetooth library using -lbluetooth
as shown in the Makefile example above.
4. Conclusion
Installing, configuring and using the OpenWRT cross compilation tools is relatively simple and well documented. Hopefully people will find this article useful in doing so quickly and easily.
Related Articles