life ideas

October 11, 2007

Writing and Compiling A Simple Program For OpenWrt

Filed under: Uncategorized — manoftoday @ 5:03 am

 

Writing and Compiling A Simple Program For OpenWrt

Written by Eric Bishop <ericpaulbishop-at-gmail.com>

Part I added 8/23/2007
Part II added 10/10/2007

Introduction

I’m writing this document because I found the documentation available on the OpenWrt wiki (http://wiki.openwrt.org) difficult to follow. I found myself in the position of wanting to compile a very simple program that I could run on my OpenWrt router. I ended up spending hours wading through the frustratingly incomplete documentation on the wiki, going through dozens of forum posts, and conducting extensive trial-and-error before my code would compile. I especially appreciated the examples on the wiki that contain the warning: “Note this Makefile is provided as an example only; it will not compile.” If something doesn’t work, it isn’t a very good example, is it? Here, then, is a (hopefully) more straightforward guide to building a program for OpenWrt. I found that existing documentation focuses more on porting existing, complicated programs to OpenWrt. My intention is to focus on getting a small, very simple, home-grown application running on OpenWrt. My goal is to explain this in as simple and complete a manner as possible, explaining each and every step necessary to write and compile a program that will run on OpenWrt. The process is actually very simple and straightforward — provided you know what you’re doing. For the purposes of this tutorial I’m going to assume you have a development box running linux and a router running OpenWrt. I will also assume you are at least somewhat familiar with C/C++ and standard Unix Makefiles.

The code for the examples in this tutorial can be downloaded from here. The example from the first part of the tutorial is in the openwrt-programming-examples/c directory and the example from the second part is in the openwrt-programming-examples/c++ directory.

Part I: A Simple Program in C

First, we’re going to need to write the code for the program itself and get it compiling on our local linux machine. Let’s write a simple “hello world” program that we want to run on the router:

~/helloworld/src/helloworld.c:

/****************
* 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;
}
	

Alright, we have our code. Note the location of this file. Make a helloworld directory and then a src subdirectory. Place the code in the src subdirectory. Now, let’s write a standard Unix Makefile to compile this code for us:

~/helloworld/src/Makefile:

# 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
	

Notice that instead of hard-coding “gcc” in the makefile to compile the program, we use a variable that holds the C compiler, $(CC). If you’re compiling a c++ program you would use $(CXX) instead of $(CC) and $(CXXFLAGS) instead of $(CFLAGS). The use of the compiler variable is not necessary to compile the code locally, but in order to compile the code for OpenWRT it is critical because we won’t be using the standard gcc compiler. Place the makefile in the same src directory our code is in. We can now go to the src directory, type “make” and the program should compile. You can run it by typing “./helloworld”

mockingbird@linuxbox:~/helloworld/src$ make
cc -c helloworld.c
cc helloworld.o -o helloworld
mockingbird@linuxbox:~/helloworld/src$ ./helloworld
Hell! O' world, why won't my code compile?

mockingbird@linuxbox:~/helloworld/src$ make clean
rm *.o helloworld
mockingbird@linuxbox:~/helloworld/src$ 
	

So far this should be a review on how to write simple C programs and how to use Makefiles. Now comes the tricky part, compiling the code so that it will run on our router. The router uses a distinctly different architecture than our linux development box. Because there isn’t enough memory/disk space on the router to install a compiler and compile the code natively, we need to “cross-compile” the code on our development box for use on the router. To do this we need a special compiler and development environment called the OpenWRT SDK. You can download the SDK from http://downloads.openwrt.org The SDK varies depending on the architecture of your development box, the architecture of your router and the version/release of OpenWrt your router is running. I currently have whiterussian v0.9 installed on my Linksys WRT54G router, and my development box is an i686, so the SDK I use is this one. Extract the SDK files from the downloaded archive, and enter the SDK directory, which should have the same name as the tar.bz2 file (in my case OpenWrt-SDK-Linux-i686-1).

mockingbird@linuxbox:~$ tar xfj OpenWrt-SDK-Linux-i686-1.tar.bz2
mockingbird@linuxbox:~$ cd OpenWrt-SDK-Linux-i686-1
mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1$ ls
dl  docs  examples  include  Makefile  package  README.SDK  rules.mk  scripts  staging_dir_mipsel
mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1$ 
	

Our goal is to build a package for OpenWrt using the source we already have. When you execute the “make” command in the SDK directory, the SDK will compile all properly configured packages in the package subdirectory under the SDK directory. The next step (and the trickiest) is to properly configure our code so that the SDK will build it. First, copy the helloworld directory we made earlier into the package subdirectory of the SDK:

mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1$ cp -r ~/helloworld package
mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1$ 
	

In order to tell the OpenWrt SDK how to build our program we need to create a special Makefile in the helloworld directory, above the src directory which contains our conventional makefile. Writing this file is 90% of the work involved in compiling our program for OpenWrt. Below is an OpenWrt makefile for building the helloworld program. Each section is heavily commented so that it should be fairly clear what is going on:

~/OpenWrt-SDK-Linux-i686-1/package/helloworld/Makefile:

##############################################
# 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_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
	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


# 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))
	

As indicated, most OpenWrt make files specify how to download the source of an application from a URL, and most documentation assumes that you want to do this. However, if you’re building your own application from scratch it doesn’t make sense to download from a URL. It’s much simpler to have the source locally and use the Build/Prepare section to copy the source to the build directory, as shown above. Also, be very careful of spacing in the Makefile. The indentation under the define sections should be tabs, not spaces and there should be no whitespace at the end of lines that are not comments. The trailing whitespace can be a problem when variables are being defined, as the compiler may think there is a space at the end of a directory name. If we’re copying something to dir_with_trailing_space/subdir the copy command may be executed as “cp my.file dir_with_trailing_space /subdir”. Not only don’t you want anything in /subdir, you probably dont have permission to create it and write to it.

Now we’re all set to compile the helloworld package. Go to the root SDK directory (if you’re not already there) and type “make V=99″ The “V=99″ option is optional, but it is useful for debugging as it instructs the compiler to be “verbose” and output all the details of what it is doing.

mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1$ make V=99
make package/compile
make[1]: Entering directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1'
Collecting package info...
make -C package compile SDK=1
make[2]: Entering directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/package'
make[2]: Leaving directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/package'
make[2]: Entering directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/package'
make -j1 compile-targets
make[3]: Entering directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/package'
make -C helloworld compile
make[4]: Entering directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/package/helloworld'
CFLAGS="-Os -pipe -mips32 -mtune=mips32 -funit-at-a-time -I/home/mockingbird/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/usr/include -I/home/mockingbird/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/include " LDFLAGS="-L/home/mockingbird/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/usr/lib -L/home/mockingbird/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/lib " make -C /home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld AR=mipsel-linux-uclibc-ar AS="mipsel-linux-uclibc-gcc -c -Os -pipe -mips32 -mtune=mips32 -funit-at-a-time" LD=mipsel-linux-uclibc-ld NM=mipsel-linux-uclibc-nm CC="mipsel-linux-uclibc-gcc" GCC="mipsel-linux-uclibc-gcc" CXX=mipsel-linux-uclibc-g++ RANLIB=mipsel-linux-uclibc-ranlib STRIP=mipsel-linux-uclibc-strip OBJCOPY=mipsel-linux-uclibc-objcopy CROSS="mipsel-linux-uclibc-" CXXFLAGS="-Os -pipe -mips32 -mtune=mips32 -funit-at-a-time -I/home/mockingbird/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/usr/include -I/home/mockingbird/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/include " ARCH="mipsel" ;
make[5]: Entering directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld'
make[5]: `helloworld' is up to date.
make[5]: Leaving directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld'
touch /home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld/.built
install -d -m0755 /home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld/ipkg/helloworld/bin
install -m0755 /home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld/helloworld /home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld/ipkg/helloworld/bin/
mkdir -p /home/mockingbird/OpenWrt-SDK-Linux-i686-1/bin/packages
find /home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld/ipkg/helloworld -name CVS | xargs rm -rf
find /home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld/ipkg/helloworld -name .svn | xargs rm -rf
find /home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld/ipkg/helloworld -name '.#*' | xargs rm -f
STRIP="/home/mockingbird/OpenWrt-SDK-Linux-i686-1/staging_dir_mipsel/bin/sstrip" STRIP_KMOD="mipsel-linux-uclibc-strip --strip-unneeded --remove-section=.comment" /home/mockingbird/OpenWrt-SDK-Linux-i686-1/scripts/rstrip.sh /home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld/ipkg/helloworld
rstrip.sh: /home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld/ipkg/helloworld/bin/helloworld:executable
ipkg-build -c -o 0 -g 0 /home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld/ipkg/helloworld /home/mockingbird/OpenWrt-SDK-Linux-i686-1/bin/packages
Packaged contents of /home/mockingbird/OpenWrt-SDK-Linux-i686-1/build_mipsel/helloworld/ipkg/helloworld into /home/mockingbird/OpenWrt-SDK-Linux-i686-1/bin/packages/helloworld_1_mipsel.ipk
make[4]: Leaving directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/package/helloworld'
make[3]: Leaving directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/package'
make[2]: Leaving directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/package'
make[1]: Leaving directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1'
( \
        cd package; \
        find . -maxdepth 2 -name Config.in | \
                sed -e 's,/Config.in,,g' | \
                xargs -r -n1 make compile -C; \
)
mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1$
	

It compiled! The new package, helloworld_1_mipsel.ipk, is now located in the bin/packages subdirectory of the root SDK directory.

mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1$ cd bin/packages
mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1/bin/packages$ ls
helloworld_1_mipsel.ipk
mockingbird@linuxbox:~OpenWrt-SDK-Linux-i686-1/bin/packages$
	

This file is a ipk file which is used by the ipkg (itsy package management) system. Ipkg is a package management system for embedded devices, where space is an issue. Let’s copy this package onto the router, which is located at 192.168.1.1 on my network.

mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1/bin/packages$ scp helloworld_1_mipsel.ipk root@192.168.1.1:
root@192.168.1.1's password: 
helloworld_1_mipsel.ipk                                                            100% 1875     1.8KB/s   00:00    
mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1/bin/packages$ 
	

Now, ssh into the router. We just copied the package to root’s home directory so we are finally ready to install our program. In root’s home directory, (where we end up immediately after connecting to the router via ssh) type “ipkg install helloworld_1_mipsel.ipk” and the ipkg system will do the rest.

mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1/bin/packages$ ssh root@192.168.1.1
root@192.168.1.1's password: 


BusyBox v1.00 (2007.01.30-11:42+0000) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 WHITE RUSSIAN (0.9) -------------------------------
  * 2 oz Vodka   Mix the Vodka and Kahlua together
  * 1 oz Kahlua  over ice, then float the cream or
  * 1/2oz cream  milk on the top.
 ---------------------------------------------------
root@OpenWrt:~# ls
TZ                       ip-up                    resolv.conf              spool
dhcp.leases              log                      resolv.conf.auto         usr
helloworld_1_mipsel.ipk  net                      run
root@OpenWrt:~# ipkg install helloworld_1_mipsel.ipk
Installing helloworld (1) to root...
Configuring helloworld
Successfully terminated.
root@OpenWrt:~# 
	

The executable has now been installed into the /bin directory on the router, per our instructions in the OpenWrt Makefile listed above. So, all we have to do to run the program is type “helloworld” at the prompt. Note that because the executable has been installed to the /bin directory you should be able to execute the program no matter what directory you are in on the router.

root@OpenWrt:~# helloworld
Hell! O' world, why won't my code compile?

root@OpenWrt:~# 
	

It works! Great success!

 

Now that you have a simple program compiling, you can start expanding on it to do whatever you want. If you run into problems I suggest you browse existing package Makefiles to see if someone else has done something similar to what you are trying to do. You can browse the files for these packages here. If you still have problems, browse the posts on the developer forum to see if anyone else has had a similar problem. If not, post your problem to the forum with a detailed explanation of what you’re trying to do, your OpenWrt Makefile and the errors you’re getting. Hopefully, some experienced developer will be kind enough to help out. Please do not email me personally if you have a problem with your code. If, however, you believe there is an error or serious omission in this tutorial, please let me know. I am relatively new to working with OpenWrt and it is certainly possible that I’ve made a mistake somewhere in this document. I have, however, personally tested all code included here on my own setup, and made every effort to be as accurate as possible.

Good luck with your programming!

Part II: C++ and the Standard Template Library (STL)

If you only want to compile C programs, the first part of my tutorial should be enough to get you started. However, if you want to use C++ there is another issue you’re likely to run into. Let’s say we want to compile the following C++ program for OpenWrt:

~/OpenWrt-SDK-Linux-i686-1/package/helloworld/src/helloworld.cpp:

/****************
* Helloworld.cpp
*****************/
#include <iostream>
#include <string>

using namespace std;

int main()
{
	string s = "Hell! O' world, why won't my c++ code run?\n\n";
	cout << s;
	return 0;
}
	

So, let’s do exactly as we did before and see what happens. We just have to update the compiler flags in the Makefile to indicate that we’re using a C++ compiler instead of a C compiler, right?

~/OpenWrt-SDK-Linux-i686-1/package/helloworld/src/Makefile:
NOTE: This code will compile but not run, further modifications are needed which are described below

# build helloworld executable when user executes "make"
helloworld: helloworld.o
	$(CXX) $(LDFLAGS) helloworld.o -o helloworld
helloworld.o: helloworld.cpp
	$(CXX) $(CXXFLAGS) -c helloworld.cpp

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

If you use the exact same OpenWrt Makefile as before, this program will compile just fine. It will even install properly when you copy the helloworld_1_mipsel.ipk file to the router and type “ipkg install helloworld_1_mipsel.ipk” However, watch what happens if you try to run the program:

root@OpenWrt:~# helloworld
helloworld: can't load library 'libstdc++.so.6'
root@OpenWrt:~#
	

So, what went wrong? The problem is that this program uses strings and iostreams which are a feature of the C++ standard template library (STL). However, because memory is so critical in an embedded application like OpenWrt, the standard template library is not available. Instead, we need to link to a special implementation of the standard library for embedded devices called uClibc++. This library implements the same functions and data structures as the standard library but takes up less memory.

Before we adjust our Makefiles to use to this alternate library, let’s first make sure that it’s installed on the router so that it is available to link to. Log into your router. Then, make sure your list of packages is up to date by using the “ipkg update” command:

root@OpenWrt:~# ipkg update
Downloading http://downloads.openwrt.org/backports/0.9/Packages
Updated list of available packages in /usr/lib/ipkg/lists/0.9-backports
Downloading http://download2.berlios.de/pub/xwrt/packages/Packages
Updated list of available packages in /usr/lib/ipkg/lists/X-Wrt
Downloading http://downloads.openwrt.org/whiterussian/packages/Packages
Updated list of available packages in /usr/lib/ipkg/lists/whiterussian
Downloading http://downloads.openwrt.org/whiterussian/packages/non-free/Packages
Updated list of available packages in /usr/lib/ipkg/lists/non-free
Successfully terminated.
root@OpenWrt:~# 
	

Once you have updated your package list, install uclibc++ by typing “ipkg install uclibc++” If you do not have uclibc++ installed this should install it:

root@OpenWrt:~# ipkg install uclibc++
Installing uclibc++ (0.1.11-2) to root...
Downloading http://downloads.openwrt.org/whiterussian/packages/uclibc++_0.1.11-2_mipsel.ipk
Configuring uclibc++
Successfully terminated.
root@OpenWrt:~# 
	

Otherwise, if the library is already installed, you’ll see this confirmation:

root@OpenWrt:~# ipkg install uclibc++
Package uclibc++ (0.1.11-2) installed in root is up to date.
Nothing to be done
Successfully terminated.
root@OpenWrt:~# 
	

Now it’s time to modify the Makefiles. First, the one in the src directory. Only a small change is necessary here, to the line where we link the objects together. We need to be able to tell the linker to link to another library, and the way we do that is by defining a variable called $(LIBS). The variable will be defined in the special OpenWrt Makefile, but will be used here, so we need to add it to the end of the line which specifies how to do the linking:

~/OpenWrt-SDK-Linux-i686-1/package/helloworld/src/Makefile:

# build helloworld executable when user executes "make"
helloworld: helloworld.o
	$(CXX) $(LDFLAGS) helloworld.o -o helloworld $(LIBS)
helloworld.o: helloworld.cpp
	$(CXX) $(CXXFLAGS) -c helloworld.cpp

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

The OpenWrt Makefile needs a slightly more complex modification. Recall the comment I placed in the OpenWrt Makefile we used before, “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.” Well, guess what? In order to link to uclibc++ we need to customize how we’re going to compile the program, and we’re going to do this in the Build/Compile directive. Before we re-define this directive to suit our purposes, let’s see what the default looks like:

TAKEN FROM: ~/OpenWrt-SDK-Linux-i686-1/include/package.mk:

define Build/Compile/Default
	CFLAGS="$(TARGET_CFLAGS) $(EXTRA_CPPFLAGS) " \
	LDFLAGS="$(EXTRA_LDFLAGS) " \
	$(MAKE) -C $(PKG_BUILD_DIR) \
		$(TARGET_CONFIGURE_OPTS) \
		CROSS="$(TARGET_CROSS)" \
		CXXFLAGS="$(TARGET_CFLAGS) $(EXTRA_CPPFLAGS) " \
		ARCH="$(ARCH)" \
		$(1);
endef
	

This code specifies the make command (the third line) and a bunch of flags and parameters for compilation. In order to link to uClibc++ we add the definition of the $(LIBS) variable as “-nodefaultlibs -lgcc -lc -luClibc++” Also, we need to specify “-nostdinc++” in the compiler flags to tell the compiler that c++ standard template library functions and data structures will be linked to in specified external libraries and not the standard libraries:

~/OpenWrt-SDK-Linux-i686-1/package/helloworld/Makefile:

##############################################
# 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_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
	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



#########################################################################################
# The Build/Compile directive needs to be specified in order to customize compilation
# and linking of our program.  We need to link to uClibc++ and to specify that we 
# do NOT want to link to the standard template library.
#
# To do this we define the LIBS variable.  To prevent linking to the standard libraries we 
# add "-nodefaultlibs" to the $(LIBS) variable and then specify "-lgcc -lc" to ensure that 
# there are no unresolved references to internal GCC library subroutines. Finally 
# "-luClibc++" to link to the  uClibc++ library.  Also, we need to specify "-nostdinc++" 
# in the compiler flags to tell the compiler that c++ standard template library functions
# and data structures will be linked to in specified external libraries and not the 
# standard libraries.
#########################################################################################
define Build/Compile
	$(MAKE) -C $(PKG_BUILD_DIR) \
		LIBS="-nodefaultlibs -lgcc -lc -luClibc++" \
		LDFLAGS="$(EXTRA_LDFLAGS)" \
		CXXFLAGS="$(TARGET_CFLAGS) $(EXTRA_CPPFLAGS) -nostdinc++" \
		$(TARGET_CONFIGURE_OPTS) \
		CROSS="$(TARGET_CROSS)" \
		ARCH="$(ARCH)" \
		$(1);
endef


# 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))
	

That’s it! That modification should be sufficient to enable linking to uClibc++. Compile it as before, copy the .ipk file to the router, install it with ipkg and run it:

mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1$ make clean
rm -rf build_* bin
mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1$ make
make package/compile
make[1]: Entering directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1'
Collecting package info...
make -C package compile SDK=1
make[2]: Entering directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/package'
make[2]: Leaving directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/package'
make[2]: Entering directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/package'
make[4] -C package compile-targets
make[5] -C package/helloworld compile
make[2]: Leaving directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1/package'
make[1]: Leaving directory `/home/mockingbird/OpenWrt-SDK-Linux-i686-1'
( \
        cd package; \
        find . -maxdepth 2 -name Config.in | \
                sed -e 's,/Config.in,,g' | \
                xargs -r -n1 make compile -C; \
)
mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1$ scp bin/packages/helloworld_1_mipsel.ipk root@192.168.1.1:
root@192.168.1.1's password: 
helloworld_1_mipsel.ipk                                                100% 2570     2.5KB/s   00:00    
mockingbird@linuxbox:~/OpenWrt-SDK-Linux-i686-1$ ssh root@192.168.1.1
root@192.168.1.1's password: 


BusyBox v1.00 (2007.01.30-11:42+0000) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

  _______                     ________        __
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
 |_______||   __|_____|__|__||________||__|  |____|
          |__| W I R E L E S S   F R E E D O M
 WHITE RUSSIAN (0.9) -------------------------------
  * 2 oz Vodka   Mix the Vodka and Kahlua together
  * 1 oz Kahlua  over ice, then float the cream or
  * 1/2oz cream  milk on the top.
 ---------------------------------------------------
root@OpenWrt:~# ipkg install helloworld_1_mipsel.ipk
Installing helloworld (1) to root...
Configuring helloworld
Successfully terminated.
root@OpenWrt:~# helloworld
Hell!  Why won't my c++ code run?
root@OpenWrt:~# 
	

It works! Our Jedi programming skills have prevailed!

Once again, please do not contact me about any issues you might have with your own programs. If, however, you think there is an error in one of my examples or that I have omitted a critical detail, please contact me and I will try to resolve the issue as soon as possible.

This tutorial is provided under the Creative Commons License, version 3.0.

Source: Writing and Compiling A Simple Program For OpenWrt

About these ads

43 Comments »

  1. thx!! it is so useful for my :)

    Comment by Merou — October 13, 2008 @ 7:45 am

  2. for me… sry!!

    Comment by Merou — October 20, 2008 @ 9:12 am

  3. Thanks! This explains it very well. Maybe it should be included in the wiki over at the OpenWRT site?

    Comment by D Brown — January 6, 2009 @ 12:08 am

  4. Plas, plas, plas…

    Really the best and the simple comes ever together…

    Next step, learn how to link libraries, (as /usr/lib/libusb) on our programs.

    Saludos, OSCAR.

    Comment by Oscar — March 6, 2009 @ 12:08 pm

  5. im having problems with cpp example:

    /jffs/bin/helloworld: line 2: ELF44: not found
    /jffs/bin/helloworld: line 3: $: VT102not found
    /jffs/bin/helloworld: line 4: syntax error: “(” unexpected

    Comment by simakas — March 18, 2009 @ 12:35 pm

  6. Vielen Dank
    I have test the c example AND
    root@76-17:/bin# ./helloworld
    Hell! O’ world, why won’t my code compile?
    root@76-17:/bin#

    now i can take-off

    thx from germany

    Comment by hexxs — May 8, 2009 @ 12:54 pm

  7. Hi,

    I am planning to port Dynamic Source routing protocol on linksys router. But before that i want to modify the code to add some extra metric and packets.
    Can you please tell me where to find the source code package which is easy to modify(i.e have commented codes)
    Please help.

    Comment by ANand — June 10, 2009 @ 12:20 pm

  8. I have to apply https://dev.openwrt.org/ticket/2508 changes to make my code compiled with recent openwrt-sdk

    Comment by xasima — November 26, 2009 @ 4:11 pm

    • you can add a DEPENDS:=+libc row in the a Package description as well

      Comment by Gábor Molnár — September 11, 2013 @ 2:49 pm

  9. One may need to apply
    >> opkg update
    >> opkg install uclibcxx

    in the recent version of openwrt (kamikaze)

    Comment by xasima — November 26, 2009 @ 4:20 pm

  10. Hi there.
    Thank you for a great post. It was very helpfull.
    Anyone reading this post should bookmark this guys contents.

    I have a new PC and needed some installation help so i went over to http://www.InstallSoftware.com but they did not provide me with the in depth
    info this guy did. he kicks all the bigger sites’ butts.

    Thanks Again

    Comment by InstallSoftware — February 1, 2010 @ 7:41 pm

  11. I am trying your helloworld script on kamikaze/8.09.2/brcm-2.4/OpenWrt-SDK-brcm-2.4-for-Linux-x86_64.tar.bz2

    I can compile the progam by using the mipsel-linux-gcc bianary.

    But I got errors when trying to create package with make.

    Collecting package info: package/helloworldERROR: please fix package/helloworld/Makefile

    What can I do to debug this? any ideas?

    Comment by Jonas — February 18, 2010 @ 12:30 pm

  12. If you are using the last release of Kamikaze (8.0.2) SDK, you have to erase this part of the code in the makefile:

    DESCRIPTION:=\
    If you can’t figure out what this program does, \\\
    you’re probably brain-dead and need immediate \\\
    medical attention.

    inside the “define Package/helloworld”

    Instead of you have to type:

    define Package/helloworld/description
    (tab)
    endef

    Regards!

    Comment by alejo — March 19, 2010 @ 11:35 pm

  13. Nice article, however, your choice of fonts hurts my eyes.

    Comment by Bryan — May 21, 2010 @ 2:32 pm

  14. thanks

    Comment by edi — July 3, 2010 @ 10:04 am

  15. Thanks Alot . It was very useful for my project

    Comment by cj — August 26, 2010 @ 5:31 am

  16. it’s really a very Nice article.

    suppose i want to use same prog. how I debug this program. I really appreciate your suggestion …..

    Comment by ankur singh — November 15, 2010 @ 2:32 pm

  17. Can anybody guide me on how to link libraries during compilation?

    I’m trying with the method specified in c++ section to link libpcap but with no success.

    Thanks,
    Hardik

    Comment by Hardik Desai — November 22, 2010 @ 3:28 am

  18. Hey!

    The building process is successfull, the install on OpenWrt too, but as i want to run it, i get this. What could be the problem? I changed only the DESCRIPTION.

    /bin/helloworld: line 1: syntax error: “(” unexpected

    Comment by János — March 19, 2011 @ 1:34 pm

  19. Thanks so much for this post — it was very useful !!

    For the latest openWRT Backfire, 10.03, I had to make the change to the Description section as outlined above, and also add a CONFIG_PACKAGE_helloworld=y to the .config file (since there is no SDK, unless you make your own) as I was working in the main tree.

    Hope this helps !!

    Thanks again — this saved me oodles of time.

    Comment by Karl Garcia — April 1, 2011 @ 4:54 am

  20. hi..

    thanxx 4 d post.. but when i try to compile the program im getting the following error.. it might be a simple error but im not able to make it out..

    root@OpenWrt:~# opkg install helloworld_1_mips.ipk
    Collected errors:
    * Packages were found, but none compatible with the architectures configured

    trying to cross compile with a kamikaze 8.09

    regards,
    priya

    Comment by priya — December 13, 2011 @ 8:57 am

  21. I do agree with all the ideas you have presented in your post.
    They’re very convincing and will certainly work. Still, the posts are very short for beginners. Could you please extend them a bit from next time? Thanks for the post.

    Comment by get laid in san francisco — November 12, 2012 @ 8:46 pm

  22. I pay a visit everyday some websites and information sites to read posts, except this website
    gives feature based writing.

    Comment by short films — November 20, 2012 @ 2:01 am

  23. This blog was… how do you say it? Relevant!! Finally I
    have found something which helped me. Kudos!

    Comment by Krista — November 21, 2012 @ 2:10 am

  24. Very good blog! Do you have any helpful hints for aspiring writers?
    I’m hoping to start my own blog soon but I’m a little lost on everything.
    Would you suggest starting with a free platform like WordPress or go for a paid option?
    There are so many options out there that I’m totally overwhelmed .. Any recommendations? Cheers!

    Comment by casino online — January 2, 2013 @ 4:22 pm

  25. WOW just what I was searching for. Came here by searching for austin tx auto insurance

    Comment by jocuri gratis masini — January 31, 2013 @ 8:44 am

  26. A person essentially lend a hand to make severely
    articles I might state. That is the first time I frequented your web page and thus far?
    I surprised with the analysis you made to make this particular publish incredible.
    Great task!

    Comment by pornographic videos xxx — February 1, 2013 @ 2:29 am

  27. When someone writes an post he/she keeps the idea of a user in his/her brain that how a user can be aware of it.
    Thus that’s why this post is amazing. Thanks!

    Comment by Debbie — April 12, 2013 @ 4:00 am

  28. This was a really great post, thanks for providing a tutorial for everyone. When I run make, I first get the following warning that I am ignoring for now: “WARNING: your configuration is out of sync. Please run make menuconfig, oldconfig or defconfig!”. Then I get an error “Package helloworld is missing dependencies for the following libraries: libc.so.6″. I already have build-essential installed. I can see that libc.so.6 is in the /lib directory…

    Comment by Dave — May 2, 2013 @ 4:48 pm

    • have you sorted out the problem? i am having the same issue, ANYONE?

      Comment by HelloWorld — September 27, 2013 @ 8:45 pm

  29. Hello! Do you know if they make any plugins to
    assist with Search Engine Optimization? I’m trying to get my blog to rank for some targeted keywords but I’m not seeing very good results.
    If you know of any please share. Thank you!

    Comment by Doyle — May 6, 2013 @ 9:47 am

  30. After looking at a few of the blog articles on your website,
    I seriously appreciate your way of blogging. I book-marked
    it to my bookmark webpage list and will be checking back
    soon. Please visit my website too and let me know your opinion.

    Comment by breast actives reviews 2013 — July 14, 2013 @ 7:25 pm

  31. As you search for firestone pool umbrella repair centers
    and other related goodyear pool umbrella repair stores, full molded auto carpets,
    pool umbrella repair east new york, hair wax styling and information.

    And consider a windshield treatment to help repeal water and
    make it nearly impossible to see.

    Comment by swimming pool cleaning Katy — July 29, 2013 @ 3:53 am

  32. Gave you a click on that ad,,,hope you get the cent.

    Comment by Damien — August 14, 2013 @ 2:55 pm

  33. Your mode of telling everything in this article is really good,
    every one be able to effortlessly know it, Thanks a lot.

    Comment by Pozdrowienia z Kaszub — September 3, 2013 @ 2:08 pm

  34. I am really enjoying the theme/design of your web site.
    Do you ever run into any internet browser compatibility issues?
    A small number of my blog readers have complained about my blog not working correctly in Explorer but looks great in Chrome.
    Do you have any solutions to help fix this problem?

    Comment by Helaine — September 20, 2013 @ 4:23 am

  35. […] Writing and Compiling A Simple Program For OpenWrt […]

    Pingback by Blog J.Schweiss | Dragino — December 12, 2013 @ 7:05 pm

  36. Dam good work Bro

    Comment by Manish — December 31, 2013 @ 6:12 am

  37. I have a code that fetch the MAC address, intime and outtime of WIFI enabled devices like smartphones, laptops whenever they visit my network, it works fine on my laptop configured with ubuntu. but now I want this program to run on a wifi router and send me the collected information on my server, So I want to ask you that can i access the router’s Wifi Interface and make it work in the monitor mode to scan the network. In my laptop, i need to have the root privileged to do this, so how can i make this program run whenever I start the router and stop the program when the router is turned off. Also , I don’t want router to provide any Internet connectivity as it will be working in monitor mode.
    Q1. Is it possible to make the router, send me collected information simultaneously on my server, if i have coded it in the program?
    Q2. The code i have developed uses my headerfiles so is there enough space on router to store the program and files?
    Q3. Can you suggest me the perfect router and the OpenWRT version suitable for my project, i am using dell vostro with core2duo,2 gb ram, ubuntu 12.10 32-bit, so what SDK should be used?
    Thank You

    Comment by Manish — December 31, 2013 @ 6:32 am

  38. Hi,
    I am using a TP-Lnk WR703n router with openwrt installed. I am enquiring if there is sample lua script code available for building packages on this operating cube. Please keep in mind that the size of the operating system is only 4MB flash memory.

    Comment by Fred — March 3, 2014 @ 6:49 pm

  39. Howdy would you mind letting me know which webhost you’re working with?
    I’ve loaded your blog in 3 different browsers and I must say this blog loads a lot faster then most.

    Can you suggest a good web hosting provider at a honest price?
    Thanks a lot, I appreciate it!

    Comment by crossfit gym — March 29, 2014 @ 7:10 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: