Building GCC

From OSDev Wiki
Jump to navigation Jump to search
Difficulty level
Difficulty 1.png
Beginner

In this tutorial we upgrade your system GCC to the most recent version. This helps you build a GCC Cross-Compiler, as it is recommended that you build the cross-compiler with the same compiler version. With some care, you don't have to bootstrap a new system compiler, but it is risky and can potentially create trouble. You should use the same major compiler release for your system compiler and your cross-compiler.

See also the official instructions for building GCC.

Introduction

Compilers are upgraded through a process called bootstrapping. At first you have your old system compiler that produces slow code and doesn't support all the new language features. You then use this old system compiler to build the new version of the compiler, hoping that the old compiler is able to build the new compiler (it supports all needed features). This produces a new compiler that produces fast code and supports all the new features, however the compiler itself is slow, because it was compiled with a compiler that produces slow code. In addition, the new compiler may be buggy because your old compiler was buggy, or perhaps the new compiler release has a bug.

The next step is to use your new slow compiler that produces fast code, and then build the new compiler again. This produces a fast compiler that produces fast code. However, the first compiler we built could be buggy, and the compiler we just built using it may be defect. We need to verify the correctness of our new fast compiler that produces fast code.

To solve that problem, we build the compiler a third time. Once we have built the third compiler using the second compiler, it should produce the very same output as the first compiler building the second, as both times we are using compilers that produce fast code and use the same source code. The compiler build system will then verify that the second and third compilers are identical, which gives you confidence in the bootstrap. If the second and third compilers are not identical, the bootstrap failed and you have encountered a compiler bug. Bootstrapping takes three times as long as just building a regular compiler, but it makes sure your toolchain is stable.

The last thing to do is run the compiler test suite so you can verify that it works correctly.

Notice how the same problems could occur if you use GCC 4.4 to build a GCC 4.8 cross-compiler. For that reason, it is recommended to use GCC 4.8 to build the GCC 4.8 cross-compiler, so you know no such problems could occur. You can't bootstrap a cross-compiler as it doesn't produce programs for the local operating system.

Do I need to bootstrap?

If your system compiler is the same major version as the compiler version you wish to build (for instance, if you have 4.6.2 and want 4.6.3), then you don't need to bootstrap. The minor releases are usually very compatible. You may be able to build another major version (such as 4.6.3 building 4.7.3) without a bootstrap, but it may not produce the ideal compiler. As the gap widens between the compiler versions, you are very likely to run into trouble. Each major compiler release is always able to build the next using a bootstrap. If you have the patience, it is possible to find a very old Linux system with a very old GCC release, and then bootstrap all the way up to the most recent GCC release, simply by iteratively upgrading a few major compiler releases at a time.

You may also be able to upgrade your system compiler through other channels.

Which compiler version do I want?

The newest GCC is recommended as it is the latest and greatest release. At this time, GCC 4.9.2 is the newest release. We recommend that you use the latest compiler release for your cross-compiler. You can also use older releases as they are usually reasonably good. If your local system compiler isn't too terribly old (at least GCC 4.6.0), you may wish to safe yourself the trouble and just pick the latest minor release (such as 4.6.3 if your system compiler is 4.6.1) for your cross-compiler. In that case, you don't need to bootstrap and you can proceed directly to building your GCC Cross-Compiler.

You can view your current compiler version by invoking:

gcc --version

If you have patience and wish to build yourself the latest and greatest cross-compiler, you'll want to bootstrap your system compiler before building your GCC Cross-Compiler.

Do I need a new Binutils as well?

It certainly couldn't hurt, but if your Binutils isn't too horribly out of date, it should be good enough for your new system compiler. You can view your current Binutils version by invoking:

ld --version

You probably need at least Binutils 2.22, or preferably the latest 2.25 release.

Preparing for the build

Difficulty level
Difficulty 1.png
Beginner


The GNU Compiler Collection is an advanced piece of software with dependencies. You need the following in order to build GCC:

  • A Unix-like environment (Windows users can use the Windows Subsystem for Linux or Cygwin)
  • Enough memory and hard disk space (it depends, 256 MiB will not be enough).
  • GCC (existing release you wish to replace), or another system C compiler
  • G++ (if building a version of GCC >= 4.8.0), or another system C++ compiler
  • Make
  • Bison
  • Flex
  • GMP
  • MPFR
  • MPC
  • Texinfo
  • ISL (optional)

Installing Dependencies

