Shell.nix -> flake.nix: cmake C++ header problems?

I’m trying to replace and old shell.nix that provided the development environment for some C++ code that needs to be compiled with cmake.

I have (essentially) replaced

{ pkgs ? import nix/pkgs.nix }:
  derivation = pkgs.callPackage (import ./nix/derivation.nix) {};

pkgs.llvmPackages_13.stdenv.mkDerivation {
  inherit (derivation) name;
  nativeBuildInputs = derivation.nativeBuildInputs ++ [

  buildInputs = derivation.buildInputs ++ [


  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05";
    flake-utils.url = "github:numtide/flake-utils";

  outputs = { self, nixpkgs, flake-utils, ... }:
        let pkgs = import nixpkgs {
              inherit system;
              overlays = [
                (final: prev: {
                  my-derivation = final.callPackage nix/derivation.nix {};
            devShell = pkgs.mkShell.override { stdenv = pkgs.clang13Stdenv; } {
              name = "Geant4 development environment";
              nativeBuildInputs = ++ [

              buildInputs = ++ [

This environment is normally activated with direnv, so I also changed .envrc from use nix to use flake.

The code being developed in this environment needs to be compiled with C++17, so the top-level CMakeLists.txt contains set(CMAKE_CXX_STANDARD 17).

Everything works as it should with the shell.nix, but when using flake.nix lots of compiler error along the lines of

In file included from /tmp/xxx/src/bbb/ccc/src/utils/
/tmp/xxx/src/bbb/ccc/src/utils/enumerate.hh:5:42: error: no member named 'begin' in namespace 'std'
          typename TIter = decltype(std::begin(std::declval<T>())),


At first I thought this was a symptom of the wrong version of the C++ standard being used, but after sifting through the diffs of the cmake-generated stuff, and thinking more about the error messages, I don’t really think that’s the case, any more.

It might be a more general problem with failure to find headers.

I’m struggling to see why/how the change from shell.nix to flake.nix would bring about this problem.

Any ideas?

OK, it’s nothing to do with shell.nix vs flake.nix but rather with the version of nixpkgs that they use. When I force the shell.nix to use the same nixos version as the flake, I get the same errors. When I downgrade the flake to use the same nixos version as the original shell.nix, the errors disappear.

So the prime suspect is now the version of cmake being used and how it deals with finding headers.

Whatever it is that’s messing things up in the new (more recent than 21.11) nixpkgs, it’s not cmake.

In now have two nixpkgs inputs in the flake, one for 21.11, one for 23.05, so that I can try upgrading just portions of the flake.

  • Old cmake, everything else new: fails.
  • New cmake, everything else old: works.
  1. When using the clang13Stdenv you shouldn’t have to add clang_13 to the inputs, the stdenv will do the right thing
  2. When using mkShell you should prefer packages over *Inputs
  3. You probably want to use cmake as a nativeBuildInputs if you insist on using *Inputs, same for cmake-language-server.

If those small refactorings do not fix your issue, can you please provide a MRE/SSCCE (sorry for the latter being HTTP)?

Hmm … clang13Stdenv does not exist in 21.11, but it works if I use clang_13.stdenv. I’m pretty sure that the clang13Stdenv spelling has worked at some stage in my stumbling around. Let’s see … clangNStdenv seems to lag behind clang_n.stdenv somewhat randomly:

nixpkgs pkgs.clangNStdenv pkgs.clang_N.stdenv
21.11 5-12 5-13
22.05 5-13 5-14
22.11 5-13 5-16
23.05 5-16 5-16

Using clang_13.stdenv (as the other spelling is not available in this version), I need clang_13 in either nativeBuildInputs, BuildInputs or packages; without it, the compilation fails. The failures look like confusion about the location of header files in my C++ code.

I can indeed move everything from *Inputs to packages and everything still works as before. Including the errors when bumping nixpkgs beyond 21.11.

(Every few months I go through the ritual of trying to understand the difference between these three. If I ever learn anything in process, it never sticks. The only thing that vaguely has stuck is that the names of the *Inputs make no sense to me in relation to their actual roles.)

I always aim to provide these. Extracting them from complex projects can be very time consuming, and given that I can get on with real work for now, by sticking to nixos 21.11, I might not be able to justify the time to pursue this one to its conclusion.

1 Like