Jump to Navigation

Overview

Introduction

This document will show you how to (re)compile glibc-2 and all supporting packages. We will use only the source distributions; usually, it is a good idea not to install binary packages, because they often lack some of the documentation and may use undesirable defaults. And compiling your own sources is much more fun :-).

Packages

Note that by the time you read this, newer versions of the packages may have been released!

  • ld.so-1.9.9
    The dynamic linker for libc-5, compatible with libc-6. You need at least version 1.9.9 for gcc-2.8.1.
  • binutils-2.9.1.0.19a
    Linker, assembler and binary utilities. You need at least version 2.9.x. Note that these are based on GNU binutils-2.9.1, but you must use a specific Linux version.
  • glibc-2.0.6
    Glibc-2, also known as libc-6. Officially, this is still a BETA version
    • glibc-linuxthreads-2.0.6
      The threads package for glibc-2.0.6
    • glibc-localedata-2.0.6
      The locale data package for glibc-2.0.6
    • glibc-crypt-2.0.6
      The crypt(2) routines; note that due to export restrictions you may only get it from the indicated places.
  • gcc-2.8.1
    The C and C++ compiler. You need at least version 2.8.1, all earlier version need additional patches.
  • libc-5.4.46
    Libc-5. While we are at it, we will also upgrade our libc-5 to the newest version, though you can skip this step if you want.
  • libstdc++-2.8.1.1
    The C++ library. You must compile a separate version for glibc-2 if you want to compile C++ programs. You will probably also need the optional add-on libg++-2.8.1.1a for backward compatibility reasons.

Cross compiler theory

A compiler is a program that translates human-written, readable programs into machine-readable code. A cross compiler is a compiler that runs on one machine/operating system and produces code (executables) for another machine/operating system. The machine/operating system the compiler runs on is called the host; the machine/operating system the produced code will run on is called the target. For a native (non-cross) compiler, the host and the target are the same.

We will build a cross-compiler that has as host a Linux i486 libc-5 system, and as target a Linux i486 libc-6 system. This cross-compiler is special, because we have a sort of super-ix86 Linux system which can run both host code and target code! Still, it is important to understand the difference between host and target to properly configure the compiler.

The GNU gcc compiler needs several supporting programs to do its work. So, we will not only create a cross-compiler, but also a cross-assembler, a cross-linker and several cross-utilities. We also need the C-library glibc-2 itself if we want to compile and link any programs; and a dynamic linker that understands about glibc-2.

What may be a bit difficult the grasp at first, is that neither the C-library nor the dynamic linker (itself a sort of library) are 'cross-libraries'. Actually, the notion of 'cross-library' is of course nonsense: a library is a collection of useful functions, for some particular machine/operating system. Remember that a 'cross-something' is a program that runs on one machine/operating system and produces or manipulates code for another machine/operating system. And neither the dynamic linker nor the C-library generate code: they are pieces of code!

When you read the documentation of the compiler and the binary utilities, you will also encounter the notion of build system. Throughout this document we will assume the build system is the same as the host system. It is different if you use a cross-compiler to compile the compiler (think about that!)

Finally, if you own a i386, Pentium or clone-processor, it is very easy to configure the compiler to generate optimized code for those processors. But fortunately, code for these processors is interchangable, so don't worry.

System assumptions

This document assumes you have a working GCC libc-5 setup. You should use one of the 2.0.x or 2.2.x kernels; I have heard rumors that compiling this stuff with some 2.1.x kernels is difficult, and I have not tried it myself.

We will use the target name i486-linux-libc5 for the default compilation target (compiling with libc-5), and i486-linux-libc6 for the additional target (compiling with libc-6). Note that you can freely choose your own names. All libc-6 stuff will go into sub-directories of /usr/i486-linux-libc6 (except for a link to the libc-6 dynamic loader, which must be available in /lib).

If you own a different machine, everything except for the names for the targets should remain the same. I will show how you can find out your so-called cannonical target names (which are needed to tell the compiler what code it must produce) later on.

Steps

As a first step, we will upgrade our native compiler (the libc-5 gcc) to the newest version. This is especially important if you run a compiler that is older than version 2.7.2 (2.6.3 had some nasty bugs, and strength reducing in the 2.7 versions, automatically selected by the -O2 flag, can cause problems). We will not yet create a cross-compiler, as we need the glibc-2 header files for that.

Next we will compile ld.so, the dynamic linker. Though glibc-2 has its own dynamic linker, the one you use for libc-5 must be glibc-2-aware.

Next, we create appropriate binary utilities. Though the format of the binaries is the same for both libc-5 and libc-6, we need to create a cross-linker if we want to compile for libc-6 without having to specify additional flags. We install the libc-5 versions at the usual places (/usr/bin) and the libc-6 versions in the special libc-6 directory (/usr/i486-linux-libc6/bin). These use different search paths from the libc-5 versions.

Normally, you would now first create a cross-compiler and then use it to compile for example your libc. Because the binary formats of libc-5 and libc-6 executables are the same, we can first compile libc-6, and only afterwards create a gcc cross-compiler for that target. Why do we do it in this way? Because gcc needs header files of the target, and the only way to get them is to compile glibc-2 first... Of course, for normal programs this trick would be impossible, but the libc is one of the very few programs that is not linked against a (not yet existing) libc!

So we first compile glibc-2 and install it in /usr/i486-linux-libc6/.... In the package we also find a dynamic linker which we link to /lib/ld-linux-2.so. We can now handle glibc-2 executables and objects, but we can not yet create those objects and executables - we need a compiler.

So, we now compile gcc as a cross-compiler: the compiler itself is a libc-5 executable, but it will create libc-6 objects and executables! Now we have done all the really necessary work.

The next-to-last step is the upgrading of our native C-library. It is smart to do that before upgrading the C++-library in the next step.

To compile C++ programs linked with glibc-2, we also need a new libg++, that is linked against libc-6 instead of libc-5. While we are at it, we also compile the latest version for libc-5.

Now we have a complete compilation environment for both libc-5 and libc-6, updated to the latest and greatest. It may be necessary to compile other libaries under the libc-6 environment too, but that should be straightforward now.



Historic_content | by Dr. Radut