Saturday, April 11, 2015

Installing and using OpenWRT SDK on Ubuntu 64bit VM

What are we compiling for?

I have a couple of very hackable routers that I have flashed with latest version of OpenWRT -Barrier Breaker 14.07:

  1. TP-LINK TL-MR3020
    (Pocket Router with USB Port | Install Instructions | Image: openwrt-ar71xx-generic-tl-mr3020-v1-squashfs-factory.bin | I use this device to build my Weather Station)
  2. TP-LINK TL-MR3040
    (Just like MR3020 but has a built-in battery | Install Instructions | Image: openwrt-ar71xx-generic-tl-mr3040-v1-squashfs-factory.bin)
  3. Dragino MS14
    (OpenWRT wiki | Product Page | Firmware installation and instruction | Change LogFirmware Image)
All these routers have the AR9331 SoC in them which is MIPS and not MIPSel. MIPSel refers to a MIPS architecture using a little endian byte order. Since almost all MIPS microprocessors have the capability of operating with either little endian or big endian byte order, the term is used only for processors where little endian byte order has been pre-determined. So we want the mips toolchain and not mipsel toolchain. AR9331 is also used on Arduino Yún.

OpenWRT SDK is a collection of tools for cross compiling software for MIPS on an x86 PC

Installing it.

Here are the steps I executed to run OpenWRT on Ubuntu 64 bit. The latest version of OpenWRT SDK (corresponding to Barrier Breaker) needs a 64bit Linux to run on. I used a Ubuntu 64 bit virtual machine running on Windows to get this done

  1. Install VirtualBox
  2. Download Ubuntu 14.10 64-bit .vdi file from http://www.osboxes.org/ubuntu/
  3. Create a new 64 bit Ubuntu machine and while doing so, attach the downloaded and existing .VDI file to the Virtual Machine
  4. Get latest Ubuntu software lists:
    sudo apt-get update
  5. Installed guest editions, setup shared folders between Windows and Linux and set user group permissions (here is how)
  6. Install dependencies:
    sudo apt-get install build-essential subversion libncurses5-dev zlib1g-dev gawk gcc-multilib flex git-core gettext libssl-dev
    Otherwise you will get the following messages while compiling:
    Build dependency: Please install ncurses. (Missing libncurses.so or ncurses.h)
    Build dependency: Please install zlib. (Missing libz.so or zlib.h)
    Build dependency: Please install GNU awk.
    Build dependency: Please install git (git-core) v1.6.5 or later.
    Build dependency: Please install the subversion client.
  7. Download latest Barrier Breaker SDK which is a 64-bit SDK (i.e. MIPS cross compiler that runs on 64bit version of x86 PCs):
    wget http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2.tar.bz2
  8. Extract 64-bit SDK:
    bzcat OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2.tar.bz2 | tar -xvf -
  9. Edit Config-build.in in ~/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2 :

Change:
config CCACHE
     bool
     default y
to
config CCACHE
     bool
     default ""

Hello World:

Create the source file and Makefile for the helloworld program. Create the appropriate folders and the following files in it (beware, there are two makefiles):

~/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/package/helloworld/src/helloworld.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
/****************
* Helloworld.c
* The most simplistic C program ever written.
* An epileptic monkey on crack could write this code.
*****************/

#include <stdio.h>

int main(void)
{
 printf("Hell! O' world, why won't my code compile?\n\n");
 return 0;
}

------------    ------------    ------------
~/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/package/helloworld/src/Makefile

1
2
3
4
5
6
7
8
9
# build helloworld executable when user executes "make"
helloworld: helloworld.o
 $(CC) $(LDFLAGS) helloworld.o -o helloworld
helloworld.o: helloworld.c
 $(CC) $(CFLAGS) -c helloworld.c

# remove object files and executable when user executes "make clean"
clean:
 rm *.o helloworld

------------    ------------    ------------

~/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/package/helloworld/Makefile

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
##############################################
# OpenWrt Makefile for helloworld program
#
#
# Most of the variables used here are defined in
# the include directives below. We just need to
# specify a basic description of the package,
# where to build our program, where to find
# the source files, and where to install the
# compiled program on the router.
#
# Be very careful of spacing in this file.
# Indents should be tabs, not spaces, and
# there should be no trailing whitespace in
# lines that are not commented.
#
##############################################

