From 6b20bbd2dd78747cb951d32c12b63c9605971b32 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 26 Aug 2020 17:42:52 +0200 Subject: AutoMoc: Restore support for re-running after project file changes For Qt >= 5.15.0 and Ninja generators AutoMoc creates a depfile to let Ninja decide when to run AutoMoc. This was introduced by commit aebfbcaa46 (AutoGen: Use depfiles for the XXX_autogen ninja targets, 2020-01-14, v3.17.0-rc1~58^2). However, AutoMoc was not triggered after adding a new moc-able file to the project. This patch adds the project file (and potentially included files) to the dependencies in the depfile. Now, a re-run of AutoMoc is triggered if the project file changes. Fixes: #21127 --- Source/cmQtAutoGenInitializer.cxx | 1 + Source/cmQtAutoMocUic.cxx | 4 +- Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt | 96 ++++++++++++++++++++++ .../MocOnAddFile/CMakeLists.txt.in | 9 ++ .../MocOnAddFile/anotherobject.cpp | 15 ++++ .../RerunMocOnAddFile/MocOnAddFile/main.cpp.in | 6 ++ .../RerunMocOnAddFile/MocOnAddFile/myobject.cpp | 6 ++ .../RerunMocOnAddFile/MocOnAddFile/myobject.h | 13 +++ Tests/QtAutogen/Tests.cmake | 1 + 9 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt create mode 100644 Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/CMakeLists.txt.in create mode 100644 Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/anotherobject.cpp create mode 100644 Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/main.cpp.in create mode 100644 Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.cpp create mode 100644 Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.h diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index c8caddf..d8b9100 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -1508,6 +1508,7 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() info.SetConfig("PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile); info.Set("DEP_FILE", this->AutogenTarget.DepFile); info.Set("DEP_FILE_RULE_NAME", this->AutogenTarget.DepFileRuleName); + info.SetArray("CMAKE_LIST_FILES", this->Makefile->GetListFiles()); info.SetArray("HEADER_EXTENSIONS", this->Makefile->GetCMakeInstance()->GetHeaderExtensions()); info.SetArrayArray( diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index f159a3d..49eb018 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -184,6 +184,7 @@ public: std::string DepFile; std::string DepFileRuleName; std::vector HeaderExtensions; + std::vector ListFiles; }; /** Shared common variables. */ @@ -2176,7 +2177,7 @@ void cmQtAutoMocUicT::JobDepFilesMergeT::Process() return dependenciesFromDepFile(f.c_str()); }; - std::vector dependencies; + std::vector dependencies = BaseConst().ListFiles; ParseCacheT& parseCache = BaseEval().ParseCache; auto processMappingEntry = [&](const MappingMapT::value_type& m) { auto cacheEntry = parseCache.GetOrInsert(m.first); @@ -2258,6 +2259,7 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) !info.GetString("DEP_FILE_RULE_NAME", BaseConst_.DepFileRuleName, false) || !info.GetStringConfig("SETTINGS_FILE", SettingsFile_, true) || + !info.GetArray("CMAKE_LIST_FILES", BaseConst_.ListFiles, true) || !info.GetArray("HEADER_EXTENSIONS", BaseConst_.HeaderExtensions, true) || !info.GetString("QT_MOC_EXECUTABLE", MocConst_.Executable, false) || !info.GetString("QT_UIC_EXECUTABLE", UicConst_.Executable, false)) { diff --git a/Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt b/Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt new file mode 100644 index 0000000..2677659 --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt @@ -0,0 +1,96 @@ +# This test checks whether adding a source file to the project triggers an AUTOMOC re-run. + +cmake_minimum_required(VERSION 3.10) +project(RerunMocOnAddFile) +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(timeformat "%Y.%j.%H.%M%S") +set(testProjectTemplateDir "${CMAKE_CURRENT_SOURCE_DIR}/MocOnAddFile") +set(testProjectSrc "${CMAKE_CURRENT_BINARY_DIR}/MocOnAddFile") +set(testProjectBinDir "${CMAKE_CURRENT_BINARY_DIR}/MocOnAddFile-build") + +# Utility macros +macro(sleep) + message(STATUS "Sleeping for a few seconds.") + execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) +endmacro() + +macro(acquire_timestamp When) + file(TIMESTAMP "${mocBasicBin}" time${When} "${timeformat}") +endmacro() + +macro(rebuild buildName) + message(STATUS "Starting build ${buildName}.") + execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${testProjectBinDir}" RESULT_VARIABLE result) + if (result) + message(FATAL_ERROR "Build ${buildName} failed.") + else() + message(STATUS "Build ${buildName} finished.") + endif() +endmacro() + +macro(require_change) + if (timeAfter VERSION_GREATER timeBefore) + message(STATUS "As expected the file ${mocBasicBin} changed.") + else() + message(SEND_ERROR "Unexpectedly the file ${mocBasicBin} did not change!\nTimestamp pre: ${timeBefore}\nTimestamp aft: ${timeAfter}\n") + endif() +endmacro() + +macro(require_change_not) + if (timeAfter VERSION_GREATER timeBefore) + message(SEND_ERROR "Unexpectedly the file ${mocBasicBin} changed!\nTimestamp pre: ${timeBefore}\nTimestamp aft: ${timeAfter}\n") + else() + message(STATUS "As expected the file ${mocBasicBin} did not change.") + endif() +endmacro() + +# Create the test project from the template +unset(additional_project_sources) +unset(main_cpp_includes) +configure_file("${testProjectTemplateDir}/CMakeLists.txt.in" "${testProjectSrc}/CMakeLists.txt") +configure_file("${testProjectTemplateDir}/main.cpp.in" "${testProjectSrc}/main.cpp") + +# Initial build +try_compile(MOC_RERUN + "${testProjectBinDir}" + "${testProjectSrc}" + MocOnAddFile + CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}" + "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}" + "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}" + OUTPUT_VARIABLE output +) +if (NOT MOC_RERUN) + message(FATAL_ERROR "Initial build of mocOnAddFile failed. Output: ${output}") +endif() + +# Sleep to ensure new timestamps +sleep() + +# Add a QObject class (defined in header) to the project and build +set(additional_project_sources myobject.cpp) +set(main_cpp_includes "#include \"myobject.h\"") +configure_file("${testProjectTemplateDir}/CMakeLists.txt.in" "${testProjectSrc}/CMakeLists.txt" + @ONLY) +configure_file("${testProjectTemplateDir}/main.cpp.in" "${testProjectSrc}/main.cpp" @ONLY) +configure_file("${testProjectTemplateDir}/myobject.h" "${testProjectSrc}/myobject.h" COPYONLY) +configure_file("${testProjectTemplateDir}/myobject.cpp" "${testProjectSrc}/myobject.cpp" COPYONLY) +rebuild(2) + +# Sleep to ensure new timestamps +sleep() + +# Add a QObject class (defined in source) to the project and build +set(additional_project_sources myobject.cpp anotherobject.cpp) +configure_file("${testProjectTemplateDir}/CMakeLists.txt.in" "${testProjectSrc}/CMakeLists.txt" + @ONLY) +configure_file("${testProjectTemplateDir}/anotherobject.cpp" "${testProjectSrc}/anotherobject.cpp" + COPYONLY) +rebuild(3) diff --git a/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/CMakeLists.txt.in b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/CMakeLists.txt.in new file mode 100644 index 0000000..9e5e21c --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/CMakeLists.txt.in @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.10) +project(MocOnAddFile) +include("@CMAKE_CURRENT_LIST_DIR@/../AutogenCoreTest.cmake") + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +add_executable(mocOnAddFile main.cpp @additional_project_sources@) +target_link_libraries(mocOnAddFile ${QT_QTCORE_TARGET}) diff --git a/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/anotherobject.cpp b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/anotherobject.cpp new file mode 100644 index 0000000..45c5af6 --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/anotherobject.cpp @@ -0,0 +1,15 @@ +#include + +class AnotherObject : public QObject +{ + Q_OBJECT +public: + AnotherObject() {} +}; + +AnotherObject* createAnotherObject() +{ + return new AnotherObject(); +} + +#include "anotherobject.moc" diff --git a/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/main.cpp.in b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/main.cpp.in new file mode 100644 index 0000000..f62027a --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/main.cpp.in @@ -0,0 +1,6 @@ +@main_cpp_includes@ + +int main(int argc, char *argv[]) +{ + return 0; +} diff --git a/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.cpp b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.cpp new file mode 100644 index 0000000..7a15300 --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.cpp @@ -0,0 +1,6 @@ +#include "myobject.h" + +MyObject::MyObject(QObject* parent) + : QObject(parent) +{ +} diff --git a/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.h b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.h new file mode 100644 index 0000000..e373ee8 --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.h @@ -0,0 +1,13 @@ +#ifndef MYOBJECT_H +#define MYOBJECT_H + +#include + +class MyObject : public QObject +{ + Q_OBJECT +public: + MyObject(QObject* parent = 0); +}; + +#endif diff --git a/Tests/QtAutogen/Tests.cmake b/Tests/QtAutogen/Tests.cmake index a19a9ae..97efa72 100644 --- a/Tests/QtAutogen/Tests.cmake +++ b/Tests/QtAutogen/Tests.cmake @@ -20,6 +20,7 @@ ADD_AUTOGEN_TEST(RccOffMocLibrary) ADD_AUTOGEN_TEST(RccOnly rccOnly) ADD_AUTOGEN_TEST(RccSkipSource) ADD_AUTOGEN_TEST(RerunMocBasic) +ADD_AUTOGEN_TEST(RerunMocOnAddFile) ADD_AUTOGEN_TEST(RerunRccConfigChange) ADD_AUTOGEN_TEST(RerunRccDepends) ADD_AUTOGEN_TEST(SameName sameName) -- cgit v0.12