diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 72c940555c..152a68b299 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -1451,8 +1451,11 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() if (this->AutogenTarget.DependOrigin) { // add_dependencies/addUtility do not support generator expressions. // We depend only on the libraries found in all configs therefore. - std::map commonTargets; + std::map targetsPartOfAllConfigs; for (std::string const& config : this->ConfigsList) { + // The same target might appear multiple times in a config, but we + // should only count it once. + std::set seenTargets; cmLinkImplementationLibraries const* libs = this->GenTarget->GetLinkImplementationLibraries( config, cmGeneratorTarget::UseTo::Link); @@ -1460,14 +1463,15 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() for (cmLinkItem const& item : libs->Libraries) { cmGeneratorTarget const* libTarget = item.Target; if (libTarget && - !StaticLibraryCycle(this->GenTarget, libTarget, config)) { + !StaticLibraryCycle(this->GenTarget, libTarget, config) && + seenTargets.insert(libTarget).second) { // Increment target config count - commonTargets[libTarget]++; + targetsPartOfAllConfigs[libTarget]++; } } } } - for (auto const& item : commonTargets) { + for (auto const& item : targetsPartOfAllConfigs) { if (item.second == this->ConfigsList.size()) { this->AutogenTarget.DependTargets.insert(item.first->Target); } diff --git a/Tests/RunCMake/Autogen_1/AutogenDuplicateDependency.cmake b/Tests/RunCMake/Autogen_1/AutogenDuplicateDependency.cmake new file mode 100644 index 0000000000..f6968d4978 --- /dev/null +++ b/Tests/RunCMake/Autogen_1/AutogenDuplicateDependency.cmake @@ -0,0 +1,38 @@ +enable_language(CXX) + +find_package(Qt${with_qt_version} REQUIRED COMPONENTS Core) + +set(CMAKE_AUTOMOC ON) + +file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/lib.cpp" + CONTENT "void foo() {}") +file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/main.cpp" + CONTENT "int main() {return 0;}") + +# Test case. +# App depends on Lib, which means App_autogen depends on Lib_autogen by default. +# Which means building App_autogen should trigger the generation of the +# fancy_generated.txt file, which is a dependency of Lib_autogen. + +# Create a shared library and an executable. +add_library(Lib SHARED "${CMAKE_CURRENT_BINARY_DIR}/lib.cpp") +add_executable(App "${CMAKE_CURRENT_BINARY_DIR}/main.cpp") + +# Link Lib into App more than once. Previously this was not properly handled by AUTOGEN, +# which discarded the Lib_autogen dependency from App_autogen entirely, and the +# file was not generated. +foreach(i RANGE 1 ${LIB_LINK_COUNT}) + target_link_libraries(App PRIVATE Lib) +endforeach() + +# Add a custom target that generates a file. +set(generated_file_path "${CMAKE_CURRENT_BINARY_DIR}/fancy_generated.txt") +add_custom_command( + OUTPUT "${generated_file_path}" + COMMAND ${CMAKE_COMMAND} -E touch "${generated_file_path}" +) +add_custom_target(generate_file DEPENDS "${generated_file_path}") + +# Make sure the file is generated as part of building the Lib_autogen target. +set_target_properties(Lib PROPERTIES + AUTOGEN_TARGET_DEPENDS generate_file) diff --git a/Tests/RunCMake/Autogen_1/RunCMakeTest.cmake b/Tests/RunCMake/Autogen_1/RunCMakeTest.cmake index 2cf60e4205..c49f09c280 100644 --- a/Tests/RunCMake/Autogen_1/RunCMakeTest.cmake +++ b/Tests/RunCMake/Autogen_1/RunCMakeTest.cmake @@ -131,4 +131,19 @@ if (DEFINED with_qt_version) endblock() endif() endif() + block() + foreach(LIB_LINK_COUNT RANGE 1 4) + set(RunCMake_TEST_VARIANT_DESCRIPTION "-link-count-${LIB_LINK_COUNT}") + set(RunCMake_TEST_BINARY_DIR + "${RunCMake_BINARY_DIR}/AutogenDuplicateDependency-build-${LIB_LINK_COUNT}") + run_cmake_with_options(AutogenDuplicateDependency ${RunCMake_TEST_OPTIONS} -DLIB_LINK_COUNT=${LIB_LINK_COUNT}) + set(RunCMake_TEST_NO_CLEAN 1) + set(RunCMake_TEST_EXPECT_stdout "fancy_generated.txt") + run_cmake_command("AutogenDuplicateDependency-build" + ${CMAKE_COMMAND} --build . --target App_autogen --verbose) + unset(RunCMake_TEST_VARIANT_DESCRIPTION) + unset(RunCMake_TEST_EXPECT_stdout) + unset(RunCMake_TEST_NO_CLEAN) + endforeach() + endblock() endif ()