cgccglibcguix

Build against an old glibc with Guix


Say that you got a c program, but almost any program will do, and put it in a file:

#include <stdio.h>
#include <gnu/libc-version.h>

int main (void) {
    puts (gnu_get_libc_version ());
    return 0;
}

And say that you want to build it against a specific version of glibc, for some reason. My initial attempt at doing this would be to create a Guix environment containing that old version of glibc along with gcc (and coreutils for programs like ls).

$ guix environment --pure --ad-hoc glibc@2.29 gcc-toolchain coreutils
$ rm a.out && gcc printer.c && ldd a.out && a.out
    linux-vdso.so.1 (0x00007ffd2cd0c000)
    libgcc_s.so.1 => /gnu/store/jlrfl1ss3b4xjggvajwffa9zppfcxksf-gcc-5.5.0-lib/lib/libgcc_s.so.1 (0x00007fcefd7b6000)
    libc.so.6 => /gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/libc.so.6 (0x00007fcefd5f9000)
    /gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/ld-linux-x86-64.so.2 (0x00007fcefd7d1000)
2.31

Unfortunately this doesn't seem to work. The resulting program is linked against a newer version of glibc than I expected, 2.31 rather than 2.29. But this may be due to gcc itself being linked against linked against glibc 2.31 and that ends up polluting the environment, so to speak.

$ ldd $(which gcc)
    linux-vdso.so.1 (0x00007fff7cfc5000)
    libm.so.6 => /gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/libm.so.6 (0x00007ff842b93000)
    libc.so.6 => /gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/libc.so.6 (0x00007ff8429d6000)
    /gnu/store/fa6wj5bxkj5ll1d7292a70knmyl7a0cr-glibc-2.31/lib/ld-linux-x86-64.so.2 (0x00007ff842cd6000)

Where do I go from here? I've tried using older versions of gcc packaged in Guix, but they all seem to be built against glibc 2.31. I also tried adding -L /gnu/store/hlsas48h6x7364kcfs8yy6xfksdsffr4-glibc-2.29/lib to my gcc-invocation but to no avail.


Solution

  • I was able to figure it out, or rather: cbaines on #guix@freenode pointed me towards the function make-gcc-toolchain which allowed me to set up the environment I wanted. By placing the following code into a file called development-environment.scm:

    (use-modules (gnu packages base)
                 (gnu packages commencement)
                 (gnu packages gcc)
                 (gnu packages version-control))
    
    (define-public gcc-glibc-2.29-toolchain
      (make-gcc-toolchain gcc glibc-2.29))
    
    (list gcc-glibc-2.29-toolchain git coreutils)
    

    and then running guix environment --pure --ad-hoc --load=development-environment.scm I was able to build my program using the version of glibc that I wanted:

    $ rm a.out && gcc printer.c && ldd a.out && ./a.out
        linux-vdso.so.1 (0x00007fff7e17c000)
        libgcc_s.so.1 => /gnu/store/71rcc4qxfgyzr0qphkh9adjsqsb999zk-gcc-glibc-2.29-7.5.0-lib/lib/libgcc_s.so.1 (0x00007f2c8adc9000)
        libc.so.6 => /gnu/store/hlsas48h6x7364kcfs8yy6xfksdsffr4-glibc-2.29/lib/libc.so.6 (0x00007f2c8ac0f000)
        /gnu/store/hlsas48h6x7364kcfs8yy6xfksdsffr4-glibc-2.29/lib/ld-linux-x86-64.so.2 (0x00007f2c8ade4000)
    2.29
    

    Hot tip for posterity: put the following in a file called .envrc, install the package direnv and insert it into your shell rc, and fill it with the following content:

    use guix --ad-hoc --load=development-environment.scm
    

    That way, every time you enter that folder with your shell the development environment will be loaded for you. The right version of glibc/gcc will be run even without the --pure flag.