My C++ setup for personal projects
Here’s a quick overview of my repo setup for any new C++ projects that I create. I’m gonna start with an empty repo and bring it up to an initial stage where all my preferred tooling is available and ready.
Empty repo scaffolding
Here’s the link to the repo, if you’re not interested in the walk through.
Starting with an empty git repo, first thing I like to do is just to
main.cpp with an empty
main function. I use vim-luasnips so, creating that is instantaneous.
By now, I’m sure you know that I like
meson and for personal projects it’s
perfect! So, you guessed it, I establish the build system:
This will create
meson.build which is a good starting point.
Sometimes, you need to adjust the filenames used to create the
executable so, I do that. Having the build system, I usually bootstrap
the build directory and link the compilation database:
I mostly use
bld as the build directory so, I add it to
and commit the link to
compile_commands.json to the repo for
convenience. This concludes my first commit:
compile_commands.json automatically updated by
means that LSP within my editor will always work, which is great!
Right, since this is a C++ project… I’ll continue with Python poetry. Wait, what?
Yes, that’s not a mistake. Usually people have their own pre-commit scripts or install them manually, but I decided that it’s not really worth to be a purist and reinvent the wheel as far as that goes. Python tooling is good and it save a lot of manual steps. I realise that this may not be a preferred way for everyone, it does work for me though so, hear me out :).
Okay, disclaimer aside, let’s continue. Yep, Python poetry:
This will create
pyproject.toml. The contents are not really that
important as I mostly gonna use it as a development tools package manager. Having
that, let’s install some basic tools. First pre-commit hook:
For conventional commits support, I’ll need
With that done, it’s time to create
pre-commit config file:
Here’s my preferred set of hooks:
First three (trailing-whitespace, end-of-line-fixer, check-added-large-files) are pretty standard, just to prevent polluting the repo with white space noise and rubbish binary files.
I like to use hooks from
integrate clang tools. Since clang requires gcc ang libstdc++, I don’t
install it via
poetry but rather rely on versions provided system
wide, managed by OS package manager:
# Arch linux
pacman -S clang
brew install llvm
Your mileage may vary but hopefully you get the gist.
Additionally, I recently became a fan of conventional commits so, I’m integrating a tool to validate my commits against that as well.
Now it’s time to install the hooks:
Since, pre-commit is run locally, re-installation of hooks is required on every freshly cloned repo so, to ease the burden of doing this, I usually add a small script to the repo:
The contents of which are:
All of that concludes the second commit:
This already ran all the configured hooks which is great!
Now, I’ve added
pre-commit hooks but I didn’t configure it yet.
clang-format --style=Google --dump-config >.clang-format
I usually just start with Google style and adjust it as I go. The default template is ready to be committed:
git add .clang-format
git commit -m "build: add clang-format configuration"
All of this integrates nicely with editors I use. I mostly use neovim
but occasionally jump into emacs - no specific reasons for that really, just
depends on the mood :). In nvim, I use
vim-codefmt which picks up
clang-format configuration automatically and applies formatting
every time when saving files. In emacs, there’s
available as well which does the same thing.
This is something that I really enjoy. The idea is that, the commit format is kind of “structured”. Thanks to that, it’s possible to generate changelogs from git commits very easily. Read through the conventional commits web page for more details.
I’ve installed commitizen as a
commit-msg hook so, if the commit message doesn’t adhere to the
format, it will be rejected. You can try it out yourself. If you clone
my test repo, run the
scripts/setup_env.sh - which installs all the discussed tools,
commitizen will become part of the
pre-commit hooks so committing i.e.:
Similarly, if I’m committing from either emacs magit or vim-fugitive, the commit will be rejected.
With all of this in place, generation of a changelog is as easy as:
poetry run cz changelog
Just as an example, the following git history:
Will result in
CHANGELOG.md looking like so:
Why do I like this setup?
I think that using python poetry to manage dependencies has a lot of advantages. There’s less effort required to manage the tooling. Integrating new tools is easy. It also helps to create reproducible development environments so, no special setup instructions are required for new devs working on your project.
This of course changes a lot and I’m not saying that this is best setup ever period. I’m sure that it’s gonna evolve further and possibly I’m gonna find a better approach to some of the solutions I currently use.