Skip to main content

C++ Setup for Neovim

There are a plethora of different ways to setup a C++ development environment in Neovim. Here’s one possible way that I landed on after a number of (unsuccessful) attempts on Linux, integrated as a part of my dotfiles.

Mason and Lsp-Zero (optional)

mason.nvim is a package manager for Neovim that enables the installation of different utilities (mainly LSP/DAP servers and linter/formatters).

lsp-zero.nvim provides a sweet spot between an out-of-the-box experience and configurability for setting up language-specific functionalities. The barebones plugin configuration with support for Mason for packer.nvim is as below (source):

use {
    'VonHeikemen/lsp-zero.nvim',
    branch = 'v2.x',
    requires = {
        -- LSP Support
        { 'neovim/nvim-lspconfig' }, -- Required
        {
            -- Optional
            'williamboman/mason.nvim',
            run = function()
                pcall(vim.cmd, 'MasonUpdate')
            end,
        },
        { 'williamboman/mason-lspconfig.nvim' }, -- Optional

        -- Autocompletion
        { 'hrsh7th/nvim-cmp' }, -- Required
        { 'hrsh7th/cmp-nvim-lsp' }, -- Required
        { 'hrsh7th/cmp-buffer' }, -- Optional
        { 'hrsh7th/cmp-path' }, -- Optional
        { 'saadparwaiz1/cmp_luasnip' }, -- Optional
        { 'hrsh7th/cmp-nvim-lua' }, -- Optional

        -- Snippets
        { 'L3MON4D3/LuaSnip' },    -- Required
        { 'rafamadriz/friendly-snippets' }, -- Optional
    }
}

Setting up clangd and clang-format

After the prerequisites are installed, there may not be any immediate changes. That is because you’ll have to provide the Clang compiler, which clangd is based on, with explicit guidance on compilation. There are different ways to supply the compilation flags to clangd, but for a simple sandbox, a .clangd file (or a compile_flags.txt) may suffice. A Cmake-generated compile_commands.json compilation database file could also do the job for larger projects. The flags are apparently version/platform specific, so double check the system settings!

CompileFlags:
  Add: [-std=c++20, -Wall, -I/usr/include/c++/11, -I/usr/include/x86_64-linux-gnu/c++/11]

Now that the errors are gone, it’s time to fine tune the formatter, clang-format. This can simply be done by adding a .clang-format file with different options at the root directory of the project. And that’s it!

Further Troubleshooting

One error that took me a particularly long time figuring out the root cause was the error message bits/c++config.h file not found that occured in headers. I tried including the directories that apparently included the lacking file, but the issue persisted. To dig deeper, I tried compiling (with verbose mode) a small test file with the following flags with clang++.

$ clang++ --std=c++2a -Wall --verbose main.cpp -o test \
    -I/usr/include/c++/11 \
    -I/usr/include/c++/x86_64-linux-gnu/11

clang version 17.0.0 (https://github.com/llvm/llvm-project.git f5a8802fa6021ab05dd126ea64f594f84c6c90d9)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/woosang.kang/.local/share/llvm-project/build/bin
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/11
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/12
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/12

So it turned out to be that I’ve installed and attempted to include an older version (11) of libstdc++ that clang wasn’t using! After installing libstdc++-12-dev along with g++-12-multilib and gcc-12-multilib, all the features were working seamlessly without any additional configuration files.