I wish more C/C++ projects used "unity builds" -- there's only one translation unit containing all the code, usually by #include-ing all the .c and .cpp files. It makes "build configuration" incredibly easy by largely doing away with it. And C/C++ compilers just copy paste your code in via the preprocessor when doing #include of headers, etc., anyway, so it's not a wacky concept at all.

- It's just one compiler invocation. If you want to support multiple compilers, just write that one invocation for each one. Usually clang and gcc will be the exact same. cl and clang-cl similarly. Even if you support multiple platforms, writing N command lines for N platforms is usually less characters than any build system out there, and simpler, and less opaque as well.

- You can guarantee exactly the flags you want are being set. No more problems where you set -fwrapv or -march or whatever on one sub-project, but forgot on another, etc., or trouble figuring out what's the "CMake way" of specifying something. Getting these types of flags working with build tools becomes quite frustrating and error prone the more specific your requirements are.

- Not something I dealt with working at trading companies, but distro package maintainers can very easily patch in their own flags, or more often can get by without even that if your unity build can just put $CFLAGS or $CXXFLAGS at the end of the command line.

- Wouldn't tout this as a major benefit as it has saved me maybe once, but it basically forces a compiler error for certain violations of the One Definition Rule, because the compiler can see the duplicate and conflicting definition at compile time, instead of the linker silently picking one of the conflicting definitions and masking the problem.

I've found that there are ample ways to keep compilation speed pretty reasonable (we're talking <10 seconds), even compiling all code at once on large, complicated projects. The general solution is to not let your compile times get crazy in the first place, which means not using a lot of general purpose external dependencies or templates.

Another technique is, for dev, split the unity build in two. Unity build of files you're actively working on or of files you need to use -O0 or -0g on for a while, and unity of the rest, and link.

Games people often carry that idea of a split unity build further. Split the structure of the code itself, and have an "infrastructure" unity build, a "business logic" unity build, and the infra code actually dynamically loads the logic .so/.dll, and can reload it on demand (so you can iterate fast on logic, without recompiling or even linking your infra code). I don't work on games so this hasn't been worth it for my projects, but I have definitely worked on projects structured with a control process (slow, smart, size not a critical issue), and a worker process (fast, dumb, size critical), which gets you pretty much the same structure by different means. You can easily get 1s turnaround for builds of the worker. I never used this structure specifically in order to help dev turnaround, rather it was intrinsic to the project requirements and faster dev was a happy knock-on effect.

I'd be a happy man if I saw a post like this in the future that at least started with:

If you see build.sh or build.ps1/bat, just run that and you're done.

Edit, PS: "unity build" obviously has nothing to do with Unity the game engine. In fact, I never even called them "unity builds" at work, I had never heard that term. I always called it a blob build, or a STU (single translation unit) build, or whatever analogy was funny that day.