gcc11Stdenv and clang

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.

1 Like

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 LLVM stdenvs with LLD outside of pkgsLLVM · Issue #142901 · NixOS/nixpkgs · GitHub). 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.

Have you tried using clang12Stdenv?

Of course.
This is the content of ${clang12Stdenv.cc}/nix-support/libcxx-cxxflags on my system:

-isystem /nix/store/2dv93bbc06c7zg866qid73j3r36zz3jx-gcc-10.3.0/include/c++/10.3.0 -isystem /nix/store/2dv93bbc06c7zg866qid73j3r36zz3jx-gcc-10.3.0/include/c++/10.3.0/x86_64-unknown-linux-gnu 

Every clang*Stdenv is like that.

(On one hand, this explains why using gcc11Stdenv does not help me. On the other hand, what short of building my own LLVM using gcc11Stdenv would?)

Oh yea, I forgot that on linux, it’s weird, and not a fully llvm+clang stdenv

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
  }
)
2 Likes

Neat, thank you! In fact, it almost works.
Almost because link fails, probably due to the wrapper’s libcxx-ldflags being empty?

It’s empty for normal clang as well, so seems unlikely. What is the error you are seeing?

Operator error indeed, sorry for the noise.

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.