All build systems for C and C++ are wrong. [Wednesday, 2019-02-13]
Since I haven’t blogged in years and I feel like starting again I thought it would be a good idea to start with something negative that always irked me, the state of build systems for C and C++.
Now don’t get me wrong, over time things have been getting slightly better in some regards, and much worse in others, but all in all things are still terrible.
In this blog post I’m going to cover why I think everything is awful and should be set on fire, and in the next I’m going to propose an alternative that other people are going to think is terrible and should be set on fire.
You need external tools, that you have to install
Why should I have to install external dependencies for building a C++ program?
Oh, your fancy build system doesn’t need a stupid DSL? What do you say? It uses Python/Groovy/node.js/Ruby/COBOL as a scripting language? Why, that’s wonderful, let me install ANOTHER toolchain to build my C/C++ project. Oh wait, the toolchain for the scripting language needs Perl and Python and a shell to be built? And also a C compiler I guess. Why are you doing this to me?
Do you know what tool every C/C++ programmer has always installed aside from a text editor? A fucking C/C++ compiler, because, and this might come as news to you, they’re going to build a C/C++ project.
It should not be a task runner
Most build sytems seem to conflate building things and running tasks, for instance you don’t want your build system to create packages for distributions, or running tests, or doing whatever, you want your build system to build, and that is it.
You need to learn some weird (and usually awful) DSL
Why the hell do I need to learn some godawful DSL some high or drunk programmer came up with in an afternoon when I already know C++?
Think about it, the syntax for Makefiles is terrible, the syntax for CMake
looks like someone started using a C preprocessor to streamline their
Makefile
generation, and then thought it was a good idea to extend into its
own program.
And don’t get me started on build systems that use formats that were never meant for direct human consumption (looking at you JSON and XML).
It must handle third-party dependencies
It doesn’t need to be fancy, but if your build system can’t download third-party libraries and other dependencies and build them, then it’s garbage.
No, I don’t want to use git submodules, they’re terrible, and no, I don’t want
to just run curl
in my Makefile
, that’s a terrible idea. And I seriously
hope you didn’t just mutter the word container.
Building in different configurations or for entirely different targets is hell
A build system should handle different configurations depending on the target and handle cross-compilation as easily as it handles building for the host.
This is especially important for embedded, but it’s also important for desktops and other garbage.
Modifying a dependency is practically impossible
Ever needed to change a line in a dependency of a dependency, or add a file, or do something before or after building? Sucks to be you, you can’t.
And if you just told me to just vendor all dependencies in tree, go back to whatever giant corporation you came from, and never talk to me or my duck ever again.