How to create a working LLVM-based stdEnv for C++ development?

This afternoon I unknowingly entered into the rabbit hole of creating a C++ development environment that is based in LLVM.

I quickly realized that this sounds much easier than it is… The first hint was this Github issue:

I also made my way through this forum, and dug this out:

Endgoal

I would like:

  • A reproducible, isolated environment, where I can compile C++ applications using most of the LLVM tools (i.e. ofc. glibc is the exception, this will have to be the one that is provided by the system)
  • Be able to choose between libc++ and libstdc++, i.e. I want to really be able to switch this. If this would require two shells, that is ofc. fine as well.

Attempt

{
  description = "A LLVM-based C/C++ development environment";

  inputs.nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.2411.715519.tar.gz";

  outputs = { self, nixpkgs }:
    let
      supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
      forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f {
        pkgs = import nixpkgs { inherit system; };
      });
    in
    {
      devShells = forEachSupportedSystem ({ pkgs }: {
        default = pkgs.mkShell.override {
          stdenv = pkgs.pkgsLLVM.stdenv;
        } {
          packages = with pkgs; [
            clang-tools
            clang
            libcxx
            libunwind
            cmake
            codespell
            conan
            ninja
            doxygen
          ] ++ (if system == "aarch64-darwin" then [ ] else [ gdb ]);
        };
      });
    };
}

What is wrong with this attempt?

(some of the below issues are fixed in the above flake, but they were problems along the way)

  • missing headers, i.e. using gcc headers instead of llvm headers
  • uses ld instead of lld
  • cannot link libc++ (or libc++abi and libunwind), e.g. library not around or not in the linkers path
  • also, I was missing llvm-ar, llvm-nm, llvm-ranlib, etc. or the wrong ones were used during a build, i.e. ar, nm, instead of the llvm version.
  • undefined references to some symbols (I was compiling a reference library, so this should not have been a configuration error, but might be related to the previous point)

Notes

1 Like

Yeah it such a rabbit hole. Here’s another working config that is free of gcc. It should meet all your needs I assume. leetcode/flake.nix at 236ff9aed530ec6886ceb12acd1ab5ea17fed97b · Congee/leetcode · GitHub

FYI we’re currently using this as an overlay:

It has some bugs (I believe libgcc_s is still in the RPATH of outputs this toolchain produces; I’m not certain whether the llvm bintools override actually works) but accomplishes the general gist of “build with clang/libc++/libunwind” and doesn’t require excessive rebuilds (of clang or llvm tooling). For libstdc++ you could potentially try to add some conditionals to differentiate between the two.

Your flake does not compile for me on my PC. I currently don’t have access to it and try to debug it tomorrow.

This works fine for me:

I can choose btw. gcc and clang environment.
The gcc or clang stdenv is passed to package.nix where stdenv.mkDerivation is called.