Re:Comparing C/C++ unity build with regular build on a large...
by jjmarr on Wednesday April 01, 2026 @10:04PM
(#47609192)
If you're doing single-core builds, you will get impressive speedups from unity builds.
This is because C++ compilers spends a lot of time redundantly parsing the same headers included in different .cpp files.
Normally, you get enough gains from compiling each .cpp file in parallel that it outweighs the parsing, but if you're artificially limited in parallelism then unity builds can pay for themselves very quickly as they did in the article.
C++20 modules try to split the difference by parsing each header once into a precompiled module, allowing it to reuse work across different .cpp files.
Unfortunately, it means C++ compilation isn't embarrassingly parallel, which is why we have slow buildsystem adoption.
Re:Comparing C/C++ unity build with regular build on a large...
by torginus on Thursday April 02, 2026 @04:07AM
(#47611394)
The problem is that due to how templates work, each compilation unit will end up with its own copy of templated function, which creates extra work, code bloat etc.
The compiler also doesn't really inline or optimize functions as well across object boundaries without link-time optimization.
But the linker is single threaded and notoriously slow - with LTO, I wouldnt be surprised it would take up as much time as the whole unity build, and the results are often suboptimal.
Also, C++ syntax is notoriously hard and slow to parse, the clang frontend takes almost as much time to run as LLVM itself.
So probably modules would help a lot with parallel parsing, but that would help unity builds just as much.
Re:Comparing C/C++ unity build with regular build on a large...
by jjmarr on Thursday April 02, 2026 @05:48PM
(#47620620)
> each compilation unit will end up with its own copy of templated function, which creates extra work, code bloat etc.
Yes, that's what causes the parsing bottleneck. Unity builds don't need to create multiple copies of templated functions.
C++20 modules could fix that because the function is parsed before substitution. Tbd on if that optimization works yet, I tried it on Clang 18 and it didn't.
> But the linker is single threaded and notoriously slow
I think most linkers have parallel LTO and `mold` provides actual parallel linking.
Re:Comparing C/C++ unity build with regular build on a large...
by PaulHoule on Monday April 06, 2026 @11:58AM
(#47662616)
(1) The demand for fast compilation in languages like Go came from the terrible experience people had with C++
(2) The road to C++ was quite empirical, path-dependent, and "worse is better". Languages like PL/I, Ada, and the Modula series were aiming for the same niche but had a combination of bad ideas, excessive complication and being born just before we realized that every future OS outside the embedded space would look enough like POSIX that C's API for I/O would be portable
(3) Today I'm a little frustrated that we don't have languages that trade a slower build for more expressiveness or flexibility. Like I wish Python really exposed that PEG grammar. It doesn't have to be much harder to add an
unless(X):
statement that works like
if(!X):
in a language like Python than like LISP, it's like a few lines to add a production for the statement, another to rewrite the statement inside the compiler and it's done.
Was it a choice because you wanted to compare only single core performances?
This is because C++ compilers spends a lot of time redundantly parsing the same headers included in different .cpp files.
Normally, you get enough gains from compiling each .cpp file in parallel that it outweighs the parsing, but if you're artificially limited in parallelism then unity builds can pay for themselves very quickly as they did in the article.
C++20 modules try to split the difference by parsing each header once into a precompiled module, allowing it to reuse work across different .cpp files.
Unfortunately, it means C++ compilation isn't embarrassingly parallel, which is why we have slow buildsystem adoption.
The compiler also doesn't really inline or optimize functions as well across object boundaries without link-time optimization.
But the linker is single threaded and notoriously slow - with LTO, I wouldnt be surprised it would take up as much time as the whole unity build, and the results are often suboptimal.
Also, C++ syntax is notoriously hard and slow to parse, the clang frontend takes almost as much time to run as LLVM itself.
So probably modules would help a lot with parallel parsing, but that would help unity builds just as much.
Yes, that's what causes the parsing bottleneck. Unity builds don't need to create multiple copies of templated functions.
C++20 modules could fix that because the function is parsed before substitution. Tbd on if that optimization works yet, I tried it on Clang 18 and it didn't.
> But the linker is single threaded and notoriously slow
I think most linkers have parallel LTO and `mold` provides actual parallel linking.
Any new modern language that can't compile 1 million lines in a couple seconds (without optimizations) should be considered a failure.
(2) The road to C++ was quite empirical, path-dependent, and "worse is better". Languages like PL/I, Ada, and the Modula series were aiming for the same niche but had a combination of bad ideas, excessive complication and being born just before we realized that every future OS outside the embedded space would look enough like POSIX that C's API for I/O would be portable
(3) Today I'm a little frustrated that we don't have languages that trade a slower build for more expressiveness or flexibility. Like I wish Python really exposed that PEG grammar. It doesn't have to be much harder to add an
statement that works like in a language like Python than like LISP, it's like a few lines to add a production for the statement, another to rewrite the statement inside the compiler and it's done.