From f623664e877feae68bd4937adaf751d9a745893d Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 23 Dec 2020 13:29:22 +0100 Subject: Do not use try_compile in RerunMocBasic test In a subsequent patch we want to extend RerunMocBasic to test the removal and addition of Q_OBJECT macros works when building incrementally. For that, properly generated dependencies are necessary. Currently, the MocBasic test project is configured using try_compile, and that turns off the generation of depfiles. Replace the try_compile call with execute_command calls that first configure and then build the test project. --- Tests/QtAutogen/RerunMocBasic/CMakeLists.txt | 38 ++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt b/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt index 9b32e59..a4179b7 100644 --- a/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt +++ b/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt @@ -47,19 +47,37 @@ macro(require_change_not) endmacro() -# Initial build +# Configure the test project configure_file("${mocBasicSrcDir}/test1a.h.in" "${mocBasicBinDir}/test1.h" COPYONLY) -try_compile(MOC_RERUN - "${mocBasicBinDir}" - "${mocBasicSrcDir}" - MocBasic - CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}" - "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}" - "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}" +if(CMAKE_GENERATOR_INSTANCE) + set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE=${CMAKE_GENERATOR_INSTANCE}") +else() + set(_D_CMAKE_GENERATOR_INSTANCE "") +endif() +execute_process( + COMMAND "${CMAKE_COMMAND}" -B "${mocBasicBinDir}" -S "${mocBasicSrcDir}" + -G "${CMAKE_GENERATOR}" + -A "${CMAKE_GENERATOR_PLATFORM}" + -T "${CMAKE_GENERATOR_TOOLSET}" + ${_D_CMAKE_GENERATOR_INSTANCE} + "-DQT_TEST_VERSION=${QT_TEST_VERSION}" + "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}" + "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}" + RESULT_VARIABLE exit_code OUTPUT_VARIABLE output ) -if (NOT MOC_RERUN) - message(FATAL_ERROR "Initial build of mocBasic failed. Output: ${output}") +if(NOT exit_code EQUAL 0) + message(FATAL_ERROR "Initial configuration of mocBasic failed. Output: ${output}") +endif() + +# Initial build +execute_process( + COMMAND "${CMAKE_COMMAND}" --build "${mocBasicBinDir}" + RESULT_VARIABLE exit_code + OUTPUT_VARIABLE output +) +if(NOT exit_code EQUAL 0) + message(FATAL_ERROR "Initial build of mocBasic failed. Output: ${output}") endif() # Get name of the output binary -- cgit v0.12 From 2999c40dd911a59b438bd5f400521ab5007d83d8 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 23 Dec 2020 14:35:51 +0100 Subject: Extend QtAutogen/RerunMoc Test that removing / adding a Q_OBJECT macro doesn't break incremental builds. This was initially done to test the fix for #21620, but the test passes without the fix. The reason is that test1.h is included by main.cpp, which contains a Q_OBJECT macro, meaning that test1.h is in AutoMoc's dependencies transitively. --- Tests/QtAutogen/RerunMocBasic/CMakeLists.txt | 26 ++++++++++++++++++++++ Tests/QtAutogen/RerunMocBasic/MocBasic/test1c.h.in | 6 +++++ 2 files changed, 32 insertions(+) create mode 100644 Tests/QtAutogen/RerunMocBasic/MocBasic/test1c.h.in diff --git a/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt b/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt index a4179b7..72c99d5 100644 --- a/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt +++ b/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt @@ -118,3 +118,29 @@ message(STATUS "Changing nothing for no MOC re-run") rebuild(3) acquire_timestamp(After) require_change_not() + + +# - Ensure that the timestamp will change +# - Remove Q_OBJECT from header +# - Rebuild +acquire_timestamp(Before) +sleep() +message(STATUS "Remove Q_OBJECT from header file for a MOC re-run") +configure_file("${mocBasicSrcDir}/test1c.h.in" "${mocBasicBinDir}/test1.h" COPYONLY) +sleep() +rebuild(4) +acquire_timestamp(After) +require_change() + + +# - Ensure that the timestamp will change +# - Add Q_OBJECT to header again +# - Rebuild +acquire_timestamp(Before) +sleep() +message(STATUS "Add Q_OBJECT to header file for a MOC re-run") +configure_file("${mocBasicSrcDir}/test1a.h.in" "${mocBasicBinDir}/test1.h" COPYONLY) +sleep() +rebuild(5) +acquire_timestamp(After) +require_change() diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/test1c.h.in b/Tests/QtAutogen/RerunMocBasic/MocBasic/test1c.h.in new file mode 100644 index 0000000..d0b9868 --- /dev/null +++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/test1c.h.in @@ -0,0 +1,6 @@ +#include +class Test1 +{ +public: + void onTst1() {} +}; -- cgit v0.12 From fefba42e3740bb6a32cda13dfdebf51d414faac7 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 23 Dec 2020 14:21:24 +0100 Subject: Add a failing test case for #21620 Extend Qt(4|5)Autogen.RerunMocBasic to check the following situation: Class MyObject3 is a QObject-derived class without Q_OBJECT macro. It's declared in myobject3.h that is not included by any file that is input of AutoMoc (this is why we had to add PlainObject). If myobject3.h were included by main.cpp, then AutoMoc would already track this dependency, because main.cpp has a Q_OBJECT macro. After the initial build(s), the Q_OBJECT macro is added to myobject3.h, and an incremental build is run. With Qt >= 5.15 and Ninja, the build fails, because AutoMoc is not run due to the missing dependency to myobject3.h. --- Tests/QtAutogen/RerunMocBasic/CMakeLists.txt | 17 ++++++++++++++++- Tests/QtAutogen/RerunMocBasic/MocBasic/CMakeLists.txt | 7 ++++++- Tests/QtAutogen/RerunMocBasic/MocBasic/main.cpp.in | 2 ++ Tests/QtAutogen/RerunMocBasic/MocBasic/myobject3a.h.in | 13 +++++++++++++ Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.cpp | 12 ++++++++++++ Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.h | 12 ++++++++++++ 6 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 Tests/QtAutogen/RerunMocBasic/MocBasic/myobject3a.h.in create mode 100644 Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.cpp create mode 100644 Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.h diff --git a/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt b/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt index 72c99d5..c53e857 100644 --- a/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt +++ b/Tests/QtAutogen/RerunMocBasic/CMakeLists.txt @@ -49,6 +49,7 @@ endmacro() # Configure the test project configure_file("${mocBasicSrcDir}/test1a.h.in" "${mocBasicBinDir}/test1.h" COPYONLY) +configure_file("${mocBasicSrcDir}/myobject3a.h.in" "${mocBasicBinDir}/myobject3.h" @ONLY) if(CMAKE_GENERATOR_INSTANCE) set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE=${CMAKE_GENERATOR_INSTANCE}") else() @@ -138,9 +139,23 @@ require_change() # - Rebuild acquire_timestamp(Before) sleep() -message(STATUS "Add Q_OBJECT to header file for a MOC re-run") +message(STATUS "Add Q_OBJECT to test1.h for a MOC re-run") configure_file("${mocBasicSrcDir}/test1a.h.in" "${mocBasicBinDir}/test1.h" COPYONLY) sleep() rebuild(5) acquire_timestamp(After) require_change() + + +# - Ensure that the timestamp will change +# - Add Q_OBJECT to MyObject3 +# - Rebuild +acquire_timestamp(Before) +sleep() +message(STATUS "Add Q_OBJECT to myobject3.h file for a MOC re-run") +set(CLASS_CONTENT "Q_OBJECT") +configure_file("${mocBasicSrcDir}/myobject3a.h.in" "${mocBasicBinDir}/myobject3.h" @ONLY) +sleep() +rebuild(6) +acquire_timestamp(After) +require_change() diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/CMakeLists.txt b/Tests/QtAutogen/RerunMocBasic/MocBasic/CMakeLists.txt index 6a9f550..42f2f57 100644 --- a/Tests/QtAutogen/RerunMocBasic/MocBasic/CMakeLists.txt +++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/CMakeLists.txt @@ -13,10 +13,15 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/main.cpp add_executable(mocBasic ${CMAKE_CURRENT_BINARY_DIR}/test1.h + ${CMAKE_CURRENT_BINARY_DIR}/myobject3.h ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + plainobject.cpp res1.qrc ) -target_include_directories(mocBasic PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_include_directories(mocBasic PRIVATE + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) target_link_libraries(mocBasic ${QT_QTCORE_TARGET}) # Write target name to text file add_custom_command(TARGET mocBasic POST_BUILD COMMAND diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/main.cpp.in b/Tests/QtAutogen/RerunMocBasic/MocBasic/main.cpp.in index 9d7ea37..5accfd6 100644 --- a/Tests/QtAutogen/RerunMocBasic/MocBasic/main.cpp.in +++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/main.cpp.in @@ -1,4 +1,5 @@ #include "test1.h" +#include "plainobject.h" extern int qInitResources_res1(); @@ -16,6 +17,7 @@ int main() Test1 test1; Test2 test2; + PlainObject plainObject; return 0; } diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/myobject3a.h.in b/Tests/QtAutogen/RerunMocBasic/MocBasic/myobject3a.h.in new file mode 100644 index 0000000..d62c314 --- /dev/null +++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/myobject3a.h.in @@ -0,0 +1,13 @@ +#ifndef MYOBJECT3_H +#define MYOBJECT3_H + +#include + +class MyObject3 : public QObject +{ + @CLASS_CONTENT@ +public: + MyObject3() {} +}; + +#endif diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.cpp b/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.cpp new file mode 100644 index 0000000..0ca785e --- /dev/null +++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.cpp @@ -0,0 +1,12 @@ +#include "plainobject.h" + +#include "myobject3.h" + +PlainObject::PlainObject() +{ +} + +void PlainObject::doSomething() +{ + MyObject3 obj3; +} diff --git a/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.h b/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.h new file mode 100644 index 0000000..8037858 --- /dev/null +++ b/Tests/QtAutogen/RerunMocBasic/MocBasic/plainobject.h @@ -0,0 +1,12 @@ +#ifndef PLAINOBJECT_H +#define PLAINOBJECT_H + +// Class that is plain C++, no Qt involved. +class PlainObject +{ +public: + PlainObject(); + void doSomething(); +}; + +#endif -- cgit v0.12 From 8cb8dd6da5552d81983c93b0cc69facac6c7b236 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Tue, 22 Dec 2020 10:53:56 +0100 Subject: AutoMoc: Re-run after adding Q_OBJECT macro Consider a Qt project with a header file that does not contain the Q_OBJECT macro. Adding the Q_OBJECT macro is supposed to trigger a run of moc. When using Qt >= 5.15 and the Ninja generator, re-running AutoMoc is controlled by the contents of a Ninja depfile. In the situation above, AutoMoc would not re-run, because the header/source files without Q_OBJECT macro are not contained in the depfile. Add the relevant source files of the project to the merged depfile to re-run AutoMoc whenever a source file changes. Fixes: #21620 --- Source/cmQtAutoMocUic.cxx | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 7365fdb..3556051 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -522,6 +522,7 @@ public: class JobDepFilesMergeT : public JobFenceT { private: + std::vector initialDependencies() const; void Process() override; }; @@ -2198,6 +2199,29 @@ std::string escapeDependencyPath(cm::string_view path) return escapedPath; } +/* + * Return the initial dependencies of the merged depfile. + * Those are dependencies from the project files, not from moc runs. + */ +std::vector +cmQtAutoMocUicT::JobDepFilesMergeT::initialDependencies() const +{ + std::vector dependencies; + dependencies.reserve(this->BaseConst().ListFiles.size() + + this->BaseEval().Headers.size() + + this->BaseEval().Sources.size()); + cm::append(dependencies, this->BaseConst().ListFiles); + auto append_file_path = + [&dependencies](const SourceFileMapT::value_type& p) { + dependencies.push_back(p.first); + }; + std::for_each(this->BaseEval().Headers.begin(), + this->BaseEval().Headers.end(), append_file_path); + std::for_each(this->BaseEval().Sources.begin(), + this->BaseEval().Sources.end(), append_file_path); + return dependencies; +} + void cmQtAutoMocUicT::JobDepFilesMergeT::Process() { if (this->Log().Verbose()) { @@ -2215,7 +2239,7 @@ void cmQtAutoMocUicT::JobDepFilesMergeT::Process() return dependenciesFromDepFile(f.c_str()); }; - std::vector dependencies = this->BaseConst().ListFiles; + std::vector dependencies = this->initialDependencies(); ParseCacheT& parseCache = this->BaseEval().ParseCache; auto processMappingEntry = [&](const MappingMapT::value_type& m) { auto cacheEntry = parseCache.GetOrInsert(m.first); -- cgit v0.12