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
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 acompile_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:
- Configure clangd to work with gcc
- Use Intellisense which also uses compile_commands.json the wonders of which I’ll explain below
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. 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"
],
},
]
}
How the debugger looks. Very convenient, and snappy fast for C++