diff options
25 files changed, 299 insertions, 34 deletions
diff --git a/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst b/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst index 3e3059d7a..5ed504ff3 100644 --- a/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst +++ b/Help/prop_tgt/AUTOMOC_PATH_PREFIX.rst @@ -13,7 +13,7 @@ the ``-p`` path prefix option. ``moc`` usually generates a relative include path in that case. :prop_tgt:`AUTOMOC_PATH_PREFIX` is initialized from the variable -:variable:`CMAKE_AUTOMOC_PATH_PREFIX`, which is ``ON`` by default. +:variable:`CMAKE_AUTOMOC_PATH_PREFIX`, which is ``OFF`` by default. See the :manual:`cmake-qt(7)` manual for more information on using CMake with Qt. @@ -24,8 +24,7 @@ Reproducible builds For reproducible builds it is recommended to keep headers that are ``moc`` compiled in one of the target :command:`include directories <target_include_directories>` and set -:prop_tgt:`AUTOMOC_PATH_PREFIX` to ``ON`` (which is the default). This ensures -that: +:prop_tgt:`AUTOMOC_PATH_PREFIX` to ``ON``. This ensures that: - ``moc`` output files are identical on different build setups, - ``moc`` output files will compile correctly when the source and/or diff --git a/Help/release/3.16.rst b/Help/release/3.16.rst index f3fdb08d2..84d96cdc8 100644 --- a/Help/release/3.16.rst +++ b/Help/release/3.16.rst @@ -178,17 +178,15 @@ Modules Autogen ------- -* When using :prop_tgt:`AUTOMOC`, CMake now generates the ``-p`` path prefix +* When using :prop_tgt:`AUTOMOC`, the new :variable:`CMAKE_AUTOMOC_PATH_PREFIX` + variable or :prop_tgt:`AUTOMOC_PATH_PREFIX` target property may be enabled + to generate the ``-p`` path prefix option for ``moc``. This ensures that ``moc`` output files are identical on different build setups (given, that the headers compiled by ``moc`` are in an :command:`include directory <target_include_directories>`). Also it ensures that ``moc`` output files will compile correctly when the source and/or build directory is a symbolic link. - The ``moc`` path prefix generation behavior can be configured by setting - the new :variable:`CMAKE_AUTOMOC_PATH_PREFIX` variable and/or - :prop_tgt:`AUTOMOC_PATH_PREFIX` target property. - CTest ----- @@ -316,3 +314,11 @@ Changes made since CMake 3.16.0 include the following. :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target properties. Previously they would be places in ``*_CFLAGS_OTHER`` variables and :prop_tgt:`INTERFACE_COMPILE_OPTIONS` target properties. + +3.16.9 +------ + +* The default value of :variable:`CMAKE_AUTOMOC_PATH_PREFIX` was changed to + ``OFF`` because this feature can break existing projects that have + identically named header files in different include directories. + This restores compatibility with behavior of CMake 3.15 and below. diff --git a/Help/release/3.17.rst b/Help/release/3.17.rst index b7c66d85a..abd746314 100644 --- a/Help/release/3.17.rst +++ b/Help/release/3.17.rst @@ -346,3 +346,12 @@ Changes made since CMake 3.17.0 include the following. :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` target properties. Previously they would be places in ``*_CFLAGS_OTHER`` variables and :prop_tgt:`INTERFACE_COMPILE_OPTIONS` target properties. + +3.17.5 +------ + +* The default value of :variable:`CMAKE_AUTOMOC_PATH_PREFIX` was changed to + ``OFF`` because this feature can break existing projects that have + identically named header files in different include directories. + This restores compatibility with behavior of CMake 3.15 and below. + The default was also changed to ``OFF`` in 3.16.9. diff --git a/Help/variable/CMAKE_AUTOMOC_PATH_PREFIX.rst b/Help/variable/CMAKE_AUTOMOC_PATH_PREFIX.rst index dca0b0657..1e9790fde 100644 --- a/Help/variable/CMAKE_AUTOMOC_PATH_PREFIX.rst +++ b/Help/variable/CMAKE_AUTOMOC_PATH_PREFIX.rst @@ -8,4 +8,4 @@ This variable is used to initialize the :prop_tgt:`AUTOMOC_PATH_PREFIX` property on all the targets. See that target property for additional information. -The default value is ``ON``. +The default value is ``OFF``. diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake index f539b4658..a773dcd4b 100644 --- a/Modules/CMakeGenericSystem.cmake +++ b/Modules/CMakeGenericSystem.cmake @@ -26,7 +26,9 @@ set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a") set(CMAKE_AUTOGEN_ORIGIN_DEPENDS ON) set(CMAKE_AUTOMOC_COMPILER_PREDEFINES ON) -set(CMAKE_AUTOMOC_PATH_PREFIX ON) +if(NOT DEFINED CMAKE_AUTOMOC_PATH_PREFIX) + set(CMAKE_AUTOMOC_PATH_PREFIX OFF) +endif() set(CMAKE_AUTOMOC_MACRO_NAMES "Q_OBJECT" "Q_GADGET" "Q_NAMESPACE" "Q_NAMESPACE_EXPORT") # basically all general purpose OSs support shared libs diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 1e82f54f2..661be1034 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 17) -set(CMake_VERSION_PATCH 4) +set(CMake_VERSION_PATCH 5) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) @@ -21,7 +21,7 @@ endif() if(NOT CMake_VERSION_NO_GIT) # If this source was exported by 'git archive', use its commit info. - set(git_info [==[103d6faed9 CMake 3.17.4]==]) + set(git_info [==[566e96d42d CMake 3.17.5]==]) # Otherwise, try to identify the current development source version. if(NOT git_info MATCHES "^([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]?[0-9a-f]?)[0-9a-f]* " diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index eed463da6..ba2ea5b1c 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -748,12 +748,8 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement( static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) - globalGen->GetRuleCmdLength(this->LanguageLinkerDeviceRule(config)); - std::string path = localGen.GetHomeRelativeOutputPath(); - if (!path.empty()) { - path += '/'; - } build.RspFile = this->ConvertToNinjaPath( - cmStrCat(path, "CMakeFiles/", genTarget->GetName(), + cmStrCat("CMakeFiles/", genTarget->GetName(), globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp")); // Gather order-only dependencies. @@ -1162,12 +1158,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( globalGen->GetRuleCmdLength(linkBuild.Rule); } - std::string path = localGen.GetHomeRelativeOutputPath(); - if (!path.empty()) { - path += '/'; - } linkBuild.RspFile = this->ConvertToNinjaPath( - cmStrCat(path, "CMakeFiles/", gt->GetName(), + cmStrCat("CMakeFiles/", gt->GetName(), globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp")); // Gather order-only dependencies. diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 629367d8c..d8b91001e 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -1180,11 +1180,54 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() if (useNinjaDepfile) { // Create a custom command that generates a timestamp file and // has a depfile assigned. The depfile is created by JobDepFilesMergeT. - - // Add additional autogen target dependencies + // + // Also create an additional '_autogen_timestamp_deps' that the custom + // command will depend on. It will have no sources or commands to + // execute, but it will have dependencies that would originally be + // assigned to the pre-Qt 5.15 'autogen' target. These dependencies will + // serve as a list of order-only dependencies for the custom command, + // without forcing the custom command to re-execute. + // + // The dependency tree would then look like + // '_autogen_timestamp_deps (order-only)' <- '/timestamp' file <- + // '_autogen' target. + const auto timestampTargetName = + cmStrCat(this->GenTarget->GetName(), "_autogen_timestamp_deps"); + std::vector<std::string> timestampTargetProvides; + cmCustomCommandLines timestampTargetCommandLines; + + // Add additional autogen target dependencies to + // '_autogen_timestamp_deps'. for (const cmTarget* t : this->AutogenTarget.DependTargets) { dependencies.push_back(t->GetName()); } + + cmTarget* timestampTarget = this->LocalGen->AddUtilityCommand( + timestampTargetName, true, this->Dir.Work.c_str(), + /*byproducts=*/timestampTargetProvides, + /*depends=*/dependencies, timestampTargetCommandLines, false, nullptr); + this->LocalGen->AddGeneratorTarget( + cm::make_unique<cmGeneratorTarget>(timestampTarget, this->LocalGen)); + + // Set FOLDER property on the timestamp target, so it appears in the + // appropriate folder in an IDE or in the file api. + if (!this->TargetsFolder.empty()) { + timestampTarget->SetProperty("FOLDER", this->TargetsFolder); + } + + // Make '/timestamp' file depend on '_autogen_timestamp_deps' and on the + // moc and uic executables (whichever are enabled). + dependencies.clear(); + dependencies.push_back(timestampTargetName); + + if (this->Moc.ExecutableTarget != nullptr) { + dependencies.push_back(this->Moc.ExecutableTarget->Target->GetName()); + } + if (this->Uic.ExecutableTarget != nullptr) { + dependencies.push_back(this->Uic.ExecutableTarget->Target->GetName()); + } + + // Create the custom command that outputs the timestamp file. const char timestampFileName[] = "timestamp"; const std::string outputFile = cmStrCat(this->Dir.Build, "/", timestampFileName); @@ -1465,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 893bd6b5d..49eb018e7 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -184,6 +184,7 @@ public: std::string DepFile; std::string DepFileRuleName; std::vector<std::string> HeaderExtensions; + std::vector<std::string> ListFiles; }; /** Shared common variables. */ @@ -2163,7 +2164,9 @@ std::string escapeDependencyPath(cm::string_view path) void cmQtAutoMocUicT::JobDepFilesMergeT::Process() { if (Log().Verbose()) { - Log().Info(GenT::MOC, "Merging MOC dependencies"); + Log().Info(GenT::MOC, + cmStrCat("Merging MOC dependencies into ", + MessagePath(BaseConst().DepFile.c_str()))); } auto processDepFile = [](const std::string& mocOutputFile) -> std::vector<std::string> { @@ -2174,7 +2177,7 @@ void cmQtAutoMocUicT::JobDepFilesMergeT::Process() return dependenciesFromDepFile(f.c_str()); }; - std::vector<std::string> dependencies; + std::vector<std::string> dependencies = BaseConst().ListFiles; ParseCacheT& parseCache = BaseEval().ParseCache; auto processMappingEntry = [&](const MappingMapT::value_type& m) { auto cacheEntry = parseCache.GetOrInsert(m.first); @@ -2256,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/MocIncludeSymlink/CMakeLists.txt b/Tests/QtAutogen/MocIncludeSymlink/CMakeLists.txt index 1627b394f..8b11b465d 100644 --- a/Tests/QtAutogen/MocIncludeSymlink/CMakeLists.txt +++ b/Tests/QtAutogen/MocIncludeSymlink/CMakeLists.txt @@ -61,6 +61,7 @@ macro(buildMocInclude sourceDir binaryDir) "${sourceDir}" MocInclude CMAKE_FLAGS "-DQT_TEST_VERSION=${QT_TEST_VERSION}" + "-DCMAKE_AUTOMOC_PATH_PREFIX=ON" "-DCMAKE_AUTOGEN_VERBOSE=${CMAKE_AUTOGEN_VERBOSE}" "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}" OUTPUT_VARIABLE output diff --git a/Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt b/Tests/QtAutogen/RerunMocOnAddFile/CMakeLists.txt new file mode 100644 index 000000000..26776595d --- /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 000000000..9e5e21c30 --- /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 000000000..45c5af681 --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/anotherobject.cpp @@ -0,0 +1,15 @@ +#include <qobject.h> + +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 000000000..f62027acb --- /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 000000000..7a1530058 --- /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 000000000..e373ee89c --- /dev/null +++ b/Tests/QtAutogen/RerunMocOnAddFile/MocOnAddFile/myobject.h @@ -0,0 +1,13 @@ +#ifndef MYOBJECT_H +#define MYOBJECT_H + +#include <qobject.h> + +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 a19a9aeec..97efa720f 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) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index e9f8bca57..0b2ef6aa2 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -134,6 +134,9 @@ if(CMAKE_GENERATOR MATCHES "Ninja") if(CMAKE_Fortran_COMPILER) list(APPEND Ninja_ARGS -DTEST_Fortran=1) endif() + if(CMake_TEST_Qt5 AND Qt5Core_FOUND) + list(APPEND Ninja_ARGS -DCMake_TEST_Qt5=1 -DCMAKE_TEST_Qt5Core_Version=${Qt5Core_VERSION}) + endif() add_RunCMake_test(Ninja) set(NinjaMultiConfig_ARGS -DCYGWIN=${CYGWIN} diff --git a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake index b77bb5432..7b479f1db 100644 --- a/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake +++ b/Tests/RunCMake/FindPkgConfig/RunCMakeTest.cmake @@ -1,5 +1,10 @@ include(RunCMake) +# Isolate test cases from caller's environment. +set(ENV{CMAKE_PREFIX_PATH} "") +set(ENV{CMAKE_APPBUNDLE_PATH} "") +set(ENV{CMAKE_FRAMEWORK_PATH} "") + run_cmake(FindPkgConfig_NO_PKGCONFIG_PATH) run_cmake(FindPkgConfig_PKGCONFIG_PATH) run_cmake(FindPkgConfig_PKGCONFIG_PATH_NO_CMAKE_PATH) diff --git a/Tests/RunCMake/Ninja/Qt5AutoMocDeps.cmake b/Tests/RunCMake/Ninja/Qt5AutoMocDeps.cmake new file mode 100644 index 000000000..d69a119ac --- /dev/null +++ b/Tests/RunCMake/Ninja/Qt5AutoMocDeps.cmake @@ -0,0 +1,9 @@ +enable_language(CXX) + +find_package(Qt5Core REQUIRED) + +set(CMAKE_AUTOMOC ON) + +add_library(simple_lib SHARED simple_lib.cpp) +add_executable(app_with_qt app.cpp app_qt.cpp) +target_link_libraries(app_with_qt PRIVATE simple_lib Qt5::Core) diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake index 0eada084c..c1f63464e 100644 --- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake +++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake @@ -132,6 +132,7 @@ ${ninja_stderr} message(FATAL_ERROR "top ninja build failed exited with status ${ninja_result}") endif() + set(ninja_stdout "${ninja_stdout}" PARENT_SCOPE) endfunction(run_ninja) function (run_LooseObjectDepends) @@ -316,3 +317,23 @@ function (run_ChangeBuildType) run_ninja("${RunCMake_TEST_BINARY_DIR}" -w dupbuild=err) endfunction() run_ChangeBuildType() + +function(run_Qt5AutoMocDeps) + if(CMake_TEST_Qt5 AND CMAKE_TEST_Qt5Core_Version VERSION_GREATER_EQUAL 5.15.0) + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Qt5AutoMocDeps-build) + run_cmake(Qt5AutoMocDeps) + unset(RunCMake_TEST_OPTIONS) + # Build the project. + run_ninja("${RunCMake_TEST_BINARY_DIR}") + # Touch just the library source file, which shouldn't cause a rerun of AUTOMOC + # for app_with_qt target. + touch("${RunCMake_SOURCE_DIR}/simple_lib.cpp") + # Build and assert that AUTOMOC was not run for app_with_qt. + run_ninja("${RunCMake_TEST_BINARY_DIR}") + if(ninja_stdout MATCHES "Automatic MOC for target app_with_qt") + message(FATAL_ERROR + "AUTOMOC should not have executed for 'app_with_qt' target:\nstdout:\n${ninja_stdout}") + endif() + endif() +endfunction() +run_Qt5AutoMocDeps() diff --git a/Tests/RunCMake/Ninja/app.cpp b/Tests/RunCMake/Ninja/app.cpp new file mode 100644 index 000000000..57380e489 --- /dev/null +++ b/Tests/RunCMake/Ninja/app.cpp @@ -0,0 +1,6 @@ +int main(int argc, char* argv[]) +{ + (void)argc; + (void)argv; + return 0; +} diff --git a/Tests/RunCMake/Ninja/app_qt.cpp b/Tests/RunCMake/Ninja/app_qt.cpp new file mode 100644 index 000000000..302c6723c --- /dev/null +++ b/Tests/RunCMake/Ninja/app_qt.cpp @@ -0,0 +1,11 @@ +#include <QObject> + +class Mango : public QObject +{ + Q_OBJECT +public: +Q_SIGNALS: + void eatFruit(); +}; + +#include "app_qt.moc" diff --git a/Tests/RunCMake/Ninja/simple_lib.cpp b/Tests/RunCMake/Ninja/simple_lib.cpp new file mode 100644 index 000000000..cf8d6893d --- /dev/null +++ b/Tests/RunCMake/Ninja/simple_lib.cpp @@ -0,0 +1,6 @@ +#ifdef _WIN32 +__declspec(dllexport) +#endif + void dummy_symbol() +{ +} diff --git a/Utilities/std/cmext/memory b/Utilities/std/cmext/memory index 50e79dfe2..fa326f0e3 100644 --- a/Utilities/std/cmext/memory +++ b/Utilities/std/cmext/memory @@ -12,18 +12,19 @@ namespace cm { -template <typename T, typename O, - cm::enable_if_t< - std::is_pointer<cm::invoke_result_t<decltype(&O::get), O>>::value, - int> = 0> +template < + typename T, typename O, + cm::enable_if_t<std::is_pointer<decltype(std::declval<O>().get())>::value, + int> = 0> T& static_reference_cast(O& item) { return *(static_cast<T*>(item.get())); } -template <typename T, typename O, - cm::enable_if_t< - std::is_pointer<cm::invoke_result_t<decltype(&O::get), O>>::value, - int> = 0> + +template < + typename T, typename O, + cm::enable_if_t<std::is_pointer<decltype(std::declval<O>().get())>::value, + int> = 0> T& dynamic_reference_cast(O& item) { auto p = dynamic_cast<T*>(item.get()); |