After configuration, BusyBox can be compiled into a single binary for different architectures, with different compilers and with static or dynamic linking.
This recipe will compile BusyBox for our desktop development system as a quick demonstration, and meanwhile, build BusyBox for an ARM target platform as an embedded system case.
Before compiling a software, we must get a compiler and the corresponding libraries, a build host, and a target platform. The build host is the one running the compiler. The target platform is the one running the target binary built by the compiler from the software source code. Here, our desktop development system is our build host, and an ARM Android system will be used as our target platform.
To compile BusyBox on our desktop development system, we need a local compiler. Generally, most Linux operating systems ship with a working C compiler, and it's usually GCC (the GNU Compiler Collection is by far the most widely used C compiler on Linux, and can be downloaded from http://gcc.gnu.org/) and the corresponding Glibc (the GNU C Library by far is the most widely used C library on Linux and can be downloaded from http://www.gnu.org/software/libc/). If it isn't present, get one from our system's package manager for Ubuntu.
$ sudo apt-get install gcc g++ make build-essential $ sudo apt-get install ia32-libs ia32-libs-multiarch
To compile BusyBox on our desktop development system for a different target architecture (for example, an ARM Android system), we need a cross-compiler.
ARM, as the most popular architecture on embedded system, is being used by more and more portable devices, such as the embedded Raspberry Pi board and the Android mobile phone or tablet, so we will concern ourselves with this alone.
The gcc-arm-linux-gnueabi
cross-compiler can be installed directly on Ubuntu with the following command:
$ sudo apt-get install gcc-arm-linux-gnueabi
On other Linux distributions, Google's official NDK is a good choice if you want to share Android's Bionic C library, but since Bionic C library lacks of many POSIX C header files, and because we want to get the most out of BusyBox applets building, the prebuilt version of Linaro GCC with Glibc is preferable. We can download it from http://www.linaro.org/downloads/; for example, http://releases.linaro.org/13.04/components/toolchain/binaries/gcc-linaro-aarch64-none-elf-4.7-2013.04-20130415_linux.tar.bz2.
Let's compile BusyBox with the default configuration for our desktop development system as a quick demonstration of the compiling procedure and cross-compile it for the ARM platform as a real embedded system building example.
Compiling BusyBox for a desktop development system can be done as follows:
$ make defconfig $ make $ file busybox busybox: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs)... $ ldd busybox linux-vdso.so.1 => (0x00007fff9edff000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1cf2cb4000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1cf28f5000) /lib64/ld-linux-x86-64.so.2 (0x00007f1cf2fcf000)
The previous lines of code compiled a binary for our x86-64 development system (the output may differ if you are using a different development system) and dynamically linked it with
libm.so
andlibc.so
.To get a quick start, simply run the
echo
applet as an example.$ ./busybox echo "Hello, Busybox." Hello, Busybox.
To get help from BusyBox and its applets, we can append the
--help
command as follows:$ ./busybox --help
We see the following output:
BusyBox v1.21.0 (2013-09-06 01:24:09 CST) multicall binary. BusyBox is copyrighted by many authors between 1998-2012. Licensed under GPLv2. See source distribution for detailed copyright notices. Usage: busybox [function [arguments]...] or: busybox --list[-full] or: busybox --install [-s] [DIR] or: function [arguments]... BusyBox is a multicall binary that combines many common Unix utilities into a single executable file. Most people will create a link to busybox for each function they wish to use and BusyBox will act like whatever it was invoked as. Currently defined functions: [, [[, acpid, add-shell, addgroup, adduser, adjtimex, arp, arping, ash, awk, base64, basename, beep, blkid, blockdev, bootchartd, brctl, bunzip2, bzcat, bzip2, cal, cat, catv, chat, chattr, chgrp, chmod, chown, chpasswd, chpst, chroot, chrt, chvt, cksum, clear, cmp, comm, conspy, cp, cpio, crond, crontab, cryptpw, cttyhack, cut, date, dc, dd, deallocvt, delgroup, deluser, depmod, devmem, df, dhcprelay, diff, dirname, dmesg, dnsd, dnsdomainname, dos2unix, du, dumpkmap, dumpleases, echo, ed, egrep, eject, env, envdir, envuidgid, ether-wake, expand, expr, fakeidentd, false, fbset, fbsplash, fdflush, fdformat, fdisk, fgconsole, fgrep, find, findfs, flock, fold, free, freeramdisk, fsck, fsck.minix, fsync, ftpd, ftpget, ftpput, fuser, getopt, getty, grep, groups, gunzip, gzip, halt, hd, hdparm, head, hexdump, hostid, hostname, httpd, hush, hwclock, id, ifconfig, ifdown, ifenslave, ifplugd, ifup, inetd, init, insmod, install, ionice, iostat, ip, ipaddr, ipcalc, ipcrm, ipcs, iplink, iproute, iprule, iptunnel, kbd_mode, kill, killall, killall5, klogd, last, less, linux32, linux64, linuxrc, ln, loadfont, loadkmap, logger, login, logname, logread, losetup, lpd, lpq, lpr, ls, lsattr, lsmod, lsof, lspci, lsusb, lzcat, lzma, lzop, lzopcat, makedevs, makemime, man, md5sum, mdev, mesg, microcom, mkdir, mkdosfs, mke2fs, mkfifo, mkfs.ext2, mkfs.minix, mkfs.vfat, mknod, mkpasswd, mkswap, mktemp, modinfo, modprobe, more, mount, mountpoint, mpstat, mt, mv, nameif, nanddump, nandwrite, nbd-client, nc, netstat, nice, nmeter, nohup, nslookup, ntpd, od, openvt, passwd, patch, pgrep, pidof, ping, ping6, pipe_progress, pivot_root, pkill, pmap, popmaildir, poweroff, powertop, printenv, printf, ps, pscan, pstree, pwd, pwdx, raidautorun, rdate, rdev, readahead, readlink, readprofile, realpath, reboot, reformime, remove-shell, renice, reset, resize, rev, rm, rmdir, rmmod, route, rpm, rpm2cpio, rtcwake, run-parts, runlevel, runsv, runsvdir, rx, script, scriptreplay, sed, sendmail, seq, setarch, setconsole, setfont, setkeycodes, setlogcons, setserial, setsid, setuidgid, sh, sha1sum, sha256sum, sha3sum, sha512sum, showkey, slattach, sleep, smemcap, softlimit, sort, split, start-stop-daemon, stat, strings, stty, su, sulogin, sum, sv, svlogd, swapoff, swapon, switch_root, sync, sysctl, syslogd, tac, tail, tar, tcpsvd, tee, telnet, telnetd, test, tftp, tftpd, time, timeout, top, touch, tr, traceroute, traceroute6, true, tty, ttysize, tunctl, ubiattach, ubidetach, ubimkvol, ubirmvol, ubirsvol, ubiupdatevol, udhcpc, udhcpd, udpsvd, umount, uname, unexpand, uniq, unix2dos, unlzma, unlzop, unxz, unzip, uptime, users, usleep, uudecode, uuencode, vconfig, vi, vlock, volname, wall, watch, watchdog, wc, wget, which, who, whoami, whois, xargs, xz,xzcat, yes, zcat, zcip.
Also we can use the echo command as follows:
$ ./busybox echo --help BusyBox v1.21.0 (2013-10-16 01:24:09 CST) multi-call binary. Usage: echo [-neE] [ARG]... Print the specified ARGs to stdout -n Suppress trailing newline -e Interpret backslash escapes (i.e., \t=tab) -E Don't interpret backslash escapes (default)
Now cross-compile it for the ARM platform. To compile it for the ARM platform, the cross-compiler
arm-linux-gnueabi-gcc
should be configured withmake menuconfig
, as we demonstrated in the previous recipe. After configuration, we can simply compile it as follows:$ make
Then a BusyBox binary is compiled for ARM with dynamic linking as follows:
$ file busybox busybox: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped
The previous
ldd
command of our development system doesn't work for listing the shared libraries required by the BusyBox binary for ARM,. Another command should be used instead,arm-linux-gnueabi-readelf
, as follows:$ arm-linux-gnueabi-readelf -d ./busybox | grep "Shared library:" \ | cut -d'[' -f2 | tr -d ']' libm.so.6 libc.so.6 ld-linux.so.3
To get the full path, we should first use the library search path.
$ arm-linux-gnueabi-ld --verbose | grep SEARCH \ | tr ';' '\n' | cut -d'"' -f2 | tr -d '"' /lib/arm-linux-gnueabi /usr/lib/arm-linux-gnueabi /usr/arm-linux-gnueabi/lib
Then we find out that
/usr/arm-linux-gnueabi/lib
is the real search path in our platform and we get the full path of the libraries as follows:$ ls /usr/arm-linux-gnueabi/lib/{libm.so,libc.so,ld-linux.so.3} /usr/arm-linux-gnueabi/lib/ld-linux.so.3 /usr/arm-linux-gnueabi/lib/libc.so /usr/arm-linux-gnueabi/lib/libm.so
Using BusyBox on an ARM platform needs an ARM device. This will be introduced in the Creating a virtual Android device (Simple) and Playing BusyBox on a virtual Android device (Intermediate) recipes.
The configuration not only generates a .config
file with enabled features, but also produces a C header file, include/autoconf.h
, that enables or disables the features with C macros. Based on these macros, the compiler determines which C context should be built in the last binary.
By default, the binary is dynamically linked. To avoid the installation of shared libraries, to reduce the whole system size, and to reduce the time cost of runtime linking, static linking is often used for embedded system compiling.
To enable static linking, configure BusyBox as follows:
Busybox Settings ---> Build Options ---> [*] Build BusyBox as a static binary (no shared libs)
We get the following error when using a new Glibc to compile BusyBox with static linking:
inetd.c:(.text.prepare_socket_fd+0x7e): undefined reference to `bindresvport'
We need to disable CONFIG_FEATURE_INETD_RPC
, as follows, to avoid it:
Networking Utilities ---> [*] inetd [ ] Support RPC services
Then, recompile it as follows:
$ make
Because it is statically linked, the required libraries will be linked into the last BusyBox binary. To run it on the target system, you only need to install the BusyBox binary (no shared libraries need to be installed).
The installation of BusyBox will be discussed in next recipe and the Creating a virtual Android device (Simple) recipe.