From 0903531964cff8888dd1cbf2a9c82ac6bb9a522f Mon Sep 17 00:00:00 2001 From: Aleix Pol Date: Thu, 6 Apr 2017 04:14:35 +0200 Subject: Autogen: Pass explicit predefines header to moc if possible Qt is relying on whoever calls moc to include a file with the predefined values that will be used by the compiler, otherwise moc takes wrong paths and weird things happen. Instead, generate an include file and feed it to all mocs to make sure it's generating correct code. Co-Author: Sebastian Holtermann Fixes: #16640 --- Modules/AutogenInfo.cmake.in | 1 + Modules/Compiler/Intel.cmake | 2 ++ Modules/Platform/Linux-GNU.cmake | 1 + Source/cmQtAutoGeneratorInitializer.cxx | 41 +++++++++++++++++++++ Source/cmQtAutoGenerators.cxx | 63 +++++++++++++++++++++++++++++++-- Source/cmQtAutoGenerators.h | 8 +++-- 6 files changed, 111 insertions(+), 5 deletions(-) diff --git a/Modules/AutogenInfo.cmake.in b/Modules/AutogenInfo.cmake.in index fcecb6c..5e945bc 100644 --- a/Modules/AutogenInfo.cmake.in +++ b/Modules/AutogenInfo.cmake.in @@ -21,6 +21,7 @@ set(AM_MOC_INCLUDES @_moc_incs@) set(AM_MOC_OPTIONS @_moc_options@) set(AM_MOC_RELAXED_MODE @_moc_relaxed_mode@) set(AM_MOC_DEPEND_FILTERS @_moc_depend_filters@) +set(AM_MOC_PREDEFS_CMD @_moc_predefs_cmd@) # UIC settings set(AM_UIC_SKIP @_uic_skip@) set(AM_UIC_TARGET_OPTIONS @_uic_target_options@) diff --git a/Modules/Compiler/Intel.cmake b/Modules/Compiler/Intel.cmake index 02968b4..06d01f1 100644 --- a/Modules/Compiler/Intel.cmake +++ b/Modules/Compiler/Intel.cmake @@ -22,5 +22,7 @@ else() string(APPEND CMAKE_${lang}_FLAGS_MINSIZEREL_INIT " -Os") string(APPEND CMAKE_${lang}_FLAGS_RELEASE_INIT " -O3") string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g") + + set(CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "${CMAKE_${lang}_COMPILER}" "-QdM" "-P" "-Za" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp") endmacro() endif() diff --git a/Modules/Platform/Linux-GNU.cmake b/Modules/Platform/Linux-GNU.cmake index 6878254..ce30a26 100644 --- a/Modules/Platform/Linux-GNU.cmake +++ b/Modules/Platform/Linux-GNU.cmake @@ -12,4 +12,5 @@ macro(__linux_compiler_gnu lang) # We pass this for historical reasons. Projects may have # executables that use dlopen but do not set ENABLE_EXPORTS. set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic") + set(CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "${CMAKE_${lang}_COMPILER}" "-dM" "-E" "-c" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp") endmacro() diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index d69794c..c7e02e6 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -96,6 +96,41 @@ static std::string GetQtMajorVersion(cmGeneratorTarget const* target) return qtMajorVersion; } +static std::string GetQtMinorVersion(cmGeneratorTarget const* target, + const std::string& qtMajorVersion) +{ + cmMakefile* makefile = target->Target->GetMakefile(); + std::string qtMinorVersion; + if (qtMajorVersion == "5") { + qtMinorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MINOR"); + } + if (qtMinorVersion.empty()) { + qtMinorVersion = makefile->GetSafeDefinition("QT_VERSION_MINOR"); + } + + const char* targetQtVersion = + target->GetLinkInterfaceDependentStringProperty("QT_MINOR_VERSION", ""); + if (targetQtVersion != CM_NULLPTR) { + qtMinorVersion = targetQtVersion; + } + return qtMinorVersion; +} + +static bool QtVersionGreaterOrEqual(const std::string& major, + const std::string& minor, + unsigned long requestMajor, + unsigned long requestMinor) +{ + unsigned long majorUL(0); + unsigned long minorUL(0); + if (cmSystemTools::StringToULong(major.c_str(), &majorUL) && + cmSystemTools::StringToULong(minor.c_str(), &minorUL)) { + return (majorUL > requestMajor) || + (majorUL == requestMajor && minorUL >= requestMinor); + } + return false; +} + static void GetCompileDefinitionsAndDirectories( cmGeneratorTarget const* target, const std::string& config, std::string& incs, std::string& defs) @@ -258,6 +293,12 @@ static void MocSetupAutoTarget( AddDefinitionEscaped(makefile, "_moc_depend_filters", GetSafeProperty(target, "AUTOMOC_DEPEND_FILTERS")); + if (QtVersionGreaterOrEqual( + qtMajorVersion, GetQtMinorVersion(target, qtMajorVersion), 5, 8)) { + AddDefinitionEscaped( + makefile, "_moc_predefs_cmd", + makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND")); + } // Moc includes and compile definitions { std::string _moc_incs; diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 246dd8d..875062c 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -360,6 +360,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( InfoGet(makefile, "AM_QT_MOC_EXECUTABLE", this->MocExecutable); InfoGet(makefile, "AM_QT_UIC_EXECUTABLE", this->UicExecutable); InfoGet(makefile, "AM_QT_RCC_EXECUTABLE", this->RccExecutable); + + InfoGet(makefile, "AM_MOC_PREDEFS_CMD", this->MocPredefsCmd); // Check Qt version if ((this->QtMajorVersion != "4") && (this->QtMajorVersion != "5")) { this->LogError("AutoGen: Error: Unsupported Qt version: " + @@ -579,6 +581,12 @@ void cmQtAutoGenerators::Init(cmMakefile* makefile) this->MocCppFilenameAbs = this->CurrentBinaryDir + this->MocCppFilenameRel; + // Moc predefs file + if (!this->MocPredefsCmd.empty()) { + this->MocPredefsFileRel = this->AutogenBuildSubDir + "moc_predefs.h"; + this->MocPredefsFileAbs = this->CurrentBinaryDir + this->MocPredefsFileRel; + } + // Init file path checksum generator fpathCheckSum.setupParentDirs(this->CurrentSourceDir, this->CurrentBinaryDir, this->ProjectSourceDir, @@ -1142,6 +1150,50 @@ bool cmQtAutoGenerators::MocGenerateAll( return true; } + // Generate moc_predefs + if (!this->MocPredefsCmd.empty()) { + if (!this->MakeParentDirectory(this->MocPredefsFileAbs)) { + this->LogError("AutoMoc: Error creating directory for " + + this->MocPredefsFileRel); + return false; + } + this->LogBold("Generating MOC predefs " + this->MocPredefsFileRel); + + std::vector cmd = this->MocPredefsCmd; + cmd.insert(cmd.end(), this->MocIncludes.begin(), this->MocIncludes.end()); + for (std::vector::const_iterator it = + this->MocDefinitions.begin(); + it != this->MocDefinitions.end(); ++it) { + cmd.push_back("-D" + (*it)); + } + cmd.insert(cmd.end(), this->MocOptions.begin(), this->MocOptions.end()); + + std::string output; + bool moc_predefsGenerated = this->RunCommand(cmd, output, false); + if (!moc_predefsGenerated) { + return false; + } + + // actually write the file + cmsys::ofstream outfile; + outfile.open(this->MocPredefsFileAbs.c_str(), std::ios::trunc); + if (!outfile) { + moc_predefsGenerated = false; + this->LogError("AutoMoc: Error opening " + this->MocPredefsFileRel); + } else { + outfile << output; + // Check for write errors + if (!outfile.good()) { + moc_predefsGenerated = false; + this->LogError("AutoMoc: Error writing " + this->MocPredefsFileRel); + } + } + + if (!moc_predefsGenerated) { + return false; + } + } + bool mocCompFileGenerated = false; bool mocCompChanged = false; @@ -1305,6 +1357,10 @@ bool cmQtAutoGenerators::MocGenerateFile( cmd.push_back("-D" + (*it)); } cmd.insert(cmd.end(), this->MocOptions.begin(), this->MocOptions.end()); + if (!this->MocPredefsFileAbs.empty()) { + cmd.push_back("--include"); + cmd.push_back(this->MocPredefsFileAbs); + } #ifdef _WIN32 cmd.push_back("-DWIN32"); #endif @@ -1805,7 +1861,7 @@ bool cmQtAutoGenerators::MakeParentDirectory(const std::string& filename) const * @return True on success */ bool cmQtAutoGenerators::RunCommand(const std::vector& command, - std::string& output) const + std::string& output, bool verbose) const { // Log command if (this->Verbose) { @@ -1813,8 +1869,9 @@ bool cmQtAutoGenerators::RunCommand(const std::vector& command, } // Execute command int retVal = 0; - bool res = - cmSystemTools::RunSingleCommand(command, &output, &output, &retVal); + bool res = cmSystemTools::RunSingleCommand( + command, &output, &output, &retVal, CM_NULLPTR, + verbose ? cmSystemTools::OUTPUT_MERGE : cmSystemTools::OUTPUT_NONE); return (res && (retVal == 0)); } diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index ee046de..cb6f45a 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -142,8 +142,8 @@ private: const char* basePrefix, const char* baseSuffix) const; bool MakeParentDirectory(const std::string& filename) const; - bool RunCommand(const std::vector& command, - std::string& output) const; + bool RunCommand(const std::vector& command, std::string& output, + bool verbose = true) const; bool FindHeader(std::string& header, const std::string& testBasePath) const; @@ -176,6 +176,8 @@ private: // - Moc std::string MocCppFilenameRel; std::string MocCppFilenameAbs; + std::string MocPredefsFileRel; + std::string MocPredefsFileAbs; std::vector MocSkipList; std::vector MocIncludePaths; std::vector MocIncludes; @@ -197,6 +199,8 @@ private: MacroFilter MacroFilters[2]; cmsys::RegularExpression RegExpMocInclude; cmsys::RegularExpression RegExpUicInclude; + // - moc_predefs + std::vector MocPredefsCmd; // - Flags bool IncludeProjectDirsBefore; bool Verbose; -- cgit v0.12