External Toolchain Support
FreeBSD needs support for external toolchains to ease testing of new compiler versions, support compilers that don't make sense to integrate into the base, and speed builds (by avoiding building of bootstrap compilers). This page documents efforts towards this.
Using pre-built toolchain packages
The simplest way to do this is with the pre-built toolchain packages. Toolchains are available via the devel/llvm## (for LLVM 10.0.0 and later), devel/xtoolchain-llvm<version> (for LLVM 8 and 9), and devel/freebsd-gcc<version> ports. For the GCC ports, architectures are provided as flavors and the resulting packages are named <arch>-gcc<version>. Once a toolchain is installed, it can be used with top-level system make targets such as buildworld and buildkernel via the CROSS_TOOLCHAIN variable to the name of the package (without the xtoolchain- prefix for LLVM toolchains). It can also be used with buildenv to build individual programs in the base system.
Cross-building with a pre-built toolchain package
For example, to build powerpc64 using GCC 6, you would do:
pkg install powerpc64-gcc6 make CROSS_TOOLCHAIN=powerpc64-gcc6 TARGET=powerpc TARGET_ARCH=powerpc64 buildworld make CROSS_TOOLCHAIN=powerpc64-gcc6 TARGET=powerpc TARGET_ARCH=powerpc64 installworld DESTDIR=/sysroots/powerpc64 make CROSS_TOOLCHAIN=powerpc64-gcc6 TARGET=powerpc TARGET_ARCH=powerpc64 distribution DESTDIR=/sysroots/powerpc64
To build arm64 with LLVM11, you would do:
pkg install llvm11 make CROSS_TOOLCHAIN=llvm11 TARGET=arm64 buildworld make CROSS_TOOLCHAIN=llvm11 TARGET=arm64 installworld DESTDIR=/sysroots/arm64 make CROSS_TOOLCHAIN=llvm11 TARGET=arm64 distribution DESTDIR=/sysroots/arm64
Use cross compiler to build native compiler
cd /usr/ports/base/binutils make CROSS_TOOLCHAIN=powerpc64-gcc6 TARGET=powerpc TARGET_ARCH=powerpc64 CROSS_SYSROOT=/sysroots/powerpc64 package cd /usr/ports/base/gcc6 make CROSS_TOOLCHAIN=powerpc64-gcc6 TARGET=powerpc TARGET_ARCH=powerpc64 CROSS_SYSROOT=/sysroots/powerpc64 package
Under the hood
The rest of this page provides details on how this works and how to override individual components if desired.
The XCC approach works with top level build targets (buildworld, buildkernel, etc) and overrides common make variables such as CC, CXX, and AS during the cross building portions of the build with values specified by the XCC, XCPP, XAS, etc variables. This method touches few files and is relatively easy to understand, but has drawbacks including the inability to build individual programs easily.
How to use
If is possible to replace both the compiler and binutils. It is possible to replace the compiler and use the built-in binutils. To replace binutils, you must also replace the compiler.
Both the compiler and binutils must be configured to support --sysroot to find headers and libraries.
Using an external compiler
To use an external compiler such as clang, set the variables XCC, XCXX, and XCPP when building and installing. You must generally set all three. For example:
$ make XCC=/usr/local/bin/clang XCXX=/usr/local/bin/clang++ XCPP=/usr/local/bin/clang-cpp buildworld ...
If your versions full paths end in cc, c++, and cpp, then you may use the CROSS_COMPILER_PREFIX variable to set all three (Note that this is a prefix, not a path):
$ ls /tmp/toolchain/ cross-c++ cross-cc cross-cpp $ make CROSS_COMPILER_PREFIX=/tmp/toolchain/cross- buildworld ...
If the compiler is clang and the target architecture is not the same as the build host then an appropriate target triple will be created and passed to clang to support native cross compilation.
Using an external binutils
To use an external binutils, set the XAS, XAR, XLD, XNM, XOBJDUMP, XRANLIB, and XSTRINGS. As with the compiler, there is a CROSS_BINUTILS_PREFIX variable. If the both the compiler and binutils have the same prefix a CROSS_TOOLCHAIN_PREFIX variable can be used to set both.
To use XCC, you must not set any of the variables that can be overridden by X* variables in /etc/make.conf or /etc/src.conf as Makefile.inc1 will be unable to change them.