How can I build self-hosted clang in nix?

I’m trying to build a self-hosted clang in nix.

By reference to other pages (NixOS Wiki: Using Clang instead of GCC) and threads (Nix discourse: Use Clang without GCC’s C++ standard library), I tried (variations on):

nix-build -E "with import <nixpkgs> {}; pkgs.clang-tools.override{ stdenv = pkgs.clangStdenv.override (x: {cc = x.cc.override(_: {libcxx = llvmPackages.libcxx;}); }); }"

But this appears to not be working:

$ nix-build -E "with import <nixpkgs> {}; pkgs.clang-tools.override{ stdenv = pkgs.clangStdenv.override (x: {cc = x.cc.override(_: {libcxx = llvmPackages.libcxx;}); }); }"
/nix/store/45whyxm1y5mjf5g12c0wjvjcmrxxqdaz-clang-tools-10.0.1
$ tail -n 1 /nix/store/45whyxm1y5mjf5g12c0wjvjcmrxxqdaz-clang-tools-10.0.1/bin/clangd
exec -a "$0" /nix/store/6pzqj9q656vc1msa675k75hmhsrfizsy-clang-10.0.1/bin/$(basename $0) "$@"
$ ldd /nix/store/6pzqj9q656vc1msa675k75hmhsrfizsy-clang-10.0.1/bin/clangd | grep gcc
libstdc++.so.6 => /nix/store/c10296m7xgm3ksibcklb2xf48jr635x3-gcc-9.3.0-lib/lib/libstdc++.so.6 (0x00007f55d359b000)
libgcc_s.so.1 => /nix/store/0c7c96gikmzv87i7lv3vq5s1cmfjd6zf-glibc-2.31-74/lib/libgcc_s.so.1 (0x00007f55d343e000)

Am I missing a step? Or mis-interpreting the output of ldd? I realize that clangd is itself a script, I did reproduce the environment that creates, but it makes no difference (and I wouldn’t expect it to). I’ve excised that from my example above for simplicity.

I tried the same setup with powertop, and that does work; maybe clang-tools is special?.

I also tried nix-build -E "with import <nixpkgs> {}; pkgs.clang.override{ stdenvNoCC = pkgs.llvmPackages.libcxxStdenv; }" , with similar results.

The definition for clang-tools is:

  clang-tools = callPackage ../development/tools/clang-tools {
    llvmPackages = llvmPackages_latest;
  };

When you override stdenv for clang-tools, you do not impact llvmPackages, which is likely the package that brings in the GCC C++ stdlib dependency.

I have tried to workaround this with:

nix-build -E "with import <nixpkgs> {}; let llvmPackages = pkgs.llvmPackages_11.override { stdenv = pkgs.libcxxStdenv; }; in pkgs.clang-tools.override (x: { inherit llvmPackages; })"

and the same with llvmPackages_12 and llvmPackages_7, but in all three cases the llvmPackages build fails as it fails one test (I think it is always: LLVM :: tools/gold/X86/parallel.ll. I have not found a way to disable the tests for that package.

I was therefore unable to build a self-hosted clang, but I thing the following uses of nix show-derivation show that once you figure out how to silence that one failing test, this should give you what you want.

This first invocation:

$ nix show-derivation $(nix show-derivation $(nix-build -E "with import <nixpkgs> {}; pkgs.clang-tools.override{ stdenv = pkgs.clangStdenv.override (x: {cc = x.cc.override(_: {libcxx = llvmPackages.libcxx;}); }); }") | jq -r '[.[]][0]'.env.stdenv) | jq -r '[.[]][0].inputDrvs' | grep -E 'clang|gcc'
  "/nix/store/a6xkjam6w10j8hf2nmin6ph56jyks2b2-clang-wrapper-7.1.0.drv": 

shows that the stdenv used to build clang-tools is indeed clang based. The one-liner retrieves the stdenv, runs nix show-derivation on it, and checks for any clang or gcc input derivation in stdenv.

This second snippet show that the clang used as an input to clang-tools (not the stdenv) is built with a gcc-based stdenv:

$ nix show-derivation $(nix-build -E "with import <nixpkgs> {}; pkgs.clang-tools.override{ stdenv = pkgs.clangStdenv.override (x: {cc = x.cc.override(_: {libcxx = llvmPackages.libcxx;}); }); }") | jq -r '[.[]][0]'.inputDrvs | grep clang 
  "/nix/store/658j0062zyxcr2574n7xxqm9nxksmzvp-clang-10.0.1.drv": [
$ nix show-derivation $(nix show-derivation /nix/store/658j0062zyxcr2574n7xxqm9nxksmzvp-clang-10.0.1.drv | jq -r '[.[]][0]'.env.stdenv) | jq -r '[.[]][0].inputDrvs' | grep -E 'clang|gcc' 
  "/nix/store/hhdqlmw9z0kmnhfcc48ng6bfd8ng4fy0-gcc-wrapper-9.3.0.drv": [
  "/nix/store/ll8mjfvnhd3rq0vf56qrxqxa0iqvb8i1-gcc-9.3.0.drv": [

Running similar two commands (switching to nix-instantiate given that nix-build does not work) on the command I proposed above, we see that it should result in a clang built using a clang-based stdenv:

$ nix show-derivation $(nix-instantiate -E "with import <nixpkgs> {}; with import <nixpkgs> {}; let llvmPackages = pkgs.llvmPackages_11.override { stdenv = pkgs.libcxxStdenv; }; in pkgs.clang-tools.override (x: { inherit llvmPackages; })") | jq -r '[.[]][0]'.inputDrvs | grep clang 
warning: you did not specify '--add-root'; the result might be removed by the garbage collector
  "/nix/store/c83qzda7iv7ahm2972vdyqnaw1ci4cl2-clang-11.0.0.drv": [
$ nix show-derivation $(nix show-derivation /nix/store/c83qzda7iv7ahm2972vdyqnaw1ci4cl2-clang-11.0.0.drv | jq -r '[.[]][0]'.env.stdenv) | jq -r '[.[]][0].inputDrvs' | grep -E 'clang|gcc'  
  "/nix/store/ds5l3bf7bpr43dlk3bfrg0n1ccax45kx-clang-wrapper-7.1.0.drv": [