NixOS: Simple C++ development in VSCode

Context
I’m trying to set up a basic development environment for C++ in VSCode on NixOS. It turns out, this is surprisingly difficult! Even for a simple project that only uses the standard library.

Here’s the project I’m working on. It builds fine with Nix, and the shell behaves as expected.

My VSCode setup is very simple; the only two extensions installed are vscode-clangd and direnv. Here’s the relevant chunk of my NixOS config (using home-manager):

  # VS Code configured via home-manager, with extensions
  programs.vscode = {
    enable = true;
    extensions = with pkgs.vscode-extensions; [
      llvm-vs-code-extensions.vscode-clangd
      mkhl.direnv
    ];
  };

Problem
The problem is that clangd seems not to pick up any header files. When I open hello.cpp from the project in VSCode, I get messages like 'Use of undeclared identifier ‘std’`, along with angry red squiggles.

Reading up on clangd, it seems like it expects a compile_commands.json file, which it can use to find libraries & headers. Outside NixOS, people often use the bear tool to generate this. I tried it with no change in the behavior. I also found another thread about clangd and standard headers, where @danielbarter bravely created a custom Python server called mini_compile_commands to generate clangd’s compile_commands.json file.

Questions

  1. How can I get this working?
  2. Is there a standard way to configure clangd for a project on NixOS? It’s recommended on the wiki page for C, but setup is unclear.
1 Like

Hey @kylegentle!

There isn’t currently a standard way for generating compile_commands.json files using nix, although i do think we should have one. GitHub - danielbarter/mini_compile_commands is not the perfect solution by any means, but at least for working on top of nix, I think it is the most reliable.

If you want to use the project with your shell.nix, you can do so as follows:

  1. clone mini_compile_commands
  2. override the standard environment for your shell using mini_compile_commands
{ pkgs ? import <nixpkgs> {} }:
# update this path to the location of the mini_compile_commands repo
let mcc-env = (pkgs.callPackage /home/danielbarter/mini_compile_commands {}).wrap pkgs.clangStdenv;
in (pkgs.mkShell.override { stdenv = mcc-env;}) {
    name = "hello";
    buildInputs = []; # use a clang stdenv rather than including as build inputs
}

now in this environment, you can run mini_compile_commands_server.py. While the server is running, any time the compiler is invoked, the exact command will be sent to the server. Once you are finished building, then kill the server with a sigint (kill -s SIGINT server_pid) and it will write a compile_commands.json for you. Alternatively, just create two shells in the environment and run the server in one.

Generally, you do this once when you first build, and you only need to redo it when you make large changes to the project structure or add new dependencies.

1 Like

Thanks for the prompt & useful reply @danielbarter!

Your mini_compile_commands project works well. I updated the nix-cpp-hello repo to incorporate the guidance you shared here, and outline a basic workflow setting up a C++ environment in VS Code on NixOS. Hopefully it will be useful to others! :smile:

1 Like