↓ Dependency / OS → Source Code Debian (Ubuntu, Mint, WSL, ...) Gentoo Fedora Cygwin OpenBSD Arch
How to install Normally sudo apt install foo sudo emerge --ask foo sudo dnf install foo Cygwin GUI setup doas pkg_add foo pacman -Syu foo
Compiler N/A build-essential sys-devel/gcc gcc gcc-c++ mingw64-x86_64-gcc-g++ / mingw64-i686-gcc-g++ Preinstalled base-devel
Make N/A build-essential dev-build/make make make Preinstalled base-devel
Bison [1] bison sys-devel/bison bison bison ? base-devel
Flex [2] flex sys-devel/flex flex flex ? base-devel
GMP [3] libgmp3-dev dev-libs/gmp gmp-devel libgmp-devel gmp gmp
MPC [4] libmpc-dev dev-libs/mpc libmpc-devel libmpc-devel libmpc libmpc
MPFR [5] libmpfr-dev dev-libs/mpfr mpfr-devel libmpfr-devel mpfr mpfr
Texinfo [6] texinfo sys-apps/texinfo texinfo texinfo texinfo base-devel
ISL (Optional) [7] libisl-dev dev-libs/isl isl-devel libisl-devel N/A N/A

You need to have Texinfo installed to build Binutils. You need to have GMP, MPC, and MPFR installed to build GCC. GCC optionally can make use of the ISL library.

For instance, you can install libgmp3-dev on Debian by running the shell command: sudo apt install libgmp3-dev

Note: Version 5.x (or later) of Texinfo is known to be incompatible with the current Binutils 2.23.2 release (and older). You can check your current version using makeinfo --version. If your version is too new and you encounter problems during the build, you will need to either use Binutils 2.24 release (or newer) or install an older version of Texinfo - perhaps through building from source - and add it to your PATH prior and during the Binutils build.

Note: GCC has dropped support for CLooG in the 5.x releases [8], and many distributions have dropped the CLooG package (e.g. Gentoo in December 2022).

Note: GCC requires at least ISL version 0.15.

Note: If you are using Cygwin, it is recommended to install the libintl-devel package (I couldn't build a cross-compiler without this package)

Downloading the Source Code

Download the needed source code into a suitable directory such as $HOME/src:

Note: The versioning scheme used is that each fullstop separates a full number, i.e. Binutils 2.20.0 is newer than 2.9.0. This may be confusing, if you have not encountered this (quite common) versioning scheme yet, when looking at an alphanumerically sorted list of tarballs: The file at the bottom of the list is not the latest version! An easy way of getting the latest version is to sort by the last modified date and scrolling to the bottom.

Note (16-bit C/C++): If you need to build 16-bit C/C++ code, don't use GCC versions 13.X.X and 14.X.X! When accessing global variables, an error occurs: collect2: fatal error: ld terminated with signal 11 [Segmentation fault], core dumped. You can build GCC version 12.1.0 and use it.

Linux Users building a System Compiler

Your distribution may ship its own patched GCC and Binutils that is customized to work on your particular Linux distribution. You should be able to build a working cross-compiler using the above source code, but you might not be able to build a new system compiler for your current Linux distribution. In that case, try a newer GCC release or get the patched source code.

Gentoo Users

Gentoo offers crossdev to set up a cross-development toolchain:

   emerge -av crossdev
   crossdev --help
   PORTDIR_OVERLAY="/usr/local/crossdev" crossdev --stage1 --binutils <binutils-version> --gcc <gcc-version> --target <target>

This will install a GCC cross-compiler into a "slot", i.e. alongside already-existing compiler versions. You can install several cross-compilers that way, simply by changing target designations. An unfortunate downside is that it will also pull in gentoo patches and pass additional configure options that differ from the official GCC Cross-Compiler setup, and they might behave differently.

After the compilation finishes successfully, your cross-compiler is callable via <target>-gcc. You can also use gcc-config to toggle between compiler versions should you need to do so. Don't replace your system compiler with a cross-compiler. The package manager will also suggest updates as soon as they become available.

You can uninstall the cross-compiler by calling crossdev --clean <target>. Read the cross-development document for additional information.

Note that the version numbers to binutils and gcc are Gentoo package versions, i.e. there might be a suffix to the "official" (GNU) version that addresses additional patchsets supplied by the Gentoo maintainers. (For example, --binutils 2.24-r3 --gcc 4.8.3 is the latest stable package pair at the time of this writing.) You can omit the version numbers to use the latest package available.

Portage uses overlays to store packages that are not part of the original package management. Crossdev needs one overlay where it can store its binutils and gcc packages before building them. You can configure one properly, or you can use PORTDIR_OVERLAY to point at where it should keep its package manager files. Using PORTDIR_OVERLAY is not a good idea with existing overlays, but by then you should know how you have personally set them up earlier anyway and how to do it properly. See [9].

Nix(OS) Users

nixpkgs provides cross-compiled versions of most packages and their dependencies/compilers, that includes pre-compiled build tools for cross-compilation for every avaliable architecture in pkgs.pkgsCross. This code snippet declares a nix shell with i686-elf-gcc :

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  nativeBuildInputs =
    with pkgs; [
        pkgsCross.i686-embedded.buildPackages.gcc
    ];
}

