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.
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.