https://github.com/ceph/ceph/pull/73585 From 2e5697967906f0d931b5a0bb97bfa25b10e561fa Mon Sep 17 00:00:00 2001 From: "Z. Liu" Date: Fri, 6 Nov 2026 21:59:10 +0800 Subject: [PATCH] cmake: order src targets after legacy option header generation The headers generated by src/common/options/y2c.py are included indirectly through common/config.h and are required by many targets throughout src. Without an explicit build-order dependency, parallel builds may compile sources before these headers have been generated. This can result in incomplete ConfigValues definitions, as seen with src/perfglue/heap_profiler.cc. Instead of adding add_dependencies() to individual targets, create an interface library and add it to the directory-level LINK_LIBRARIES property in src/. This propagates its build dependency to targets created in this directory and its subdirectories. The interface library depends on a custom target in src/common/options that represents the generated headers. Using BUILD_INTERFACE keeps this helper out of installed target interfaces without changing the actual linker command lines. Verified by adding time.sleep(600) to y2c.py and building the full tree from an empty build directory. No header-generation ordering failures occurred. However, with the Unix Makefiles generator, custom commands may be duplicated across multiple targets' build.make files when their outputs are consumed by independent targets. Under parallel builds, separate make processes can execute the same command concurrently, causing them to overwrite the generated files and potentially leave them truncated or incomplete. This is particularly problematic for the legacy option headers, which are generated by y2c.py and consumed by multiple targets. Ninja handles this differently by maintaining a single global build graph, so the same generation rule is executed only once. Signed-off-by: Z. Liu diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 46226c6bbe8..c23cb48f05c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -590,6 +590,29 @@ if(WITH_JAEGER) endif() CHECK_C_COMPILER_FLAG("-fvar-tracking-assignments" HAS_VTA) + +# The *_legacy_options.h headers generated by src/common/options/y2c.py +# are included indirectly by a large part of the source tree: +# common/config.h includes common/options/legacy_config_opts.h, which +# in turn includes these generated headers. +# +# Without an explicit build-order dependency, parallel builds may start +# compiling sources before the headers have been generated. One example +# is src/perfglue/heap_profiler.cc, which may then see an incomplete +# ConfigValues definition. +# +# Propagate the dependency to all targets in this directory tree through +# the directory-level LINK_LIBRARIES property, rather than adding +# add_dependencies() to individual targets. +# +# The interface library provides a build-order dependency without adding +# anything to the actual link command. BUILD_INTERFACE also keeps this +# helper out of the exported link interfaces of installed targets. +add_library(ceph-legacy-option-headers INTERFACE) +add_dependencies(ceph-legacy-option-headers ceph-legacy-option-header-files) +set_property(DIRECTORY APPEND PROPERTY LINK_LIBRARIES + "$") + add_subdirectory(auth) add_subdirectory(common) add_subdirectory(crush) diff --git a/src/common/options/CMakeLists.txt b/src/common/options/CMakeLists.txt index 916f55dcfbd..8225dc0d900 100644 --- a/src/common/options/CMakeLists.txt +++ b/src/common/options/CMakeLists.txt @@ -111,6 +111,11 @@ target_sources(legacy-option-headers PRIVATE ${legacy_options_headers}) +# Expose the generated headers through a custom target so that targets +# in parent directories can depend on their generation. +add_custom_target(ceph-legacy-option-header-files + DEPENDS ${legacy_options_headers}) + include(AddCephTest) add_ceph_test(validate-options ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/validate-options.py ${options_yamls}) -- 2.49.1