[llvm] [runtimes] Make later runtimes wait for earlier header targets (PR #192814)
Yaxun Liu via llvm-commits
llvm-commits at lists.llvm.org
Sat Apr 18 16:20:27 PDT 2026
https://github.com/yxsamliu created https://github.com/llvm/llvm-project/pull/192814
`LLVM_ENABLE_RUNTIMES` is already ordered so that dependencies come first
(e.g. `libc;compiler-rt;openmp`). The problem is that this order only
controls CMake configuration. Once ninja starts, the targets from sibling
runtimes are independent unless we add explicit dependencies.
A real example is the amdgcn runtimes build:
- `libc` generates GPU headers such as `<string.h>` and `<limits.h>`
- `compiler-rt` includes those headers when building
`libclang_rt.profile-amdgcn`
Today, even though `libc` appears before `compiler-rt`, ninja can still
start compiling `compiler-rt/lib/profile/InstrProfiling.c` before
`libc` finishes generating its headers. That makes the build fail.
Fix this in `runtimes/CMakeLists.txt`, where the runtime order is known.
After each `add_subdirectory`, recursively collect the targets created by
that runtime and make them depend on prerequisite targets exported by
earlier runtimes. For now we seed the list with LLVM-libc's
`libc-headers` target, so all later runtimes wait for generated libc
headers before they build.
This is generic: later runtimes do not need to know the internal target
names inside libc, and future runtimes can export similar prerequisite
targets the same way.
No functional change when `libc` is not part of the runtimes build.
Related: PR #177665.
>From 84d68502bef4c189bc5b051eea51ecfe4f520d86 Mon Sep 17 00:00:00 2001
From: "Yaxun (Sam) Liu" <yaxun.liu at amd.com>
Date: Fri, 17 Apr 2026 13:31:08 -0400
Subject: [PATCH] [runtimes] Make later runtimes wait for earlier header
targets
`LLVM_ENABLE_RUNTIMES` is already ordered so that dependencies come first
(e.g. `libc;compiler-rt;openmp`). The problem is that this order only
controls CMake configuration. Once ninja starts, the targets from sibling
runtimes are independent unless we add explicit dependencies.
A real example is the amdgcn runtimes build:
- `libc` generates GPU headers such as `<string.h>` and `<limits.h>`
- `compiler-rt` includes those headers when building
`libclang_rt.profile-amdgcn`
Today, even though `libc` appears before `compiler-rt`, ninja can still
start compiling `compiler-rt/lib/profile/InstrProfiling.c` before
`libc` finishes generating its headers. That makes the build fail.
Fix this in `runtimes/CMakeLists.txt`, where the runtime order is known.
After each `add_subdirectory`, recursively collect the targets created by
that runtime and make them depend on prerequisite targets exported by
earlier runtimes. For now we seed the list with LLVM-libc's
`libc-headers` target, so all later runtimes wait for generated libc
headers before they build.
This is generic: later runtimes do not need to know the internal target
names inside libc, and future runtimes can export similar prerequisite
targets the same way.
No functional change when `libc` is not part of the runtimes build.
Related: PR #177665.
---
runtimes/CMakeLists.txt | 44 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index eba41b8b10ac4..fb14f4f0da8cd 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -364,12 +364,56 @@ if(LLVM_INCLUDE_TESTS)
umbrella_lit_testsuite_begin(check-runtimes)
endif()
+# Return every target created under <dir>, including subdirectories.
+# We use this to say "all compiler-rt targets depend on libc-headers"
+# instead of naming every compiler-rt target by hand.
+function(_llvm_runtimes_collect_targets dir out_var)
+ set(_collected "")
+ get_directory_property(_targets DIRECTORY "${dir}" BUILDSYSTEM_TARGETS)
+ list(APPEND _collected ${_targets})
+ get_directory_property(_subs DIRECTORY "${dir}" SUBDIRECTORIES)
+ foreach(_sub ${_subs})
+ _llvm_runtimes_collect_targets("${_sub}" _sub_targets)
+ list(APPEND _collected ${_sub_targets})
+ endforeach()
+ set(${out_var} ${_collected} PARENT_SCOPE)
+endfunction()
+
+# "Things later runtimes should wait for".
+# Example: if the runtime list is `libc;compiler-rt;openmp`, then after we
+# add libc we put `libc-headers` in this list. When we later add compiler-rt
+# and openmp, we make all of their targets depend on `libc-headers`.
+# This turns the runtime list order into a real ninja dependency, not just
+# a configuration-time order.
+set(_llvm_runtimes_cross_deps "")
+
# We do this in two loops so that HAVE_* is set for each runtime before the
# other runtimes are added.
foreach(entry ${runtimes})
get_filename_component(projName ${entry} NAME)
add_subdirectory(${entry} ${projName})
+
+ # Make every target from this runtime wait for the prerequisites gathered
+ # from earlier runtimes.
+ # Example: after adding `libc`, the list contains `libc-headers`, so when
+ # we add `compiler-rt` we attach `add_dependencies(<each compiler-rt target>
+ # libc-headers)`.
+ # Skip the walk when the list is empty.
+ if(_llvm_runtimes_cross_deps)
+ _llvm_runtimes_collect_targets("${entry}" _new_targets)
+ foreach(_tgt ${_new_targets})
+ if(TARGET ${_tgt})
+ add_dependencies(${_tgt} ${_llvm_runtimes_cross_deps})
+ endif()
+ endforeach()
+ endif()
+
+ # Seed the list for later runtimes.
+ # Today only LLVM-libc publishes such a target: `libc-headers`.
+ if(projName STREQUAL "libc" AND TARGET libc-headers)
+ list(APPEND _llvm_runtimes_cross_deps libc-headers)
+ endif()
endforeach()
# Define runtimes-test-depends so the parent build can use it unconditionally.
More information about the llvm-commits
mailing list