diff options
9 files changed, 132 insertions, 7 deletions
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 71c288c..9cb172b 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -192,7 +192,7 @@ public: { public: // -- Parse Cache - bool ParseCacheChanged = false; + std::atomic<bool> ParseCacheChanged = ATOMIC_VAR_INIT(false); cmFileTime ParseCacheTime; ParseCacheT ParseCache; @@ -1777,16 +1777,24 @@ bool cmQtAutoMocUicT::JobProbeDepsMocT::Probe(MappingT const& mapping, { // Check dependency timestamps std::string const sourceDir = SubDirPrefix(sourceFile); - for (std::string const& dep : mapping.SourceFile->ParseData->Moc.Depends) { + auto& dependencies = mapping.SourceFile->ParseData->Moc.Depends; + for (auto it = dependencies.begin(); it != dependencies.end(); ++it) { + auto& dep = *it; + // Find dependency file auto const depMatch = FindDependency(sourceDir, dep); if (depMatch.first.empty()) { - Log().Warning(GenT::MOC, - cmStrCat(MessagePath(sourceFile), " depends on ", - MessagePath(dep), - " but the file does not exist.")); - continue; + if (reason != nullptr) { + *reason = + cmStrCat("Generating ", MessagePath(outputFile), " from ", + MessagePath(sourceFile), ", because its dependency ", + MessagePath(dep), " vanished."); + } + dependencies.erase(it); + BaseEval().ParseCacheChanged = true; + return true; } + // Test if dependency file is older if (outputFileTime.Older(depMatch.second)) { if (reason != nullptr) { diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/CMakeLists.txt b/Tests/QtAutogen/RerunMocOnMissingDependency/CMakeLists.txt new file mode 100644 index 0000000..c5811eb --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnMissingDependency/CMakeLists.txt @@ -0,0 +1,80 @@ +# This test checks whether a missing dependency of the moc output triggers an AUTOMOC re-run. + +cmake_minimum_required(VERSION 3.10) +project(RerunMocOnMissingDependency) +include("../AutogenCoreTest.cmake") + +# Create an executable to generate a clean target +set(main_source "${CMAKE_CURRENT_BINARY_DIR}/generated_main.cpp") +file(WRITE "${main_source}" "int main() {}") +add_executable(exe "${main_source}") + +# Utility variables +set(testProjectTemplateDir "${CMAKE_CURRENT_SOURCE_DIR}/MocOnMissingDependency") +set(testProjectSrc "${CMAKE_CURRENT_BINARY_DIR}/MocOnMissingDependency") +set(testProjectBinDir "${CMAKE_CURRENT_BINARY_DIR}/MocOnMissingDependency-build") +if(DEFINED Qt5Core_VERSION AND Qt5Core_VERSION VERSION_GREATER_EQUAL "5.15.0") + set(moc_depfiles_supported TRUE) +else() + set(moc_depfiles_supported FALSE) +endif() + +# Utility macros +macro(sleep) + message(STATUS "Sleeping for a few seconds.") + execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) +endmacro() + +macro(rebuild buildName) + message(STATUS "Starting build ${buildName}.") + execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${testProjectBinDir}" + RESULT_VARIABLE result OUTPUT_VARIABLE output) + if (result) + message(FATAL_ERROR "Build ${buildName} failed.") + else() + message(STATUS "Build ${buildName} finished.") + endif() +endmacro() + +# Create the test project from the template +file(COPY "${testProjectTemplateDir}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") +configure_file("${testProjectTemplateDir}/CMakeLists.txt.in" "${testProjectSrc}/CMakeLists.txt" @ONLY) + +# Initial build +file(REMOVE_RECURSE "${testProjectBinDir}") +try_compile(MOC_RERUN + "${testProjectBinDir}" + "${testProjectSrc}" + MocOnMissingDependency + CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}" + "-DCMAKE_AUTOGEN_VERBOSE=ON" + "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}" + OUTPUT_VARIABLE output +) +if (NOT MOC_RERUN) + message(FATAL_ERROR "Initial build of mocOnMissingDependency failed. Output: ${output}") +endif() + +# Sleep to ensure new timestamps +sleep() + +if(moc_depfiles_supported) + # Remove the dependency inc1/foo.h and build again. + # We expect that the moc_XXX.cpp file gets re-generated. But only if we have depfile support. + file(REMOVE_RECURSE "${testProjectSrc}/inc1") + rebuild(2) + if(NOT output MATCHES "AutoMoc: Generating \"[^\"]*moc_myobject.cpp\"") + message(FATAL_ERROR "moc_myobject.cpp was not re-generated " + "after removing one of its dependencies") + endif() +endif() + +# Sleep to ensure new timestamps +sleep() + +# The next build should *not* re-renerate any moc outputs +rebuild(3) +if(output MATCHES "AutoMoc: Generating") + message(FATAL_ERROR "moc_myobject.cpp was not re-generated " + "after removing one of its dependencies") +endif() diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/CMakeLists.txt.in b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/CMakeLists.txt.in new file mode 100644 index 0000000..2155f45 --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/CMakeLists.txt.in @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.18) +project(MocOnMissingDependency) +include("@CMAKE_CURRENT_LIST_DIR@/../AutogenCoreTest.cmake") +set(CMAKE_AUTOMOC ON) +add_executable(MocOnMissingDependency main.cpp myobject.cpp) +target_include_directories(MocOnMissingDependency PRIVATE inc1 inc2) +target_link_libraries(MocOnMissingDependency PRIVATE ${QT_QTCORE_TARGET}) diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc1/foo.h b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc1/foo.h new file mode 100644 index 0000000..cd8b2f9 --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc1/foo.h @@ -0,0 +1,2 @@ + +#include <qobject.h> diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc2/foo.h b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc2/foo.h new file mode 100644 index 0000000..cd8b2f9 --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/inc2/foo.h @@ -0,0 +1,2 @@ + +#include <qobject.h> diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/main.cpp b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/main.cpp new file mode 100644 index 0000000..36d51fa --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/main.cpp @@ -0,0 +1,9 @@ +#include <iostream> + +#include "myobject.h" + +int main(int argc, char* argv[]) +{ + MyObject obj; + return 0; +} diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.cpp b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.cpp new file mode 100644 index 0000000..7a15300 --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.cpp @@ -0,0 +1,6 @@ +#include "myobject.h" + +MyObject::MyObject(QObject* parent) + : QObject(parent) +{ +} diff --git a/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.h b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.h new file mode 100644 index 0000000..25176cc --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnMissingDependency/MocOnMissingDependency/myobject.h @@ -0,0 +1,10 @@ +#pragma once + +#include <foo.h> + +class MyObject : public QObject +{ + Q_OBJECT +public: + MyObject(QObject* parent = 0); +}; diff --git a/Tests/QtAutogen/Tests.cmake b/Tests/QtAutogen/Tests.cmake index 0c7bd79..b1337d6 100644 --- a/Tests/QtAutogen/Tests.cmake +++ b/Tests/QtAutogen/Tests.cmake @@ -21,6 +21,7 @@ ADD_AUTOGEN_TEST(RccOnly rccOnly) ADD_AUTOGEN_TEST(RccSkipSource) ADD_AUTOGEN_TEST(RerunMocBasic) ADD_AUTOGEN_TEST(RerunMocOnAddFile) +ADD_AUTOGEN_TEST(RerunMocOnMissingDependency) ADD_AUTOGEN_TEST(RerunRccConfigChange) ADD_AUTOGEN_TEST(RerunRccDepends) ADD_AUTOGEN_TEST(SameName sameName) |