include $(TOPDIR)/rules.mk

# Name and release number of this package
PKG_NAME:=helloworld
PKG_VERSION:=1.0.0
PKG_RELEASE:=1

# This specifies the directory where we're going to build the program.
# The root build directory, $(BUILD_DIR), is by default the build_mipsel
# directory in your OpenWrt SDK directory
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

include $(INCLUDE_DIR)/package.mk

# Specify package information for this program.
# The variables defined here should be self explanatory.
define Package/helloworld
 SECTION:=utils
 CATEGORY:=Utilities
 TITLE:=Helloworld -- prints a snarky message
endef

define Package/helloworld/description
 If you can't figure out what this program does,
 you're probably brain-dead and need immediate
 medical attention.
endef

# Specify what needs to be done to prepare for building the package.
# In our case, we need to copy the source files to the build directory.
# This is NOT the default.  The default uses the PKG_SOURCE_URL and the
# PKG_SOURCE which is not defined here to download the source from the web.
# In order to just build a simple program that we have just written, it is
# much easier to do it this way.
define Build/Prepare
 mkdir -p $(PKG_BUILD_DIR)
 $(CP) ./src/* $(PKG_BUILD_DIR)/
endef

define Build/Configure
  $(call Build/Configure/Default,--with-linux-headers=$(LINUX_DIR))
endef

# We do not need to define Build/Configure or Build/Compile directives
# The defaults are appropriate for compiling a simple program such as this one

# Specify where and how to install the program. Since we only have one file,
# the helloworld executable, install it by copying it to the /bin directory on
# the router. The $(1) variable represents the root directory on the router running
# OpenWrt. The $(INSTALL_DIR) variable contains a command to prepare the install
# directory if it does not already exist.  Likewise $(INSTALL_BIN) contains the
# command to copy the binary file from its current location (in our case the build
# directory) to the install directory.
define Package/helloworld/install
 $(INSTALL_DIR) $(1)/bin
 $(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin/
endef

# This line executes the necessary commands to compile our program.
# The above define directives specify all the information needed, but this
# line calls BuildPackage which in turn actually uses this information to
# build a package.
$(eval $(call BuildPackage,helloworld))

You can download the above source files from here. Its a good idea to fetch the files rather than copying and pasting so as to retain the proper spaces and tabs and EOLs - these are important when Makefiles are parsed.

Compiling it, Installing it, Running it on your OpenWRT device:

  1. While in ~/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2 run:
    make V=99
  2. .ipkwill be placed in ~/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/bin/ar71xx/packages/base
  3. Copy the ipk to Windows using shared folders
  4. Use WinSCP to copy helloworld_1.0.0-1_ar71xx.ipk to your OpenWRT router. (To know how to use WinSCP, go through the "Copying the executable to the router" section here)
  5. Connect to OpenWRT device using PuTTY and install the package:
    opkg install helloworld_1.0.0-1_ar71xx.ipk
  6. Execute:
    helloworld
Running helloworld

References:

  1. OpenWRT: Using the SDK http://wiki.openwrt.org/doc/howto/obtain.firmware.sdk 
  2. https://giovanni.wordpress.com/2011/01/23/how-to-cross-compile-a-c-program-for-openwrt/ 
  3. http://postwarrior.com/openwrt-please-fix-packagehelloworldmakefile-see-logspackagehelloworlddump-txt-for-details-solution/ 
  4. http://wiki.openwrt.org/doc/devel/packages 
  5. http://downloads.openwrt.org/barrier_breaker/14.07/ar71xx/generic/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2.tar.bz2 Will not work on 32bit Linux and needs 64 bit linux because the binaries in there are built to run on 64 bit. You will get an error like: find: syntax error: "(" unexpected

In case of 32-bit Ubuntu, use the older Attitude Adjustment SDK:

  • Download SDK:
    wget http://downloads.openwrt.org/attitude_adjustment/12.09/ar71xx/generic/OpenWrt-SDK-ar71xx-for-linux-i486-gcc-4.6-linaro_uClibc-0.9.33.2.tar.bz2
  • Extract SDK:
    bzcat OpenWrt-SDK-ar71xx-for-linux-i486-gcc-4.6-linaro_uClibc-0.9.33.2.tar.bz2   | tar -xvf -

In case of the newer release of OpenWRT Chaos Calmer 15.05: