Neko

Post

C++ Programming setup for noobs

Setting up my dev environment for C++ a few months ago was unsurprisingly non-trivial, so I wanted to share the things that would’ve helped me get it started much faster.

Some parts may vary for non-Mac users. More on this in the clangd section

Table of contents:

IDE: VSCode / Cursor

In the past I’ve worked with: Eclipse, CLion, Visual Studio, Vim – and VSCode is the best in terms of versatility + ease of setting up.

Though tbh the main reason I initially switched from Vim to VSCode was proper Jupyter Notebook support.

But it’s easy to have a very pleasant setup that doesn’t require me to really tweak much:

  • CodeLLDB for debugging
  • Clangd for language support - more on that in this section
  • CMake - syntax highlighting for CMakeLists.txt files

And Monokai as my Color Theme of choice

IDE screenshot How my IDE setup looks

My other must-have is the Vim extension — if you’re not familiar, I believe the speedup is worth investing a ~week of your life into developing the muscle memory for it.
LearnVim is probably a good starting point if you’re interested

CMake

CMake initially isn’t a nice build system to use, but it’s the most widespread & well-adopted for C/C++, so it’s worth to stick to it. Also, it’s turing-complete (is that a good thing? lol), basically meaning you can do anything with it.

I’ve taken a look at Bazel for C++ – the syntax is definitely much nicer, but then again, it’s mostly only used in Google projects (for example, I’ve had to battle with its usage in Mediapipe), and the syntax sugar leads to abstractions that are hard to debug once something goes wrong.

The very minimal example of CMakeLists.txt:

1
2
3
4
5
6
7
cmake_minimum_required(VERSION 3.10)
project(lib)

include_directories(${CMAKE_SOURCE_DIR})
file(GLOB SOURCES *.cpp)

add_executable(cct_tests ${SOURCES})

This works in a file setup like:

1
2
3
4
- main.cpp
- lib.hpp
- lib.cpp
- CMakeLists.txt

Understanding CMake basics is not trivial – I only actually grasped it after a month of close work with it (and wrote some notes about it). But I believe you can achieve this understanding much faster.
I found this article about CMake Basics that seems to be written in a more human way than usual, might be a good starting point.

For convenience, in all my C++ projects I have a build.sh that looks like this:

1
2
3
4
5
6
7
8
9
10
11
ADDITIONAL_FLAGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=1"
BUILD_TYPE="Release"
if [ "$DEBUG" = "1" ] || [ "$DEBUG" = "true" ]; then
    ADDITIONAL_FLAGS="$ADDITIONAL_FLAGS -DCMAKE_CXX_FLAGS='-fsanitize=address' -DCMAKE_C_FLAGS='-fsanitize=address' -DCMAKE_EXE_LINKER_FLAGS='-fsanitize=address'"
    BUILD_TYPE="Debug"
fi

mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE $ADDITIONAL_FLAGS
make -j$(nproc)

What this does is:

  • By default, running ./build.sh will simply build your project, and also generate a compile_commands.json (about which I’ll talk in the clangd section)
  • Running it like DEBUG=1 ./build.sh will enable running the debugger on the compiled executable, and enable the sanitizer

Linting: clangd

Clangd is a language server for C/C++ (and more) which integrates well if you’re using clang for compilation (which I kinda recommend)

If you are using GCC as your compiler, you can either:

A very common issue that I encountered while setting up C++ projects – the linter just doesn’t understand where to search for your header .h/.hpp files / where to find the libraries. Linter Issue Some examples of things that the linter gets weirdly wrong

But your compiler can provide your linter with those hints – just add -DCMAKE_EXPORT_COMPILE_COMMANDS=1 to your CMake flags (as in the build.sh script in the CMake section), and then setup a .clangd at the root of your project with

1
2
CompileFlags:
  CompilationDatabase: build/

And voila, your linter perfectly understands your codebase! (Given that it actually compiles)

Clangd also has clangd-tidy with advanced code checks – to enable, add this to the .clangd file:

1
2
3
4
CompileFlags:
  CompilationDatabase: build/
  ClangdTidy:
    Add: modernize-*

All available clangd-tidy checks are here.

After every .clangd update or major change to the build setup, you’ll need to reload the IDE for the linter to see the changes

Debugging

As mentioned, the CodeLLDB provides very simple debugging support. However, in VSCode for debugging you need to set up a launch.json file – my template is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "run_script",
            "type": "lldb",
            "request": "launch",
            "program": "${workspaceFolder}/build/run_script", 
            "args": [
                "--input",
                "lalala"
            ],
        },
    ]
}

Debugger screenshot How the debugger looks. Very convenient, and snappy fast for C++

This post is licensed under CC BY 4.0 by the author.