I want to build a C++ project with the newest possible standard (GNU) C++ headers etc., but using Clang as the compiler because reasons.
I’ve tried using an stdenv obtained by (more or less) overrideCC gcc11Stdenv llvmPackages_latest.clang, and noticed that Clang++ (version 13) is using C++ includes from gcc10.
Presumably this is because the LLVM packages in Nixpkgs are built in the default stdenv which is based on gcc10? If so, this is host build config leaking into the toolchain target config, which is not very good.
The other possibility, as always, is that I’m doing something stupid.
What do you mean by C++ includes from gcc? clang defaults to libstdc++ by default. If you want to come closer to a pure LLVM toolchain, use llvmPackages.libcxxStdenv. If you don’t care that it’ll use (native) cross compilation, use pkgsLLVM.stdenv for a full LLVM toolchain.
Note on llvmPackages.libcxxStdenv: ATM this will use GNU binutils which often causes linker errors in conjunction with C++ (see https://github.com/NixOS/nixpkgs/issues/142901). As a workaround you can do:
let
fullLlvm11Stdenv = pkgs.overrideCC pkgs.stdenv
(pkgs.llvmPackages_11.libcxxStdenv.cc.override {
inherit (pkgs.llvmPackages_11) bintools;
});
in
fullLlvm11Stdenv.mkDerivation { /* … */ }
I mean libstdc++, yes. I do want it it and not LLVM’s libcxx, but I want a version that is newer than 10, and I thought that deriving my env from gcc11Stdenv would get me there. And it does if I compile with gcc11, but not if I compile with llvmPackages_latest.clang.
Evidently I don’t understand what’s going on, thus this topic.
Right! Then I misunderstood you. How this works is a bit non-obvious, actually. I think it’s relatively difficult to build gcc and libstdc++ separately, so we need to get it from gcc (at the moment). For clang, the cc-wrapper takes care of injecting this into the flags passed to clang, for this it receives an argument called gccForLibs (if you want to follow the code in pkgs/build-support/cc-wrapper/default.nix). We can of course override this:
overrideCC llvmPackages.stdenv (
llvmPackages.clang.override {
gccForLibs = gcc11.cc; # the cc attribute is the *un*wrapped compiler we require
}
)
Great! Any more weird linker problems may be due to GNU binutils, so using bintools = llvmPackages.bintools; then would be worth a try in the override.