How to build a FreeBSD toolchain for Linux

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.

1 Like

Hi, Thanks for the post it is very clear and simple. How to use this toolschain to compile freebsd from source. Because i can’t compile freebsd using make program in my linux machine.

I don’t make any test with cross compiling a custom FreeBSD kernel with this toolchain setup under Linux.

But it must be possible. If you’re very lucky, all you need to set LD_LIBRARY_PATH and PATH environment variables to run cross-compiler binaries.

I’m not a BSD guy but probably nobody wants to cross-compile FreeBSD kernel within Linux. I just tried to help people who need to compile their own software project for FreeBSD in Linux. Although cross-compiling FreeBSD kernel itself is theoretically possible, it can be very hard.