Read more at the official Nix documentation page for cross-compilation.

macOS Users

macOS users need a replacement libiconv because the system libiconv is seriously out of date. macOS users can download the latest libiconv release by visiting the libiconv website or directly accessing the GNU main FTP mirror. Otherwise you may get unresolved symbol errors related to libiconv when compiling GCC 4.3 or higher on OS X 10.4 and 10.5.

Install a new version (compile it yourself or use MacPorts) and add --with-libiconv-prefix=/opt/local (or /usr/local if you compiled it yourself) to GCC's ./configure line. Alternatively you may place the libiconv source as gcc-x.y.z/libiconv and it will be compiled as part of the GCC compilation process. (This trick also works for MPFR, GMP, and MPC).

The makefiles of Binutils and GCC use the $(CC) variable to invoke the compiler. On OS X, this resolves to gcc by default, which is actually clang. Prior to OS X 10.8, the Clang that came with Xcode's Command Line Tools package was not able to build a working GCC. Users running OS X 10.7 or below may need to find and install GCC, either from Homebrew, or from somewhere on Apple's website. You can try with the old GCC that comes preinstalled on some macOS versions.

# This is only necessary for OS X users running 10.7 or below.
export CC=/usr/bin/gcc-4.2
export CXX=/usr/bin/g++-4.2
export CPP=/usr/bin/cpp-4.2
export LD=/usr/bin/gcc-4.2

You will want to unset these exports once you compiled and installed the cross compiler.

Note for Lion users: If you're on Lion (or above) chances are that you don't have the "real" GCC since Apple removed it from the Xcode package, but you can still install it. You can do it via Homebrew or by compiling from source, both are perfectly described on a StackExchange answer.

Note for Maverick users: You can build binutils-2.24 and gcc-4.8.3 (possible other version) with Xcode 5.1.1. Note that building GCC with LLVM is not officially supported and may cause interesting bugs, if you are willing to take this risk and save time building host-gcc just to compile a cross-gcc, follow this. Install GMP, MPFR, Mpc with MacPorts.

sudo port install gmp mpfr libmpc
../binutils-2.24/configure --prefix=$PREFIX \
--target=$TARGET \
--enable-interwork --enable-multilib \
--disable-nls --disable-werror
../gcc-4.8.3/configure --prefix=$PREFIX \
--target=$TARGET \
--disable-nls \
--enable-languages=c,c++ --without-headers \
--enable-interwork --enable-multilib \
--with-gmp=/usr --with-mpc=/opt/local --with-mpfr=/opt/local

Note: There is an issue with port's GMP, so the version from OS X from /usr is used instead. Note2: If you still have some errors, try making a case-sensitive APFS disk image using disk utility app and build from there

Windows Users

Windows users need to set up a Unix-like enviroment such as MinGW or Cygwin. It may well be worth looking into systems such as Linux and see if they fit your needs, as you commonly use a lot of Unix-like tools in operating systems development and this is much easier from a Unix-like operating system. If you have just installed the basic Cygwin package, you have to run the setup.exe again and install the following packages: GCC, G++, Make, Flex, Bison, Diffutils, libintl-devel, libgmp-devel, libmpfr-devel, libmpc-devel, Texinfo

MinGW + MSYS is an option, and as it addresses the native Windows API instead of a POSIX emulation layer, results in a slightly faster toolchain. Some software packages will not build properly under MSYS as they were not designed for use with Windows. As far as this tutorial is concerned, everything that applies to Cygwin also applies to MSYS unless otherwise specified. Make sure you install the C and C++ compilers, and the MSYS Basic System.

The "Windows Subsystem for Linux (Beta)", released with the Windows 10 Anniversary update is also an option for using a cross compiler. (Tested 08/08/2016 with GCC 6.1.0 and Binutils 2.27) This cross-compiler works reasonably fast, although being in beta state, it may not be ideal permanent development platform.

Cygwin note: Cygwin includes your Windows %PATH% in its bash $PATH. If you were using DJGPP before, this could result in confusion as e.g. calling GCC on the Cygwin bash command line would still call the DJGPP compiler. After uninstalling DJGPP, you should delete the DJGPP environment variable and clear the C:\djgpp entry (or wherever you installed it) from your %PATH%. Likewise, it might be a bad idea to mix build environments in your system PATH variable.

