If you’re working on a C/C++ project which same codebase must be compiled also for FreeBSD and you don’t want to work on a FreeBSD box just for compilation, you need a cross-compiling toolchain environment.
But, this is not an easy job like working embedded Linux projects on ARM, Mips e.g. architectures because FreeBSD doesn’t use GNU C library (glibc) and this makes generation of toolchains a little bit harder. If you search over the internet probably you can’t find any toolchain for Linux that targets FreeBSD.
So, you need to build yourself as me. Here are the step by step instructions to generate a toolchain for FreeBSD Release 10.X (target name for autoconf utils must be: x86_64-pc-freebsd10 for 64bit x86 toolchain):
-
First of all, you need a running FreeBSD installation to copy some required files. If you don’t have any running FreeBSD system yet, you can make a minimal installation with VirtualBox or qemu.
-
Create and empty directrory in your Linux box for the new toolchain. In our example, I used to
/opt/cross-freebsd
directory:
$ sudo mkdir /opt/cross-freebsd && sudo chown -R $USER /opt/cross-freebsd
- Now create a temprory directory for builds, like
build-tmp
:
$ sudo mkdir build-tmp && cd build-tmp
- Download and compile binutils:
$ wget http://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.gz
$ tar xf binutils-2.25.1.tar.gz
$ cd binutils-2.25.1/
$ ./configure --enable-libssp --enable-gold --enable-ld \
--target=x86_64-pc-freebsd10 --prefix=/opt/cross-freebsd
$ make -j4
$ make install
$ cd ..
-
At this step, we have to copy some necessary files from a running FreeBSD system:
-
Copy whole
/usr/include
directory from FreeBSD to/opt/cross-freebsd/x86_64-pc-freebsd10/
directory. -
Copy following stub and library files from FreeBSD to
/opt/cross-freebsd/x86_64-pc-freebsd10/lib/
directory:
/usr/lib/crt1.o
/usr/lib/crti.o
/usr/lib/crtn.o
/usr/lib/libc.a
/usr/lib/libm.a
/lib/libc.so.7
/lib/libm.so.5
/usr/lib/libpthread.so
Please note that, if your FreeBSD version is different, version of the libm
and libc
libraries may be different.
After copying all the files, go to the copied directory and make proper links for libm
and libc
:
$ pushd .
$ cd /opt/cross-freebsd/x86_64-pc-freebsd10/lib
$ ln -s libm.so.5 libm.so
$ ln -s libc.so.7 libc.so
$ popd
If you omit above symbolic link steps, you will get relocation errors because compiler will try to link with static version of the libc
and libm
. It is not possible to do with static libraries, so all the shared libraries must be found by the compiler.
- Compile gmp package as below:
$ wget http://ftp.gnu.org/gnu/gmp/gmp-6.0.0a.tar.xz
$ tar xf gmp-6.0.0a.tar.xz
$ cd gmp-6.0.0/
$ ./configure --prefix=/opt/cross-freebsd --enable-shared --enable-static \
--enable-mpbsd --enable-fft --enable-cxx --host=x86_64-pc-freebsd10
$ make -j4
$ make install
$ cd ..
- Compile mpfr package as below:
$ wget http://ftp.gnu.org/gnu/mpfr/mpfr-3.1.3.tar.xz
$ tar xf mpfr-3.1.3.tar.xz
$ cd mpfr-3.1.3/
$ ./configure --prefix=/opt/cross-freebsd --with-gnu-ld --enable-static \
--enable-shared --with-gmp=/opt/cross-freebsd --host=x86_64-pc-freebsd10
$ make -j4
$ make install
$ cd ..
- Compile mpc package as below:
$ wget http://ftp.gnu.org/gnu/mpc/mpc-1.0.3.tar.gz
$ tar xf mpc-1.0.3.tar.gz
$ cd mpc-1.0.3/
$ ./configure --prefix=/opt/cross-freebsd --with-gnu-ld --enable-static \
--enable-shared --with-gmp=/opt/cross-freebsd \
--with-mpfr=/opt/cross-freebsd --host=x86_64-pc-freebsd10
$ make -j4
$ make install
$ cd ..
- And finally, compile the gcc package as below:
$ wget http://ftp.gnu.org/gnu/gcc/gcc-4.8.5/gcc-4.8.5.tar.bz2
$ tar xf gcc-4.8.5.tar.bz2
$ cd gcc-4.8.5/
$ mkdir build
$ cd build
$ ../configure --without-headers --with-gnu-as --with-gnu-ld --disable-nls \
--enable-languages=c,c++ --enable-libssp --enable-gold --enable-ld \
--disable-libitm --disable-libquadmath --target=x86_64-pc-freebsd10 \
--prefix=/opt/cross-freebsd --with-gmp=/opt/cross-freebsd \
--with-mpc=/opt/cross-freebsd --with-mpfr=/opt/cross-freebsd --disable-libgomp
$ LD_LIBRARY_PATH=/opt/cross-freebsd/lib make -j4
$ make install
Now your FreeBSD toolchain is ready:
$ ls /opt/cross-freebsd/bin
x86_64-pc-freebsd10-addr2line x86_64-pc-freebsd10-gcc x86_64-pc-freebsd10-ld.gold
x86_64-pc-freebsd10-ar x86_64-pc-freebsd10-gcc-4.8.5 x86_64-pc-freebsd10-nm
x86_64-pc-freebsd10-as x86_64-pc-freebsd10-gcc-ar x86_64-pc-freebsd10-objcopy
x86_64-pc-freebsd10-c++ x86_64-pc-freebsd10-gcc-nm x86_64-pc-freebsd10-objdump
x86_64-pc-freebsd10-c++filt x86_64-pc-freebsd10-gcc-ranlib x86_64-pc-freebsd10-ranlib
x86_64-pc-freebsd10-cpp x86_64-pc-freebsd10-gcov x86_64-pc-freebsd10-readelf
x86_64-pc-freebsd10-dwp x86_64-pc-freebsd10-gprof x86_64-pc-freebsd10-size
x86_64-pc-freebsd10-elfedit x86_64-pc-freebsd10-ld x86_64-pc-freebsd10-strings
x86_64-pc-freebsd10-g++ x86_64-pc-freebsd10-ld.bfd x86_64-pc-freebsd10-strip
You can compile your traditional hello world within Linux for FreeBSD:
$ export LD_LIBRARY_PATH=/opt/cross-freebsd/lib
$ /opt/cross-freebsd/bin/x86_64-pc-freebsd10-gcc -o hello hello.c
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), dynamically linked
(uses shared libs), for FreeBSD 10.1, not stripped
Please note that, you need to set LD_LIBRARY_PATH
to point /opt/cross-freebsd/lib
directory before executing the compiler.