OpenWrt building packages howto
About the OpenWrt SDK
This howto is for people who would like to port/package applications to OpenWrt with the OpenWrt Software Development Kit (SDK).
When using the SDK you don't require a full buildroot. The SDK is a stripped down version of it, which includes the toolchain and all the required library and header files to cross-compile applications for OpenWrt.
Requirements
- a recent GNU/Linux distribution
- GNU Make (at least 3.80 with the Debian patch)
- wget
- patch
These packages suffice for the "Hello world" program described below
Using the OpenWrt SDK
TIP: Before you begin porting your own package to OpenWrt, check if it has not been already done by someone else. To check that browse the subversion repository of the development version in your web browser and see if the package is already there. Don't do the work twice.
Let's start with porting and packaging the well known "Hello world" program as an example.
Obtaining and installing the SDK
The SDK can be downloaded from http://downloads.openwrt.org/whiterussian/newest/.
Download it into your home directory (don't use the root account) and untar the tarball. After that change into the new directory.
cd ~ wget http://downloads.openwrt.org/whiterussian/newest/OpenWrt-SDK-Linux-i686-1.tar.bz2 bzcat OpenWrt-SDK-Linux-i686-1.tar.bz2 | tar -xvf - cd ~/OpenWrt-SDK-Linux-i686-1
Creating the directories
Create the following directories:
cd ~/OpenWrt-SDK-Linux-i686-1 mkdir -p package/helloworld/ipkg mkdir -p package/helloworld/patches
Directories and their contents:
#!CSV Directory; Description ipkg; Control file which contains information about your package patches; Patch files for example 100-foo.patch
TIP: To compile more than one package in a special order do:
cd ~/OpenWrt-SDK-Linux-i686-1 mkdir -p package/100-packagename/ipkg mkdir -p package/100-packagename/patches mkdir -p package/200-packagename/ipkg mkdir -p package/200-packagename/patches
Creating the required files
TIP: If you intend to 'copy & paste' the text from this Wiki to create files on your system, then use the Unix command
unexpandto translate the leading spaces into tabs.
unexpand --first-only - >package/helloworld/Config.in
After pasting it into a text editor, press
ENTERand then
CTRL-Dkeys to save the file.
You can also create your own files in the
package/helloworlddirectory (for example config files). That files you can access in your
package/helloworld/Makefilewith
./filenameand copy it to your
$(PKG_INSTALL_DIR)directory.
package/helloworld/Config.in
config BR2_PACKAGE_HELLO
prompt "hello............................. The classic greeting, and a good example"
tristate
default m if CONFIG_DEVEL
help
The GNU hello program produces a familiar, friendly greeting. It
allows non-programmers to use a classic computer science tool which
would otherwise be unavailable to them.
*
Seriously, though: this is an example of how to do a Debian package.
It is the Debian version of the GNU Project's `hello world' program
(which is itself an example for the GNU Project).
http://www.wheretofindpackage.tld
You need to create a Config.in file. It identifies the package name. In the above example BR2_PACKAGE_HELLO identifes that this is a 'BR2'(??) formatted 'PACKAGE' whose name is 'HELLO'. The final executable is 'hello'.
package/helloworld/Makefile
The Makefile determines the way the software package is shipped. Basically we can divide the software into 2 main categories :
- C (or ANSI-C) programs
- shipped with configure script
- shipped with Makefile script (with references to gcc or $(CC) )
- sources files only
- C++ programs
- potentially uClibc++ linkables
- not uClibc++ linkables
TIP: Use the
md5sumcommand to create the
PKG_MD5SUMfrom the original tarball. Use
@SF/hello(choose a and expanded random SourceForge mirror) for the
PKG_SOURCE_URLwhen your program has a download location on SourceForge.
If PKG_SOURCE_URL and PKG_SOURCE are correctly identified, then the file will be downloaded into the ~/OpenWrt-SDK-Linux-i686-1/dl/ directory. It will be expanded into the ~/OpenWrt-SDK-Linux-i686-1/build_mipsel/ directory for compilation and processing.
Sample Makefile for C/C++ programs shipped with configure script
include $(TOPDIR)/rules.mk
PKG_NAME:=hello
PKG_VERSION:=2.1.1
PKG_RELEASE:=1
PKG_MD5SUM:=70c9ccf9fac07f762c24f2df2290784d
PKG_SOURCE_URL:=ftp://ftp.cs.tu-berlin.de/pub/gnu/hello \
http://mirrors.sunsite.dk/gnu/hello \
http://ftp.gnu.org/gnu/hello
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_CAT:=zcat
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_INSTALL_DIR:=$(PKG_BUILD_DIR)/ipkg-install
include $(TOPDIR)/package/rules.mk
$(eval $(call PKG_template,HELLO,$(PKG_NAME),$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
$(PKG_BUILD_DIR)/.configured: $(PKG_BUILD_DIR)/.prepared
(cd $(PKG_BUILD_DIR); \
$(TARGET_CONFIGURE_OPTS) \
CFLAGS="$(TARGET_CFLAGS)" \
CPPFLAGS="-I$(STAGING_DIR)/usr/include -I$(STAGING_DIR)/include" \
LDFLAGS="-L$(STAGING_DIR)/usr/lib -L$(STAGING_DIR)/lib" \
*/configure \
--target=$(GNU_TARGET_NAME) \
--host=$(GNU_TARGET_NAME) \
--build=$(GNU_HOST_NAME) \
--prefix=/usr \
--without-libiconv-prefix \
--without-libintl-prefix \
--disable-nls \
);
## Add software specific configurable options above
## See : ./configure --help
touch $@
$(PKG_BUILD_DIR)/.built:
rm -rf $(PKG_INSTALL_DIR)
mkdir -p $(PKG_INSTALL_DIR)/usr/bin
$(MAKE) -C $(PKG_BUILD_DIR)/src \
$(TARGET_CONFIGURE_OPTS) \
prefix="$(PKG_INSTALL_DIR)/usr"
$(CP) $(PKG_BUILD_DIR)/src/hello $(PKG_INSTALL_DIR)/usr/bin
touch $@
$(IPKG_HELLO):
install -d -m0755 $(IDIR_HELLO)/usr/bin
$(CP) $(PKG_INSTALL_DIR)/usr/bin/hello $(IDIR_HELLO)/usr/bin
$(RSTRIP) $(IDIR_HELLO)
$(IPKG_BUILD) $(IDIR_HELLO) $(PACKAGE_DIR)
mostlyclean:
make -C $(PKG_BUILD_DIR) clean
rm $(PKG_BUILD_DIR)/.built
Sample Makefile for C/C++ software shipped with a Makefile containing references to gcc or $(CC)
If you Makefile contains harcoded "gcc" commands, then you will have to patch the makefile and replace gcc with $(CC) in order to define at "make time" the cross-compiler to use.
/!\ Note this Makefile is provided as an example only; it will not compile
include $(TOPDIR)/rules.mk
PKG_NAME:=hello
PKG_VERSION:=2.1.1
PKG_RELEASE:=1
PKG_MD5SUM:=70c9ccf9fac07f762c24f2df2290784d
PKG_SOURCE_URL:=ftp://ftp.cs.tu-berlin.de/pub/gnu/hello \
http://mirrors.sunsite.dk/gnu/hello \
http://ftp.gnu.org/gnu/hello
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_CAT:=zcat
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_INSTALL_DIR:=$(PKG_BUILD_DIR)/ipkg-install
include $(TOPDIR)/package/rules.mk
$(eval $(call PKG_template,HELLO,$(PKG_NAME),$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
$(PKG_BUILD_DIR)/.configured: $(PKG_BUILD_DIR)/.prepared
#Since there is no configure script, we can directly go to the building step
touch $@
$(PKG_BUILD_DIR)/.built:
rm -rf $(PKG_INSTALL_DIR)
mkdir -p $(PKG_INSTALL_DIR)/usr/bin
#Note here that we pass cross-compiler as default compiler to use
$(MAKE) -C $(PKG_BUILD_DIR)/src \
CC=$(TARGET_CC) \
$(TARGET_CONFIGURE_OPTS) \
prefix="$(PKG_INSTALL_DIR)/usr"
$(CP) $(PKG_BUILD_DIR)/src/hello $(PKG_INSTALL_DIR)/usr/bin
touch $@
$(IPKG_HELLO):
install -d -m0755 $(IDIR_HELLO)/usr/bin
$(CP) $(PKG_INSTALL_DIR)/usr/bin/hello $(IDIR_HELLO)/usr/bin
$(RSTRIP) $(IDIR_HELLO)
$(IPKG_BUILD) $(IDIR_HELLO) $(PACKAGE_DIR)
mostlyclean:
make -C $(PKG_BUILD_DIR) clean
rm $(PKG_BUILD_DIR)/.built
Sample Makefile for C/C++ programs without makefiles (usually one or two source files)
/!\ Note this Makefile is provided as an example only; it will not compile
include $(TOPDIR)/rules.mk
PKG_NAME:=hello
PKG_VERSION:=2.1.1
PKG_RELEASE:=1
PKG_MD5SUM:=70c9ccf9fac07f762c24f2df2290784d
PKG_SOURCE_URL:=ftp://ftp.cs.tu-berlin.de/pub/gnu/hello \
http://mirrors.sunsite.dk/gnu/hello \
http://ftp.gnu.org/gnu/hello
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_CAT:=zcat
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_INSTALL_DIR:=$(PKG_BUILD_DIR)/ipkg-install
include $(TOPDIR)/package/rules.mk
$(eval $(call PKG_template,HELLO,$(PKG_NAME),$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
$(PKG_BUILD_DIR)/.configured: $(PKG_BUILD_DIR)/.prepared
#Since there is no configure script, we can directly go to the building step
touch $@
$(PKG_BUILD_DIR)/.built:
rm -rf $(PKG_INSTALL_DIR)
mkdir -p $(PKG_INSTALL_DIR)/usr/bin
$(TARGET_CC) $(PKG_BUILD_DIR)/src/$(PKG_NAME).c -o $(PKG_BUILD_DIR)/$(PKG_NAME) ## -lyourlib #Note we directly call the cross-compiler and define its output
$(CP) $(PKG_BUILD_DIR)/src/hello $(PKG_INSTALL_DIR)/usr/bin
touch $@
$(IPKG_HELLO):
install -d -m0755 $(IDIR_HELLO)/usr/bin
$(CP) $(PKG_INSTALL_DIR)/usr/bin/hello $(IDIR_HELLO)/usr/bin
$(RSTRIP) $(IDIR_HELLO)
$(IPKG_BUILD) $(IDIR_HELLO) $(PACKAGE_DIR)
mostlyclean:
make -C $(PKG_BUILD_DIR) clean
rm $(PKG_BUILD_DIR)/.built
Sample Makefile for C++ shipped with configure script, and uClibc++ linkables
/!\ Note this Makefile is provided as an example only; it will not compile
include $(TOPDIR)/rules.mk
PKG_NAME:=hello
PKG_VERSION:=2.1.1
PKG_RELEASE:=1
PKG_MD5SUM:=70c9ccf9fac07f762c24f2df2290784d
PKG_SOURCE_URL:=ftp://ftp.cs.tu-berlin.de/pub/gnu/hello \
http://mirrors.sunsite.dk/gnu/hello \
http://ftp.gnu.org/gnu/hello
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_CAT:=zcat
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_INSTALL_DIR:=$(PKG_BUILD_DIR)/ipkg-install
include $(TOPDIR)/package/rules.mk
$(eval $(call PKG_template,HELLO,$(PKG_NAME),$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH)))
$(PKG_BUILD_DIR)/.configured: $(PKG_BUILD_DIR)/.prepared
(cd $(PKG_BUILD_DIR); \
$(TARGET_CONFIGURE_OPTS) \
CFLAGS="$(TARGET_CFLAGS)" \
CPPFLAGS="-I$(STAGING_DIR)/usr/include -I$(STAGING_DIR)/include" \
LDFLAGS="-L$(STAGING_DIR)/usr/lib -L$(STAGING_DIR)/lib" \
*/configure \
CXXFLAGS="$(TARGET_CFLAGS) -fno-builtin -fno-rtti -nostdinc++" \
CPPFLAGS="-I$(STAGING_DIR)/usr/include -I$(STAGING_DIR)/include" \
LDFLAGS="-nodefaultlibs -L$(STAGING_DIR)/usr/lib -L$(STAGING_DIR)/lib" \ #do not use default libraries since we want uClibc++ linking
LIBS="-luClibc++ -lc -lm -lgcc" \ # You may need to add other libraries : lpcap, lssl ... #
--target=$(GNU_TARGET_NAME) \
--host=$(GNU_TARGET_NAME) \
--build=$(GNU_HOST_NAME) \
--prefix=/usr \
--without-libiconv-prefix \
--without-libintl-prefix \
--disable-nls \
);
## Add software specific configurable options above
## See : ./configure --help
touch $@
$(PKG_BUILD_DIR)/.built:
rm -rf $(PKG_INSTALL_DIR)
mkdir -p $(PKG_INSTALL_DIR)/usr/bin
$(MAKE) -C $(PKG_BUILD_DIR)/src \
$(TARGET_CONFIGURE_OPTS) \
prefix="$(PKG_INSTALL_DIR)/usr"
$(CC) $(PKG_BUILD_DIR)/src/hello $(PKG_INSTALL_DIR)/usr/bin
touch $@
$(IPKG_HELLO):
install -d -m0755 $(IDIR_HELLO)/usr/bin
$(CP) $(PKG_INSTALL_DIR)/usr/bin/hello $(IDIR_HELLO)/usr/bin
$(RSTRIP) $(IDIR_HELLO)
$(IPKG_BUILD) $(IDIR_HELLO) $(PACKAGE_DIR)
mostlyclean:
make -C $(PKG_BUILD_DIR) clean
rm $(PKG_BUILD_DIR)/.built
package/helloworld/ipkg/hello.control
The control file, as you might have guessed, controls the package information reported by ipkg.
Anyone familiar with Debian packaging will be aware of the format - a deeper description than provided here is available in the ipkg documentation.
Package: hello Priority: optional Section: misc Description: The GNU hello world program
The following fields are available:
- Package - should be the package name, as in the Makefile.
Priority - should be set to optional for almost all packages. Section - indicates the type of package - useful sections include comm, editors, graphics, libs, net, text, web, or if you can't decide, misc. Description - a short description of the package. (You can include a longer description here in a similar manner to the help text in Config.in. Start a new line after the short description, and use a line containing a single full stop ('.') as a replacement for blank lines. Depends (not in the example above) - a list of package names that this package requires to operate. Use package names without versions here where possible (e.g. openssh-client).
Note: had to modify package/rules.mk changing ./ipkg/$(2) to the real directory ./ did not work for me
package/helloworld/patches/100-hello.patch
This example applies a Debian patch, which isn't essential for (so you can skip this point).
Other Linux and free UNIX distributions are often an excellent source of patches for non-portable programs. You might like to try searching for packages from Ubuntu, Gentoo, or FreeBSD's Ports.
cd package/helloworld/patches wget http://ftp.debian.org/debian/pool/main/h/hello/hello_2.1.1-4.diff.gz gunzip hello_2.1.1-4.diff.gz mv hello_2.1.1-4.diff 100-hello.patch
TIP: You can apply as many patches as you like. To apply them in a special order name them like:
100-xxx.patch 200-xxx.patch
Compile the package
The
makecommand below compiles every package that you have created in the
packagedirectory.
cd ~/OpenWrt-SDK-Linux-i686-1 make clean && make world
Note that there is a fault in the default package/rules.mk file. There is ".." following the "$(PKG_BUILD_DIR)/" which causes the files to be extracted to the wrong directory. Here is the corrected version:
ifneq ($(strip $(PKG_CAT)),) $(PKG_BUILD_DIR)/.prepared: $(DL_DIR)/$(PKG_SOURCE) rm -rf $(PKG_BUILD_DIR) mkdir -p $(PKG_BUILD_DIR) $(PKG_CAT) $(DL_DIR)/$(PKG_SOURCE) | tar -C $(PKG_BUILD_DIR)/ $(TAR_OPTIONS) if [ -d ./patches ]; then \ $(PATCH) $(PKG_BUILD_DIR) ./patches ; \ fi touch $(PKG_BUILD_DIR)/.prepared endif
NOTE: If you are using GNU make 3.80 (current "latest") and get a "virtual memory exhausted" message while making, see this page.
For Slackware users there is a fixed make package here and sources + patch are here.
When the compiling is finished you have a ready to use ipkg package for OpenWrt in the
~/OpenWrt-SDK-Linux-i686-1/bin/packagesdirectory.
cd bin/packages; ls -al hello_2.1.1-1_mipsel.ipk -rw-r--r-- 1 openwrt-dev openwrt-dev 3976 Sep 14 13:03 hello_2.1.1-1_mipsel.ipk
Contribute your new ported program
When you like you can contribute your program/package to the OpenWrt community. It may be included in further versions of OpenWrt.
To do this create a patch from your
package/directory with:
cd ~/OpenWrt-SDK-Linux-i686-1 diff -ruN package/.orig package/ > -.patch
Once you have created a patch open a ticket and submit your new package (the patch).
Native Development
You need 150Mb storage unit (USB or SD Card)
- Download the file Native Mipsel Toolchain (24Mb)
- Bunzip2 (120mb) it to the storage unit in a ext2 partition.
- unmount partition
- Execute this script, I have it at /sbin/devel.sh
#!/bin/sh # Kill unusefull tasks (uncoment it) we need memory #killall logger #killall syslogd #killall telnetd #killall crond #killall klogd #killall udhcpc #killall httpd #rmmod ext3 #rmmod jbd #My SD card have 2 partitions 1.ext2 2.swap mount /dev/mmc/disc0/part1 /mnt -o noatime async # Swap for large sources. I have 30Mb #swapoff -a #mkswap /dev/mmc/disc0/part2 #swapon /dev/mmc/disc0/part2 mount -o move /tmp /mnt/tmp echo " *** exit *** to back - Para volver al sistema" chroot /mnt/ /bin/ash - echo " *** Me are here again - De vuelta al sistema original ***" mount -o move /mnt/tmp/ /tmp/ umount /mnt
- Go /home
- download the source. Example: Didiwiki-0.5.tar.gz from http://www.didiwiki.org
- tar -xvzf didiwiki-0.5.tar.gz
- cd didiwiki-0.5
- configure (1 minute)
- make (1 minute)
- You have your new Binary in the SRC directory (didiwiki)
- copy it to the /tmp directori
- type exit
You have the binary in /tmp directory. copy it to /usr/bin
The result didiwiki.mipsel.binary.gz a small wiki for our router at 8000 port. If you don't use storage unit, you must create /home to store new pages. /home/.didiwiki/*
Links
You can find an useful reference for the packaging process in nbd's paper to the 'OpenWrt Hacking' talk on the 22C3:
- http://events.ccc.de/congress/2005/fahrplan/attachments/567-Paper_HackingOpenWRT.pdf
Full buildroot documentation (for compiling kernel modules and such things, for the rest the SDK should be used)
- http://downloads.openwrt.org/docs/buildroot-documentation.html
oldwiki/buildingpackageshowto.txt · Last modified: 2009/04/23 12:36 (external edit)