Wednesday, September 24, 2008

MIPS Cross Compiling on Linux x86_64

Cross compiling might be a quite "scary" subject for some programmers. Nevertheless, it's not so difficult as long as you have already obtained the right cross-toolchain.

At first sight, I thought that I have to put lengthy LDFLAGS and CFLAGS arguments in the Makefile of my test program. But, surprisingly, it's not the case. Let's see how it works. My build system is Slamd64 12.1, a Linux x86_64 platform. The target is a MIPS R3000 system. This is the Makefile:

all: set_power_cck

CC = mips-uclibc-gcc
STRIP = mips-uclibc-strip

CFLAGS = -v
IFLAGS =
LDFLAGS =


DEBUG = -Wall -Os

set_power_cck: Makefile set_power_cck.o
$(CC) -o $@ $(DEBUG) $(CFLAGS) $(IFLAGS) $(LDFLAGS) set_power_cck.o
$(STRIP) $@

clean:
rm -f set_power_cck *.o

set_power_cck.o: set_power_cck.c
$(CC) -c -o $@ $(DEBUG) $(CFLAGS) $(IFLAGS) $<



As you see, the only exotic option is in the CC and STRIP program definition which specify a cross-mips toolchain. Actually this is an x86 (not x86_64) cross toolchain, but because my Slamd64 is a multilib linux installation, it's not a problem. In the first run of this makefile, I'm very surprised how the cross-toolchain could find the right include paths and library paths. After tinkering with GCC for sometime, I found that the -v CFLAGS could reveal what exactly happens. Now, let's see how the cross-toolchain found the right library paths and include paths.


darmawan@opunaga:realtek_rtl8186_sdk_v1.4c_svn_co $ make -C AP/set_power_cck/
make: Entering directory `/home/darmawan/_Projects/Antek_SRL/RTL8186_work/realtek_rtl8186_sdk_v1.4c_svn_co/AP/set_power_cck'
mips-uclibc-gcc -c -o set_power_cck.o -Wall -Os -v set_power_cck.c
Reading specs from /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/specs
Configured with: /root/toolchain/gcc-3.3.x/toolchain_build_mips_nofpu/gcc-3.3.3/configure --prefix=/usr/local/gcc333/lexra-nnop-v5 --build=i386-pc-linux-gnu --host=i386-pc-linux-gnu --target=mips-linux-uclibc --enable-languages=c,c++ --enable-shared --with-gxx-include-dir=/usr/local/gcc333/lexra-nnop-v5/mips-linux-uclibc/include/c++ --disable-__cxa_atexit --enable-target-optspace --with-gnu-ld -with-gnu-as --disable-nls --enable-multilib --without-float --enable-sjlj-exceptions
Thread model: posix
gcc version 3.3.3
/usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/cc1 -quiet -v -D__GNUC__=3 -D__GNUC_MINOR__=3 -D__GNUC_PATCHLEVEL__=3 set_power_cck.c -quiet -dumpbase set_power_cck.c -auxbase-strip set_power_cck.o -Os -Wall -version -msoft-float -o /tmp/ccNOlsiQ.s
GNU C version 3.3.3 (mips-linux-uclibc)
compiled by GNU C version 2.96 20000731 (Red Hat Linux 7.3 2.96-110).
GGC heuristics: --param ggc-min-expand=94 --param ggc-min-heapsize=120073
ignoring duplicate directory "/usr/local/gcc333/lexra-nnop-v5/mips-linux-uclibc/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/include
/usr/local/gcc333/lexra-nnop-v5/mips-linux-uclibc/sys-include
End of search list.
set_power_cck.c: In function `set_tx_power_cck':
set_power_cck.c:20: warning: unused variable `tx_power_cck'
set_power_cck.c:22: warning: control reaches end of non-void function
set_power_cck.c: At top level:
set_power_cck.c:19: warning: `set_tx_power_cck' defined but not used
/usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/../../../../mips-linux-uclibc/bin/as -EB -g0 -32 -v -KPIC -o set_power_cck.o /tmp/ccNOlsiQ.s
GNU assembler version 2.14.90.0.7 (mips-linux-uclibc) using BFD version 2.14.90.0.7 20031029
mips-uclibc-gcc -o set_power_cck -Wall -Os -v set_power_cck.o
Reading specs from /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/specs
Configured with: /root/toolchain/gcc-3.3.x/toolchain_build_mips_nofpu/gcc-3.3.3/configure --prefix=/usr/local/gcc333/lexra-nnop-v5 --build=i386-pc-linux-gnu --host=i386-pc-linux-gnu --target=mips-linux-uclibc --enable-languages=c,c++ --enable-shared --with-gxx-include-dir=/usr/local/gcc333/lexra-nnop-v5/mips-linux-uclibc/include/c++ --disable-__cxa_atexit --enable-target-optspace --with-gnu-ld -with-gnu-as --disable-nls --enable-multilib --without-float --enable-sjlj-exceptions
Thread model: posix
gcc version 3.3.3
/usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/collect2 --eh-frame-hdr -EB -dynamic-linker /lib/ld-uClibc.so.0 -o set_power_cck /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/../../../../mips-linux-uclibc/lib/crt1.o /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/../../../../mips-linux-uclibc/lib/crti.o /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/crtbegin.o -L/usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3 -L/usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/../../../../mips-linux-uclibc/lib set_power_cck.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/crtend.o /usr/local/gcc333/lexra-nnop-v5/lib/gcc-lib/mips-linux-uclibc/3.3.3/../../../../mips-linux-uclibc/lib/crtn.o
mips-uclibc-strip set_power_cck
make: Leaving directory `/home/darmawan/_Projects/Antek_SRL/RTL8186_work/realtek_rtl8186_sdk_v1.4c_svn_co/AP/set_power_cck'



As you see, the cross-compiler driver (mips-uclibc-gcc) found the right paths for libraries and include files in the spec file definition. Now, it's clear to me what a "compiler driver" really is. This knowledge is very handy when you are working with cross-toolchain. Now, let's see the result using the file utility.

darmawan@opunaga:realtek_rtl8186_sdk_v1.4c_svn_co $ file AP/set_power_cck/set_power_cck
AP/set_power_cck/set_power_cck: ELF 32-bit MSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked (uses shared libs), stripped

It's very clear that the binary result is indeed MIPS ELF 32-bit executable file. When I run the executable in the target MIPS system, it works just fine as follows:

BusyBox v1.00-pre8 (2008.09.24-13:53+0000) Built-in shell (msh)
Enter 'help' for a list of built-in commands.
# set_power_cck
Usage: $0 (0-255 decimal)
where (0-255 decimal) is the power level gain. Choose a value between 0 and 255 decimal

Cross compiling is not as scary as it sounds, doesn't it? Personally, I think it's scary if you have to build the cross-toolchain yourself. Let's leave it for another time.
Post a Comment

2 comments:

Max said...

HI Darmawan salihun, really great work, I always wanted to know about the MIPS kernel, I'm looking for some example of using the ports of these micros MIPS to handle drivers for motor control, some sensors, I have wanted to experiment with small robots with rtl8225 wifi controller, with Webcam LAN rtl83055c, some motors and sensors, with rtl8186 for example.

Greetings from Argentina.

Max said...

Hi Darmawan Salihun, really great work, I always wanted to know about the MIPS kernel, I'm looking for some example of using the ports of these micros MIPS to handle drivers for motor control, some sensors, I have wanted to experiment with small robots with rtl8225 wifi controller, with Webcam LAN rtl83055c, some motors and sensors, with rtl8186 for example.