This is an automated archive made by the Lemmit Bot.

The original was posted on /r/nixos by /u/aurescere on 2024-09-03 16:44:30+00:00.


Hi all;

I’ve discovered what I would consider to be the “most correct” C development environment in that the tooling functions as I would expect. I’m sharing this information so others can benefit.

You may prefer a basic flake so nix develop can place you into a shell with everything you need. You can use flake-parts or flake-utils to abstract the selection of system; this is kept simple for demonstration purposes. Additionally, I’m not going to discuss setting up an editor, but you’ll want your editor to run clangd. The following flake will address everything else:

{
  description = "Demo";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
  };

  outputs = { self, nixpkgs, ... }:
    let
      system = "x86_64-linux";

      pkgs = import nixpkgs {
        inherit system;
      };

      stdenv = pkgs.gcc14Stdenv;
    in
    {
      packages.${system} = {
        default = stdenv.mkDerivation {
          name = "demo";
          src = pkgs.lib.cleanSource ./.;
          nativeBuildInputs = with pkgs; [
            cmake
            keepBuildTree
          ];
          buildInputs = with pkgs; [
            # your runtime dependencies
          ];
        };
      };

      devShells.${system} = {
        default = pkgs.mkShell.override {
          inherit stdenv;
        } {
          inputsFrom = [
            self.packages.${system}.default
          ];
          packages = with pkgs; [
            llvmPackages_17.clang-tools
          ];
          env = {
            CLANGD_FLAGS = "--query-driver=${pkgs.lib.getExe stdenv.cc}";
          };
          shellHook = ''
            ln -sfn ${self.packages.${system}.default}/.build/source/build/compile_commands.json .
          '';
        };
      };
    };
}

Here, I choose to use GCC 14.2 and CMakeLists.txt (not shown) is set to use C23 and to output the compilation database. The compilation database is placed into the working directory when you enter the shell via a symlink. keepBuildTree is important for preserving the compilation database in the nix store. Without it, only the binary outputs would be preserved. cleanSource puts the build directory in a predictable location. Crucially, you do not need to struggle to generate a “comprehensive” compilation database—headers are fed to the compiler via the wrapper scripts in nixpkgs. You can use the basic cmake- or meson-generated output and I would recommend that.

--query-driver is required and can be provided to clangd in a variety of ways (e.g. in your editor’s LSP configuration for running clangd with $NIX_CC), but I choose to provide it in my flake. If you don’t provide this, clangd won’t consider itself to ‘have permission’ to run gcc and you’ll end up with quirks like duplicated completions and #include insertions with quotations rather than brackets (for system headers, for example).

There is significance to llvmPackages_17.clang-tools. This is the only version of clang-tools where clangd correctly suggests completions for an assortment of items, like EXIT_SUCCESS and BUFSIZ. I did document this here at one point: . With this setup, however, you can use the latest libc features (e.g. char8_t from uchar.h will be suggested and the correct #include will be inserted).

If you are aware of any improvements to this configuration, I’d be glad to refine this further.