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.
Build system
Starting with an empty git repo, first thing I like to do is just to
create 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 .gitignore
and commit the link to compile_commands.json
to the repo for
convenience. This concludes my first commit:
|
|
Having the compile_commands.json
automatically updated by meson
means that LSP within my editor will always work, which is great!
Pre-commit hooks
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 commitizen
:
|
|
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
github/pocc which
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
# macOS
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!
|
|
clang-format
Now, I’ve added .clang-format
to 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"
Editors 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 clang-format
plugin
available as well which does the same thing.
Conventional commits
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.
Changelogs
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.