C: Difference between revisions
imported>Mic92 add article about the c infrastructure |
imported>Mic92 typos |
||
Line 17: | Line 17: | ||
== The compiler wrapper == | == The compiler wrapper == | ||
When | When inspecting the compiler or linker executable one will notice that those are not binaries but shell scripts: | ||
binaries but shell scripts: | |||
<syntaxHighlight lang=console> | <syntaxHighlight lang=console> | ||
Line 30: | Line 29: | ||
</syntaxHighlight> | </syntaxHighlight> | ||
These shell-scripts | These shell-scripts wrap around the actual compiler and add additional compiler flags depending | ||
on environment variables. In particular the wrapper around the | on environment variables. In particular the wrapper around the C compiler, | ||
will also look for a <code>NIX_CFLAGS_COMPILE</code> variable and prepend the content | will also look for a <code>NIX_CFLAGS_COMPILE</code> variable and prepend the content | ||
to command line arguments passed to the underlying compiler. | to command line arguments passed to the underlying compiler. | ||
Line 54: | Line 53: | ||
</syntaxHighlight> | </syntaxHighlight> | ||
In <code>$NIX_CFLAGS_COMPILE</code> we see that the include search path by appending new directories | In <code>$NIX_CFLAGS_COMPILE</code> we see that the include search path is extended by appending new directories | ||
using the <code>-isystem</code flag. For <code>$NIX_LDFLAGS</code> see that the library link path is extended | using the <code>-isystem</code flag. For <code>$NIX_LDFLAGS</code> see that the library link path is extended | ||
using the <code>-L</code> flag. We also notice that in addition to library paths the linker gets instructed | using the <code>-L</code> flag. We also notice that in addition to library paths the linker gets instructed |
Revision as of 16:25, 6 February 2019
This article gives practical advices when working C/C++ projects with Nix. It is written to be read from top to bottom.
Differences between nixpkgs and the rest
The way nixpkgs and its stdenv handles compiling and linking is very different from other linux distributions.
Usually header files are put into well known paths i.e. /usr/include
, where the compiler will
look for them. Same is true when linking against libraries, which are put in a few places, where the build-time
linker. Dynamically linked libraries will have a run-time linker (also known as ld.so
) set as an interpreter.
This linker reads /etc/ld.so.conf
to figure out where to find libraries.
In nixpkgs in contrast this information is provided by environment variables that will
be set based on the build inputs that are given when building a package or
when loading a nix expression into a `nix-shell
`.
Therefore it is not sufficient to just install libraries with nix-env
into the profile
since the compiler will not look in those paths when compiling.
The compiler wrapper
When inspecting the compiler or linker executable one will notice that those are not binaries but shell scripts:
$ nix-shell -p hello --command 'which $CC'
/nix/store/isg8rxaxkijl9x3hr2gzsf8pqfnqxg3k-gcc-wrapper-7.4.0/bin/gcc
$ nix-shell -p hello --command 'which $LD'
/nix/store/isg8rxaxkijl9x3hr2gzsf8pqfnqxg3k-gcc-wrapper-7.4.0/bin/ld
$ file /nix/store/isg8rxaxkijl9x3hr2gzsf8pqfnqxg3k-gcc-wrapper-7.4.0/bin/gcc /nix/store/isg8rxaxkijl9x3hr2gzsf8pqfnqxg3k-gcc-wrapper-7.4.0/bin/ld
/nix/store/isg8rxaxkijl9x3hr2gzsf8pqfnqxg3k-gcc-wrapper-7.4.0/bin/gcc: a /nix/store/vs6d2fjkl4kb3jb7rwibsd76k9v2n4xy-bash-4.4-p23/bin/bash script, ASCII text executable
/nix/store/isg8rxaxkijl9x3hr2gzsf8pqfnqxg3k-gcc-wrapper-7.4.0/bin/ld: symbolic link to /nix/store/lwdkm354f3zzsvkf7pqmnc8w6r164b42-binutils-wrapper-2.30/bin/ld
These shell-scripts wrap around the actual compiler and add additional compiler flags depending
on environment variables. In particular the wrapper around the C compiler,
will also look for a NIX_CFLAGS_COMPILE
variable and prepend the content
to command line arguments passed to the underlying compiler.
A different variable is called NIX_LDFLAGS
, which will be provided as input to the build time linker.
Nixpkgs use these variables to influence what kind of header files and libraries are visible to the build tools when running.
For example when we add zlib
to buildInputs
of a stdenv.mkDerivation
call and
load the resulting file in a nix-shell
, we can see the effect on both NIX_CFLAGS_COMPILE
and NIX_LDFLAGS
$ cat > shell.nix <<EOF
with import <nixpkgs> {};
stdenv.mkDerivation {
name = "myenv";
buildInputs = [ zlib ];
};
EOF
[nix-shell:~] echo $NIX_CFLAGS_COMPILE
-isystem /nix/store/bjl5kk674rmdzzpmcsvmw73hvf35jwh8-zlib-1.2.11-dev/include -isystem /nix/store/bjl5kk674rmdzzpmcsvmw73hvf35jwh8-zlib-1.2.11-dev/include
[nix-shell:~] echo $NIX_LDFLAGS
-rpath /nix/store/d5dzr90q2wy2nlw0z7s0pgxkjfjv1jrj-myenv/lib64 -rpath /nix/store/d5dzr90q2wy2nlw0z7s0pgxkjfjv1jrj-myenv/lib -L/nix/store/5dphwv1xs46n0qbhynny2lbhmx4xh1fc-zlib-1.2.11/lib -L/nix/store/5dphwv1xs46n0qbhynny2lbhmx4xh1fc-zlib-1.2.11/lib
In $NIX_CFLAGS_COMPILE
we see that the include search path is extended by appending new directories
using the -isystem</code flag. For
$NIX_LDFLAGS
see that the library link path is extended
using the -L
flag. We also notice that in addition to library paths the linker gets instructed
to extend the RPATH
of the program using the -rpath
flag.
This is needed when the executable is executed since the runtime linker will read the RPATH
from
the elf header to figure out where to find shared libraries.
We can print the
RPATH
of executable using the patchelf
command.
nix-shell -p hello --command 'patchelf --print-rpath $(which hello)'
/nix/store/fivq0nbggp4y8mhy3ixprqd7qyn1hy2j-glibc-2.27/lib