MinGW note: Some MinGW-specific information on building a cross-toolchain can be found on the hosted cross-compiler how-to page on the MinGW homepage.

Windows Subsystem for Linux (Beta) Note: You cannot have your cross compiler in the /mnt/c/ (or /mnt/"x") areas, as trying to compile your cross-compiler there will generate errors, whereas building to $HOME/opt/cross works perfectly. This is fixed with Windows Update KB3176929

OpenBSD Users

OpenBSD users might need to install "gcc" package from ports because base system's GCC is very outdated. If you want to build GCC, try to use the ports' version instead of the latest version available and apply all patches from ports to your build. Also, if the build fails during compiling lto-plugin, a temporary solution is to disable LTO altogether during configure stage of building GCC by adding --disable-lto

The Build

You need to decide where to install your new compiler. It is dangerous to replace your current system compiler and installation into system directories is likely a very bad idea. You also need to decide whether the new compiler should be installed globally or just for you. If you want to install it just for you (recommended), installing into $HOME/opt/gcc-x.y.z is normally a good idea. If you want to install it globally, installing it into /usr/local/gcc-x.y.z is normally a good idea.

Please note that we build everything out of the source directory tree, as is considered good practice. Some packages only support building outside, some only inside and some both (but may not offer extensive checking with make). Building GCC inside the source directory tree fails miserably, at least for older versions.

As the build can take a long time, it is recommended to make use of make's "-jN" option. This will allow make to use multiple threads to compile the programs, which will speed up things a LOT. Substitute N with a number; a good guideline is the number of core you CPU has, plus one. So for a 4 core CPU, you'll want to use :

make -j5

Preparation

export PREFIX="$HOME/opt/gcc-x.y.z"

Binutils

cd $HOME/src
mkdir build-binutils
cd build-binutils
../binutils-x.y.z/configure --prefix="$PREFIX" --disable-nls --disable-werror
make
make install

--disable-nls tells Binutils not not include native language support. This is basically optional, but reduces dependencies and compile time. It will also result in English-language diagnostics, which the people on the Forum understand when you ask your questions.

GCC

See also the offical instructions for configuring GCC.
cd $HOME/src


# If you wish to build these packages as part of GCC:
mv libiconv-x.y.z gcc-x.y.z/libiconv # Mac OS X users
mv gmp-x.y.z gcc-x.y.z/gmp
mv mpfr-x.y.z gcc-x.y.z/mpfr
mv mpc-x.y.z gcc-x.y.z/mpc

# Or in new GCC versions, you can ask gcc to download the prerequisites
cd gcc-x.y.z
./contrib/download_prerequisites
cd $HOME/src # Returning the main src folder

mkdir build-gcc
cd build-gcc
../gcc-x.y.z/configure --prefix="$PREFIX" --disable-nls --enable-languages=c,c++
make
make install

--disable-nls is the same as for Binutils above.

--enable-languages tells GCC to not to compile all the other language frontends it supports, but only C and C++. Even if you aren't going to use C++ to make your OS, you'll need it later on to port GCC.

--disable-bootstrap tells the compiler to not bootstrap itself against the current system compiler. This results in a much quicker compilation, but if the current and the new compiler differ too much in version, you will get a less robust compiler or weird errors.

Building and bootstrapping GCC may take quite a while, so sit back and relax, and enjoy that you are about to use the latest and greatest version of the GNU Compiler Collection.

Before you run make install and install the new compiler, if you have some additional patience, read the official testing instructions and test your compiler for defects.

Using the new Compiler

You can now run your new compiler by invoking something like:

$HOME/opt/gcc-x.y.z/bin/gcc --version

To use your new compiler simply by invoking gcc, add $HOME/opt/gcc-x.y.z/bin to your $PATH by typing:

export PATH="$HOME/opt/gcc-x.y.z/bin:$PATH"

This command will add your new compiler to your PATH for this shell session. If you wish to use it permanently, add the PATH command to your ~/.profile configuration shell script or similar. Consult your shell documentation for more information.

Building the Cross-Compiler

Main article: GCC Cross-Compiler

Now that you have a system compiler that is up to date, you can build your cross-compiler for your new operating system. You can use the latest and greatest version of GCC as your cross-compiler safely because you use the same version to build it. Once you have built the actual cross-compiler, you can uninstall the compiler we built in this tutorial by removing the installation directory. The cross-compiler will not depend on the compiler that built it, just like our new compiler doesn't depend on the old system compiler it replaced.