Adding IDE Support for Coroutines

C++20 was recently finalized, and I know that many of us in the community are eager to begin exploring its new features. This article outlines how to set up an IDE with autocomplete, reference tagging, and other modern features, such as coroutines.

This tutorial will also show how to modify the cppcoro library in order to use coroutines with C++20 and g++-10.

Which editors does this work with?

This tutorial is based on a C++ language server called ccls. It’s built on top of clang, and as clang is updated with additional and improved support for C++20, the functionality of ccls will improve too. The editors ccls works with include:

  • Visual Studio Code
  • Atom
  • Emacs
  • Vim/Neovim
  • Kakoune
  • Monaco Editor

I like ccls because it has excellent support for C++ overall, including the ability to evaluate constexpr functions in order to figure out the type of an expression for autocomplete and linting purposes. C++ has a lot of features that makes it very unfriendly to more traditional methods of autocomplete, and it’s very nice to see a language server with such good support for modern C++. The results of these constexpr evaluations are cached, so the editor remains very quick and responsive, even when working with a large code base.

Setting up ccls to use C++20

This is a relatively straightforwrd process, but I’ll explain it here for people who haven’t used it before in order to save you some time and googling. There are three steps here:

  1. Build ccls
  2. Add ccls as a plugin to your editor
  3. Configure compile_commands.json for your project so that ccls knows where to find libraries, and to use C++20 with coroutines

The ccls github repository provides a good explanation of steps 1 and 2, and I’ll link the instructions here:

In order to have support for C++20, build ccls with the most recent version of clang, clang 10. In order to understand the underlying syntax and semantics of C++, ccls uses clang. Building ccls with the most recent version of clang will give it the most up-to-date support for C++20 features. Clang understands what coroutines are, and as a result ccls does too. In addition, ccls can be built with versions of clang other than the system version, so if you’re not ready to update the system clang, that’s okay: just download a clang for ccls to use in a sub-folder of the ccls repo or any other convenient directory.

Is it difficult to add ccls as a plug-in? No. The steps depend on the editor of course, but ccls was designed to make this process as easy as possible. For visual studio code, there are three steps:

  • Download the ccls extension from the marketplace (the extension is just called ccls too)
  • If ccls isn’t on your path, set the launch command to point to where it’s installed This will be in the Release folder of the ccls repo, so [stuff]/ccls/Release/ccls
  • Optionally, disable the error-checking, code highlighting, and autotomplete sections of the Microsoft VSCode C++ extension if it’s enabled. The ccls language server is able to handle all of these on its own.

What if I already have ccls on my system? Re-build ccls with the most recent version of clang, as discussed above! If you re-build it in the same place as before, you shouldn’t have to change anything with your editors!

So what’s compile_commands.json and why do I need it?

This file provides information about what compiler settings you’re using, and where the compiler can find headers, libraries, and other useful components. Ccls uses it to figure out what version of C++ to use and find the libraries you’re using for your project, so that it can handle code autocompletion for them. If you’re using macros to enable or disable parts of the code, having compile_commands.json will also communicate those settings to ccls.

Let’s look at compile_commands.json for a really, really simple project:

[
    {
        "directory": "build",
        "command": "g++-10 -Iinclude -fcoroutines -std=c++20 src/main.cpp -o build/main",
        "file": "src/main.cpp"
    }
]

This project has three directories:

  • The build directory, where output files go
  • The include directory, where you can put libraries
  • The src directory, where we have main.cpp and other source files.

Traditionally, compile_commands.json is generated by CMake, however I wanted to provide a stripped-down version that still works in order to better illustrate what it’s doing (and provide a template if you wanted to write your own without using cmake). Adding -fcoroutines indicates that clang should recognize that we’re using coroutines, and using -std=c++20 informs clang to use other C++20 features as well.

compile_commands.json should go in the top-level directory of the project or workspace. In order to generate compile_commands.json automatically from CMake, just add the following line to CMakeLists.txt, and compile_commands.json will be generated in whatever directory you run CMake from:

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

Creating your first project with coroutines

While coroutines are officialy in the C++20 standard, standard library support for coroutines is delayed to the next release of the standard. Thankfully, there are third party libraries written by experts that implement full coroutine functionality.

updatedupdated2021-09-192021-09-19