[Runtimes] Fix Unix Makefiles race between runtimes-build and EXTRA_TARGETS (#187634)

In our downstream we have a non-runtime target depending on libclc
EXTRA_TARGET and then observe a race condition in parallel build: both
runtimes-build (full build, no lock) and libclc EXTRA_TARGET (triggered
by non-runtime target, FileLock) build concurrently, leading to corrupt
libclc library.

This exposes an limitation in ExternalProject EXTRA_TARGET design:
EXTRA_TARGETS in llvm_ExternalProject_Add only depend on
${name}-configure, not ${name}-build. This makes EXTRA_TARGETS unsafe as
dependencies of a non-runtime target..

Fix: Add a locked BUILD_COMMAND to ExternalProject_Add for Unix
Makefiles generator, using the same cmake.lock as EXTRA_TARGETS. This
serializes runtimes-build with all EXTRA_TARGETS under one lock.

With this PR, a non-runtime target can depend on a specific
EXTRA_TARGET, rather than needing to depend on the umbrella runtimes
target. This is an improvement. A non-runtime target can start as soon
as its dependent specific EXTRA_TARGET build finishes, without waiting
for other runtimes. In addition, the non-runtime target may only need a
specific EXTRA_TARGET and minimal dependency on it is accurate.

Assisted-by: Claude Sonnet 4.6

---------

Co-authored-by: Petr Hosek <phosek@google.com>
This commit is contained in:
Wenju He 2026-03-21 07:33:21 +08:00 committed by GitHub
parent 335a2d0e7e
commit bae6a2a76b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -9,7 +9,12 @@ function(llvm_ExternalProject_BuildCmd out_var target bin_dir stamp_dir)
endif()
if (CMAKE_GENERATOR MATCHES "Make")
# Use special command for Makefiles to support parallelism.
string(JOIN "@" make_cmd "$(MAKE)" "-C" "${bin_dir}" "${target}")
# Handle empty target (full build, no target argument).
if(target)
string(JOIN "@" make_cmd "$(MAKE)" "-C" "${bin_dir}" "${target}")
else()
string(JOIN "@" make_cmd "$(MAKE)" "-C" "${bin_dir}")
endif()
set(file_lock_script "${LLVM_CMAKE_DIR}/FileLock.cmake")
set(${out_var} ${CMAKE_COMMAND} "-DLOCK_FILE_PATH=${stamp_dir}/cmake.lock"
"-DCOMMAND=${make_cmd}"
@ -378,6 +383,14 @@ function(llvm_ExternalProject_Add name source_dir)
set(verbose -DCMAKE_VERBOSE_MAKEFILE=ON)
endif()
if(CMAKE_GENERATOR MATCHES "Make")
# Use the same FileLock for Unix Makefiles to serialize the main build with
# EXTRA_TARGETS. This prevents concurrent make invocations from corrupting
# shared artifacts in BINARY_DIR.
llvm_ExternalProject_BuildCmd(build_cmd "" ${BINARY_DIR} ${STAMP_DIR})
set(build_command_arg BUILD_COMMAND ${build_cmd})
endif()
ExternalProject_Add(${name}
DEPENDS ${ARG_DEPENDS} llvm-config
${name}-clobber
@ -408,6 +421,7 @@ function(llvm_ExternalProject_Add name source_dir)
${cmake_args}
${PASSTHROUGH_VARIABLES}
CMAKE_CACHE_DEFAULT_ARGS ${CMAKE_CACHE_DEFAULT_ARGS}
${build_command_arg}
INSTALL_COMMAND ""
STEP_TARGETS configure build
BUILD_ALWAYS 1