wenju-he
(Wenju He)
May 26, 2026, 3:00am
1
By default, CMake does not add the compiler executable as a dependency of compiled objects. Sources are rebuilt when they change, but not when the compiler changes.
This causes a concrete problem in toolchain bootstrap builds such as LLVM (GitHub - llvm/llvm-project: The LLVM Project is a collection of modular and reusable compiler and toolchain technologies. · GitHub ):
- Step 1: Build clang using host compiler.
- Step 2: LLVM runtimes (libc, libclc, etc.) are configured as a separate CMake invocation via ExternalProject, using the just-built clang as CMAKE_C_COMPILER/CMAKE_CXX_COMPILER.
When clang is subsequently modified and rebuilt, the runtimes are not rebuilt because their object files have no dependency on the clang binary. This is especially critical for some runtimes that emit LLVM bitcode, where a compiler change must invalidate all outputs.
The behavior is probably related to the explanation provided in When to reconfigure vs configure from scratch? Why? - #2 by ben.boeckel , but it forces llvm-project to work around it by adding dependency on compiler executable manually.
Request: Could CMake provide an option or a variable — so that add_library/add_executable automatically adds compiler executable as an OBJECT_DEPENDS for all compiled sources?
which Generator do you use?
If Ninja is the Generator, all llvm headers are in the dependency list:
bash-5.3$ ninja -t deps | grep -w llvm | sort -u
# ...
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/algorithm
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/array
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/atomic
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/bitset
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/cassert
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/cctype
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/cerrno
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/chrono
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/cinttypes
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/climits
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/clocale
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/cmath
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/compare
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/concepts
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/condition_variable
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/coroutine
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/cstddef
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/cstdint
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/cstdio
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/cstdlib
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/cstring
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/ctime
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/ctype.h
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/cwchar
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/cwctype
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/deque
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/errno.h
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/exception
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/format
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/functional
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/initializer_list
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/inttypes.h
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/ios
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/iosfwd
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/iostream
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/istream
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/iterator
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/limits
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/locale
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/math.h
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/memory
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/memory_resource
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/mutex
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/new
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/optional
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/ostream
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/print
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/queue
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/ranges
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/ratio
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/source_location
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/span
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/sstream
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/stddef.h
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/stdexcept
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/stdio.h
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/stdlib.h
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/streambuf
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/string
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/string.h
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/string_view
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/system_error
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/thread
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/tuple
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/type_traits
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/typeinfo
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/unordered_map
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/utility
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/variant
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/vector
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/version
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/wchar.h
/usr/local/Cellar/llvm/22.1.6/include/c++/v1/wctype.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stdarg___gnuc_va_list.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stdarg___va_copy.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stdarg_header_macro.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stdarg_va_arg.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stdarg_va_copy.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stdarg_va_list.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stddef_header_macro.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stddef_max_align_t.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stddef_null.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stddef_nullptr_t.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stddef_offsetof.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stddef_ptrdiff_t.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stddef_rsize_t.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stddef_size_t.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/__stddef_wchar_t.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/inttypes.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/limits.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/stdarg.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/stddef.h
/usr/local/Cellar/llvm/22.1.6/lib/clang/22/include/stdint.h
wenju-he
(Wenju He)
May 27, 2026, 4:27am
3
It should not be related to generator type. I can reproduce the issue using Ninja and Make generators.
It is not missing dependency on llvm headers. It is that just built clang isn’t in the dependency.
Ninja reproduce steps:
cd llvm-project-llvmorg-22.1.6/build
cmake -GNinja -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_ENABLE_RUNTIMES="libc" -DLLVM_TARGETS_TO_BUILD="X86" -DCMAKE_BUILD_TYPE=Release -DLLVM_LIBC_FULL_BUILD=OFF ../llvm
ninja
ls -l ./bin/clang-22
-rwxr-x--- 1 wenjuhe icg_src 152354624 May 27 02:21 ./bin/clang-22*
ls -l ./runtimes/runtimes-bins/libc/lib/libllvmlibc.a
-rw-r----- 1 wenjuhe icg_src 5923336 May 27 02:22 ./runtimes/runtimes-bins/libc/lib/libllvmlibc.a
touch ../llvm/lib/Transforms/Scalar/LICM.cpp
ninja
ls -l ./bin/clang-22
-rwxr-x--- 1 wenjuhe icg_src 152354624 May 27 04:51 ./bin/clang-22*
ls -l ./runtimes/runtimes-bins/libc/lib/libllvmlibc.a
-rw-r----- 1 wenjuhe icg_src 5923336 May 27 02:22 ./runtimes/runtimes-bins/libc/lib/libllvmlibc.a
ninja -C runtimes/runtimes-bins -t deps|grep "build/bin/clang"
We can see that timestamp of just-built clang is updated after rebuild, but timestamp of libc library libllvmlibc.a isn’t updated.
However, libllvmlibc.a is built using just-built clang. For example, Unix Makefiles generator output file runtimes/runtimes-bins/compile_commands.json has content:
{
"directory": "/localdisk2/wenjuhe/tmp5/llvm-project-llvmorg-22.1.6/build-make/runtimes/runtimes-bins/libc/src/__support",
"command": "/localdisk2/wenjuhe/tmp5/llvm-project-llvmorg-22.1.6/build-make/bin/clang++ --target=x86_64-unknown-linux-gnu -DLIBC_NAMESPACE=__llvm_libc_22_1_6_ -I/localdisk2/wenjuhe/tmp5/llvm-project-llvmorg-22.1.6/libc -I/localdisk2/wenjuhe/tmp5/llvm-project-llvmorg-22.1.6/build-make/runtimes/runtimes-bins/libc -isystem /localdisk2/wenjuhe/tmp5/llvm-project-llvmorg-22.1.6/build-make/runtimes/runtimes-bins/libc/include -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wno-pass-failed -Wmisleading-indentation -Wctad-maybe-unsupported -ffunction-sections -fdata-sections -O3 -DNDEBUG -std=gnu++17 -DLIBC_QSORT_IMPL=LIBC_QSORT_QUICK_SORT -DLIBC_COPT_STRING_LENGTH_IMPL=clang_vector -DLIBC_COPT_FIND_FIRST_CHARACTER_IMPL=word -DLIBC_ADD_NULL_CHECKS -DLIBC_ERRNO_MODE=LIBC_ERRNO_MODE_DEFAULT -DLIBC_THREAD_MODE=LIBC_THREAD_MODE_PLATFORM -DLIBC_CONF_WCTYPE_MODE=LIBC_WCTYPE_MODE_ASCII -DLIBC_COPT_RAW_MUTEX_DEFAULT_SPIN_COUNT=100 -fpie -ffixed-point -fno-builtin -fno-exceptions -fno-lax-vector-conversions -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-rtti -ftrivial-auto-var-init=pattern -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -Wall -Wextra -Werror -Wconversion -Wno-sign-conversion -Wdeprecated -Wno-c99-extensions -Wno-gnu-imaginary-constant -Wno-pedantic -Wimplicit-fallthrough -Wwrite-strings -Wextra-semi -Wnewline-eof -Wnonportable-system-include-path -Wstrict-prototypes -Wthread-safety -Wglobal-constructors -DLIBC_FREELIST_MALLOC_SIZE= -o CMakeFiles/libc.src.__support.freelist_heap.dir/freelist_heap.cpp.o -c /localdisk2/wenjuhe/tmp5/llvm-project-llvmorg-22.1.6/libc/src/__support/freelist_heap.cpp",
"file": "/localdisk2/wenjuhe/tmp5/llvm-project-llvmorg-22.1.6/libc/src/__support/freelist_heap.cpp",
"output": "libc/src/__support/CMakeFiles/libc.src.__support.freelist_heap.dir/freelist_heap.cpp.o"
},
The intention is that rebuild of clang should trigger rebuild of libc library.
The last command outputs empty, meaning that libc library has no dependency on clang executable.
wenju-he
(Wenju He)
June 16, 2026, 11:07am
4
Kindly ping. Does this feature request make sense as an opt-in feature for bootstrap build scenario? The core issue is that CMake does not register compiler as a build dependency, which breaks when a newly built compiler is updated in bootstrap step.