`make` takes over 3 minutes when no source has changed: why?

I am trying to understand the build process of llvm + clang from source.
These are the commands I executed, on a Linux Mint 19 Tara machine with a i5-6600T CPU @ 2.70GHz and 24GB of RAM:

git clone https://github.com/llvm/llvm-project.git llvm.git
mkdir llvm.bld
cd llvm.bld
cmake ../llvm.git/llvm -G "Unix Makefiles" -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_BUILD_TYPE=Release
time make -j 4 

The first time, this takes a few hours to compile; that is to be expected. However, when I run make -j 4 again without touching any source files, it still takes more than 3 minutes. Why is that? Here are the actual timings I got on one run:

real 2m3.950s
user 3m15.365s
sys 0m14.494s

To get better insight, I tried time make VERBOSE=1 so that it shows what commands it is executing. It seems to be calling cmake recursively, e.g.:

/usr/bin/cmake -H/home/johan/work/llvm.git/llvm -B/home/johan/work/llvm.bld --check-build-system CMakeFiles/Makefile.cmake 0

It is also calling make recursively, possibly to generate dependencies, e.g.:

make -f lib/Demangle/CMakeFiles/LLVMDemangle.dir/build.make lib/Demangle/CMakeFiles/LLVMDemangle.dir/depend

Finally, it also seems to be regenerating some *.inc files, e.g.:

cd /home/johan/work/llvm.bld/tools/clang/include/clang/StaticAnalyzer/Checkers && ../../../../../../bin/clang-tblgen -gen-clang-sa-checkers -I /home/johan/work/llvm.git/clang/include/clang/StaticAnalyzer/Checkers -I /home/johan/work/llvm.git/clang/include -I /home/johan/work/llvm.bld/tools/clang/include -I /home/johan/work/llvm.bld/include -I /home/johan/work/llvm.git/llvm/include /home/johan/work/llvm.git/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td --write-if-changed -o /home/johan/work/llvm.bld/tools/clang/include/clang/StaticAnalyzer/Checkers/Checkers.inc

Why is it doing so much work when nothing changed?

What about the lessons in “Recursive Make Considered Harmful”? (See e.g. Recursive Make Considered Harmful)

When I am only interested in a specific executable, say clang-11, is there a faster way to rebuild it after a change in a single file, or do I always have to wait the full 2 minutes plus actual compile and line time?

The LLVM project uses CMake as build system which is a sort of meta-build system able to generate build configurations for other build systems, in your case Unix Makefiles. The quality of the produced Makefiles is therefore also dependant on CMake. What also has to be said is that historically Makefiles, and make in general are rather slow, especially for huge projects when wanting to utilize incremental builds as you are.

That’s why most developers probably use and recommend you to use Ninja [1] instead of make. It in my experience builds LLVM and Clang way faster than make, makes better use of multithreading and makes incremental builds basically instant.
To switch to Ninja, the only thing you need to is specify -GNinja instead of -G "Unix Makefiles". The command for building are exactly the same as make but the binary is instead called ninja. ninja install would eg. build all and then install it. Unlike with make, you are better off not specifying -j as by default it will choose to use as many cores as possible, but if you want to share resources with other programs you can still specify thread count that way.

[1] https://ninja-build.org/

Yes, using Ninja helps: with no source files changed, it takes less than 1 sec, compared to > 3 minutes for llvm’s makefile. Thanks.