C: Difference between revisions

imported>Mic92
imported from old wiki
 
(11 intermediate revisions by 7 users not shown)
Line 1: Line 1:
This article gives practical advices when working on C/C++ projects with Nix.
This is a collection of recipes for working on C/C++ projects with Nix.
The article does not just apply to C but also C++.
They do not just apply to C but also C++.


== Differences between nixpkgs and the rest ==
== Differences between nixpkgs and the rest ==


The way nixpkgs and its stdenv handles compiling and linking is very different from other linux distributions.
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. <code>/usr/include</code>, where the compiler will  
In more conventional Linux distributions it's usual that header files are put into well known paths i.e. <code>/usr/include</code>, 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 will find them. Dynamically linked libraries will have a  run-time linker (also known as <code>ld.so</code>) set as an interpreter.
look for them. Same is true when linking against libraries, which are put in a few places, where the build-time
linker will find them. Dynamically linked libraries will have a  run-time linker (also known as <code>ld.so</code>) set as an interpreter.
This linker reads <code>/etc/ld.so.conf</code> to figure out where to find libraries.
This linker reads <code>/etc/ld.so.conf</code> to figure out where to find libraries.
In nixpkgs in contrast this information is provided by environment variables.
In nixpkgs in contrast this information is provided by environment variables.
Line 40: Line 38:


<syntaxHighlight  lang=console>
<syntaxHighlight  lang=console>
$ cat > shell.nix <<EOF
$ cat > shell.nix <<EOF ;nix-shell
with import <nixpkgs> {};
with import <nixpkgs> {};
stdenv.mkDerivation {
stdenv.mkDerivation {
   name = "myenv";
   name = "myenv";
   buildInputs = [ zlib ];
   buildInputs = [ zlib ];
};
}
EOF
EOF
[nix-shell:~] $ echo $NIX_CFLAGS_COMPILE
[nix-shell:~] $ echo $NIX_CFLAGS_COMPILE
Line 105: Line 103:


== Hardening flags ==
== Hardening flags ==
To improve the security of applications the wrapper also injects additional hardening compile flags into the application.
To improve the security of applications the wrapper also injects additional hardening compile flags into the application. These nix flags enable different compiler flags, as seen in the [https://nixos.org/nixpkgs/manual/#sec-hardening-in-nixpkgs manual].
Under some circumstances this can make programs fail to build or function.
Under some circumstances this can make programs fail to build or function. For example, the `fortify` flag enables the `-O2` optimization level -- if you want to change this, you need to disable the `fortify` flag and re-add the compiler flags manually (`env.NIX_CFLAGS_COMPILE = [ "-O" "....."]`).
To disable all hardening options one can export the environment variable <code>hardeningDisable="all"</code>.
To disable all hardening options one can export the environment variable <code>hardeningDisable="all"</code>.
This also works for derivations like that:
This also works for derivations like that:
Line 117: Line 115:
</syntaxHighlight>
</syntaxHighlight>


It is also possible to only enable certain parts:


It is also possible to only disable certain parts, for example <code>-Werror=format-security</code>:


<syntaxHighlight lang=nix>
<syntaxHighlight lang=nix>
Line 203: Line 201:
[nix-shell:~] $ echo 'int main {}' > hello.c
[nix-shell:~] $ echo 'int main {}' > hello.c
[nix-shell:~] $ cmake .
[nix-shell:~] $ cmake .
</syntaxHighlight>
== gcc multilib ==
<code>pkgs.gcc_multi</code> exports a <code>gcc</code> in a multilib variant, which can produce 32-bit and 64-bit x86 code at the same time. However, <code>gcc_multi</code> falls back to the gcc version coming from <code>pkgs.gcc</code>. To use a specific version of gcc, you might use something like that:
<syntaxHighlight lang=nix>
{
  gcc11_multi = pkgs.wrapCCMulti pkgs.gcc11;
  // or
  gcc13_multi = pkgs.wrapCCMulti pkgs.gcc13;
}
</syntaxHighlight>
</syntaxHighlight>


Line 272: Line 282:
gcc (GCC) 8.3.0
gcc (GCC) 8.3.0
</syntaxHighlight>
</syntaxHighlight>
* Available gcc based stdenv variants: gcc{49,6-12}Stdenv, gccMultiStdenv (32bit/64bit mixed support)
* Available clang based stdenv variants:  llvmPackages_[5-13].{stdenv,libcxxStdenv}, clangMultiStdenv (32bit/64bit mixed support)
Those stdenv instances can be also constructed using the <code>overrideCC</code> function:
Here we are creating a shell environment that will always have the latest available gcc:
<syntaxHighlight lang=nix>
(overrideCC stdenv gcc_latest).mkDerivation {
  name = "env";
}
</syntaxHighlight>
Note that this will only affect compiler and not the used linker. To overwrite the linker and maybe also the used libc
Check out the <code>wrapCCWith</code> example in the next section.
See also: [[Using Clang instead of GCC]]


== Get a compiler without default libc ==
== Get a compiler without default libc ==
Line 332: Line 359:
== Use a clang compiled from source ==
== Use a clang compiled from source ==


Unwrapped compilers usually do not any access to libraries/headers in nix. This is an issue if you work on the clang/llvm code base.
Unwrapped compilers usually do not have any access to libraries/headers in nix. This is an issue if you work on the clang/llvm code base. Assuming you have built llvm/clang like this
Assuming you have built llvm/clang like this


<syntaxHighlight lang=console>
<syntaxHighlight lang=console>
Line 387: Line 413:


[[Category:Languages]]
[[Category:Languages]]
[[Category:Cookbook]]