diff options
Diffstat (limited to 'Source')
49 files changed, 1992 insertions, 893 deletions
diff --git a/Source/CMakeInstallDestinations.cmake b/Source/CMakeInstallDestinations.cmake index 023f6c0..28f4e87 100644 --- a/Source/CMakeInstallDestinations.cmake +++ b/Source/CMakeInstallDestinations.cmake @@ -25,6 +25,12 @@ set(CMAKE_DOC_DIR_DESC "docs") set(CMAKE_MAN_DIR_DESC "man pages") set(CMAKE_XDGDATA_DIR_DESC "XDG specific files") +set(CMake_INSTALL_INFIX "" CACHE STRING "") +set_property(CACHE CMake_INSTALL_INFIX PROPERTY HELPSTRING + "Intermediate installation path (empty by default)" + ) +mark_as_advanced(CMake_INSTALL_INFIX) + foreach(v CMAKE_BIN_DIR CMAKE_DATA_DIR @@ -41,7 +47,7 @@ foreach(v # Use the default when the user did not set this variable. if(NOT ${v}) - set(${v} "${${v}_DEFAULT}") + set(${v} "${CMake_INSTALL_INFIX}${${v}_DEFAULT}") endif() # Remove leading slash to treat as relative to install prefix. string(REGEX REPLACE "^/" "" ${v} "${${v}}") diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index d15fdbe..2835ee6 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -710,6 +710,8 @@ if (WIN32) cmGhsMultiTargetGenerator.h cmGhsMultiGpj.cxx cmGhsMultiGpj.h + cmVSSetupHelper.cxx + cmVSSetupHelper.h ) # Add a manifest file to executables on Windows to allow for @@ -785,6 +787,15 @@ target_link_libraries(CMakeLib cmsys ${CMake_KWIML_LIBRARIES} ) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR MATCHES "sparc") + # the atomic instructions are implemented using libatomic on some platforms, + # so linking to that may be required + check_library_exists(atomic __atomic_fetch_add_4 "" LIBATOMIC_NEEDED) + if(LIBATOMIC_NEEDED) + target_link_libraries(CMakeLib atomic) + endif() +endif() + # On Apple we need CoreFoundation if(APPLE) target_link_libraries(CMakeLib "-framework CoreFoundation") diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index ff5c776..0c64d70 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 7) -set(CMake_VERSION_PATCH 20161221) +set(CMake_VERSION_PATCH 20170116) #set(CMake_VERSION_RC 1) diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx index 36566a4..5c50da8 100644 --- a/Source/CPack/cmCPackDebGenerator.cxx +++ b/Source/CPack/cmCPackDebGenerator.cxx @@ -173,7 +173,11 @@ int cmCPackDebGenerator::PackageComponentsAllInOne( std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + this->GetOutputExtension()); // all GROUP in one vs all COMPONENT in one - localToplevel += "/" + compInstDirName; + // if must be here otherwise non component paths have a trailing / while + // components don't + if (!compInstDirName.empty()) { + localToplevel += "/" + compInstDirName; + } /* replace the TEMP DIRECTORY with the component one */ this->SetOption("CPACK_TEMPORARY_DIRECTORY", localToplevel.c_str()); diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index 2c31f60..a062e64 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -305,6 +305,9 @@ void cmCTestMemCheckHandler::GenerateDartOutput(cmXMLWriter& xml) case cmCTestMemCheckHandler::ADDRESS_SANITIZER: xml.Attribute("Checker", "AddressSanitizer"); break; + case cmCTestMemCheckHandler::LEAK_SANITIZER: + xml.Attribute("Checker", "LeakSanitizer"); + break; case cmCTestMemCheckHandler::THREAD_SANITIZER: xml.Attribute("Checker", "ThreadSanitizer"); break; @@ -459,6 +462,12 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() this->LogWithPID = true; // even if we give the log file the pid is added } if (this->CTest->GetCTestConfiguration("MemoryCheckType") == + "LeakSanitizer") { + this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand"); + this->MemoryTesterStyle = cmCTestMemCheckHandler::LEAK_SANITIZER; + this->LogWithPID = true; // even if we give the log file the pid is added + } + if (this->CTest->GetCTestConfiguration("MemoryCheckType") == "ThreadSanitizer") { this->MemoryTester = this->CTest->GetCTestConfiguration("CMakeCommand"); this->MemoryTesterStyle = cmCTestMemCheckHandler::THREAD_SANITIZER; @@ -586,6 +595,7 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() } // these are almost the same but the env var used is different case cmCTestMemCheckHandler::ADDRESS_SANITIZER: + case cmCTestMemCheckHandler::LEAK_SANITIZER: case cmCTestMemCheckHandler::THREAD_SANITIZER: case cmCTestMemCheckHandler::MEMORY_SANITIZER: case cmCTestMemCheckHandler::UB_SANITIZER: { @@ -597,12 +607,20 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() this->MemoryTesterDynamicOptions.push_back("-E"); this->MemoryTesterDynamicOptions.push_back("env"); std::string envVar; - std::string extraOptions = + std::string extraOptions = ":" + this->CTest->GetCTestConfiguration("MemoryCheckSanitizerOptions"); + std::string suppressionsOption; + if (!this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile") + .empty()) { + suppressionsOption = ":suppressions=" + + this->CTest->GetCTestConfiguration("MemoryCheckSuppressionFile"); + } if (this->MemoryTesterStyle == cmCTestMemCheckHandler::ADDRESS_SANITIZER) { envVar = "ASAN_OPTIONS"; - extraOptions += " detect_leaks=1"; + } else if (this->MemoryTesterStyle == + cmCTestMemCheckHandler::LEAK_SANITIZER) { + envVar = "LSAN_OPTIONS"; } else if (this->MemoryTesterStyle == cmCTestMemCheckHandler::THREAD_SANITIZER) { envVar = "TSAN_OPTIONS"; @@ -614,8 +632,9 @@ bool cmCTestMemCheckHandler::InitializeMemoryChecking() envVar = "UBSAN_OPTIONS"; } std::string outputFile = - envVar + "=log_path=\"" + this->MemoryTesterOutputFile + "\" "; - this->MemoryTesterEnvironmentVariable = outputFile + extraOptions; + envVar + "=log_path=\"" + this->MemoryTesterOutputFile + "\""; + this->MemoryTesterEnvironmentVariable = + outputFile + suppressionsOption + extraOptions; break; } default: @@ -644,6 +663,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckOutput(const std::string& str, case cmCTestMemCheckHandler::PURIFY: return this->ProcessMemCheckPurifyOutput(str, log, results); case cmCTestMemCheckHandler::ADDRESS_SANITIZER: + case cmCTestMemCheckHandler::LEAK_SANITIZER: case cmCTestMemCheckHandler::THREAD_SANITIZER: case cmCTestMemCheckHandler::MEMORY_SANITIZER: case cmCTestMemCheckHandler::UB_SANITIZER: @@ -680,6 +700,9 @@ bool cmCTestMemCheckHandler::ProcessMemCheckSanitizerOutput( case cmCTestMemCheckHandler::ADDRESS_SANITIZER: regex = "ERROR: AddressSanitizer: (.*) on.*"; break; + case cmCTestMemCheckHandler::LEAK_SANITIZER: + // use leakWarning regex + break; case cmCTestMemCheckHandler::THREAD_SANITIZER: regex = "WARNING: ThreadSanitizer: (.*) \\(pid=.*\\)"; break; diff --git a/Source/CTest/cmCTestMemCheckHandler.h b/Source/CTest/cmCTestMemCheckHandler.h index 5faace0..ff8b593 100644 --- a/Source/CTest/cmCTestMemCheckHandler.h +++ b/Source/CTest/cmCTestMemCheckHandler.h @@ -47,6 +47,7 @@ private: BOUNDS_CHECKER, // checkers after here do not use the standard error list ADDRESS_SANITIZER, + LEAK_SANITIZER, THREAD_SANITIZER, MEMORY_SANITIZER, UB_SANITIZER diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 5c45fe5..ac1644f 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -134,6 +134,7 @@ void cmCTestRunTest::CompressOutput() size_t rlen = cmsysBase64_Encode(out, strm.total_out, encoded_buffer, 1); + this->CompressedOutput.clear(); for (size_t i = 0; i < rlen; i++) { this->CompressedOutput += encoded_buffer[i]; } @@ -416,6 +417,7 @@ bool cmCTestRunTest::StartTest(size_t total) << std::setw(getNumWidth(this->TestHandler->GetMaxIndex())) << this->TestProperties->Index << ": " << this->TestProperties->Name << std::endl); + this->ProcessOutput.clear(); this->ComputeArguments(); std::vector<std::string>& args = this->TestProperties->Args; this->TestResult.Properties = this->TestProperties; diff --git a/Source/QtDialog/RegexExplorer.cxx b/Source/QtDialog/RegexExplorer.cxx index 1512166..abed70e 100644 --- a/Source/QtDialog/RegexExplorer.cxx +++ b/Source/QtDialog/RegexExplorer.cxx @@ -64,10 +64,32 @@ void RegexExplorer::on_inputText_textChanged() return; } + std::string matchingText; + + if (matchAll->isChecked()) { + const char* p = m_text.c_str(); + while (m_regexParser.find(p)) { + std::string::size_type l = m_regexParser.start(); + std::string::size_type r = m_regexParser.end(); + if (r - l == 0) { + // matched empty string + clearMatch(); + return; + } + if (!matchingText.empty()) { + matchingText += ";"; + } + matchingText += std::string(p + l, r - l); + p += r; + } + } else { + matchingText = m_regexParser.match(0); + } + #ifdef QT_NO_STL - QString matchText = m_regexParser.match(0).c_str(); + QString matchText = matchingText.c_str(); #else - QString matchText = QString::fromStdString(m_regexParser.match(0)); + QString matchText = QString::fromStdString(matchingText); #endif match0->setPlainText(matchText); @@ -95,8 +117,16 @@ void RegexExplorer::on_matchNumber_currentIndexChanged(int index) matchN->setPlainText(match); } +void RegexExplorer::on_matchAll_toggled(bool checked) +{ + Q_UNUSED(checked); + + on_inputText_textChanged(); +} + void RegexExplorer::clearMatch() { + m_matched = false; match0->clear(); matchN->clear(); } diff --git a/Source/QtDialog/RegexExplorer.h b/Source/QtDialog/RegexExplorer.h index f1c1e5f..caef975 100644 --- a/Source/QtDialog/RegexExplorer.h +++ b/Source/QtDialog/RegexExplorer.h @@ -22,6 +22,7 @@ private slots: void on_regularExpression_textChanged(const QString& text); void on_inputText_textChanged(); void on_matchNumber_currentIndexChanged(int index); + void on_matchAll_toggled(bool checked); private: static void setStatusColor(QWidget* widget, bool successful); diff --git a/Source/QtDialog/RegexExplorer.ui b/Source/QtDialog/RegexExplorer.ui index 2c2d761..0af6999 100644 --- a/Source/QtDialog/RegexExplorer.ui +++ b/Source/QtDialog/RegexExplorer.ui @@ -104,11 +104,38 @@ <widget class="QLineEdit" name="regularExpression"/> </item> <item> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Complete Match</string> - </property> - </widget> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Complete Match</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="matchAll"> + <property name="text"> + <string>Match All</string> + </property> + </widget> + </item> + </layout> </item> <item> <widget class="QPlainTextEdit" name="match0"> diff --git a/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in b/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in index e3d8554..8cc5835 100644 --- a/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in +++ b/Source/QtIFW/CMake.DeveloperReference.HTML.qs.in @@ -11,8 +11,8 @@ Component.prototype.createOperations = function() if (installer.value("os") === "win") { component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/@CMAKE_DOC_DIR@/developer-reference/html/index.html", - installer.value("StartMenuDir") + "/CMake Developer Reference.lnk"); + "@TargetDir@/%CMAKE_DOC_DIR%/developer-reference/html/index.html", + "@StartMenuDir@/CMake Developer Reference.lnk"); } diff --git a/Source/QtIFW/CMake.Dialogs.QtGUI.qs b/Source/QtIFW/CMake.Dialogs.QtGUI.qs.in index 219a0a9..71f395a 100644 --- a/Source/QtIFW/CMake.Dialogs.QtGUI.qs +++ b/Source/QtIFW/CMake.Dialogs.QtGUI.qs.in @@ -11,8 +11,8 @@ Component.prototype.createOperations = function() if (installer.value("os") === "win") { component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/bin/cmake-gui.exe", - installer.value("StartMenuDir") + "/CMake (cmake-gui).lnk"); + "@TargetDir@/%CMAKE_BIN_DIR%/cmake-gui.exe", + "@StartMenuDir@/CMake (cmake-gui).lnk"); } diff --git a/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in b/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in index 5c929e8..54bc14a 100644 --- a/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in +++ b/Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in @@ -11,8 +11,8 @@ Component.prototype.createOperations = function() if (installer.value("os") === "win") { component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/@CMAKE_DOC_DIR@/html/index.html", - installer.value("StartMenuDir") + "/CMake Documentation.lnk"); + "@TargetDir@/%CMAKE_DOC_DIR%/html/index.html", + "@StartMenuDir@/CMake Documentation.lnk"); } diff --git a/Source/QtIFW/CMake.qs.in b/Source/QtIFW/CMake.qs.in index 828cc7c..1f3166e 100644 --- a/Source/QtIFW/CMake.qs.in +++ b/Source/QtIFW/CMake.qs.in @@ -1,3 +1,5 @@ +// Component: CMake + function Component() { // Default constructor @@ -9,12 +11,12 @@ Component.prototype.createOperations = function() if (installer.value("os") === "win") { component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/@CMAKE_DOC_DIR@/cmake.org.html", - installer.value("StartMenuDir") + "/CMake Web Site.lnk"); + "@TargetDir@/%CMAKE_DOC_DIR%/cmake.org.html", + "@StartMenuDir@/CMake Web Site.lnk"); component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/cmake-maintenance.exe", - installer.value("StartMenuDir") + "/CMake Maintenance Tool.lnk"); + "@TargetDir@/cmake-maintenance.exe", + "@StartMenuDir@/CMake Maintenance Tool.lnk"); } // Call default implementation diff --git a/Source/QtIFW/installscript.qs.in b/Source/QtIFW/installscript.qs.in index 39a8795..72d49e8 100644 --- a/Source/QtIFW/installscript.qs.in +++ b/Source/QtIFW/installscript.qs.in @@ -1,3 +1,5 @@ +// Component: CMake + function Component() { // Do not show component selection page @@ -9,15 +11,15 @@ Component.prototype.createOperations = function() // Create shortcut if (installer.value("os") === "win") { -@_CPACK_IFW_SHORTCUT_OPTIONAL@ +%_CPACK_IFW_SHORTCUT_OPTIONAL% component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/@CMAKE_DOC_DIR@/cmake.org.html", - installer.value("StartMenuDir") + "/CMake Web Site.lnk"); + "@TargetDir@/%CMAKE_DOC_DIR%/cmake.org.html", + "@StartMenuDir@/CMake Web Site.lnk"); component.addOperation("CreateShortcut", - installer.value("TargetDir") + "/cmake-maintenance.exe", - installer.value("StartMenuDir") + "/CMake Maintenance Tool.lnk"); + "@TargetDir@/cmake-maintenance.exe", + "@StartMenuDir@/CMake Maintenance Tool.lnk"); } // Call default implementation diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 7e113ab..239582f 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -63,6 +63,13 @@ void cmCommonTargetGenerator::AddFeatureFlags(std::string& flags, void cmCommonTargetGenerator::AddModuleDefinitionFlag( cmLinkLineComputer* linkLineComputer, std::string& flags) { + // A module definition file only makes sense on certain target types. + if (this->GeneratorTarget->GetType() != cmStateEnums::SHARED_LIBRARY && + this->GeneratorTarget->GetType() != cmStateEnums::MODULE_LIBRARY && + this->GeneratorTarget->GetType() != cmStateEnums::EXECUTABLE) { + return; + } + if (!this->ModuleDefinitionFile) { return; } diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index e6000db..9d4b9cc 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -12,7 +12,7 @@ #include "cmSystemTools.h" #define INCLUDE_REGEX_LINE \ - "^[ \t]*#[ \t]*(include|import)[ \t]*[<\"]([^\">]+)([\">])" + "^[ \t]*[#%][ \t]*(include|import)[ \t]*[<\"]([^\">]+)([\">])" #define INCLUDE_REGEX_LINE_MARKER "#IncludeRegexLine: " #define INCLUDE_REGEX_SCAN_MARKER "#IncludeRegexScan: " @@ -420,7 +420,7 @@ void cmDependsC::SetupTransforms() if (!this->TransformRules.empty()) { // Construct the regular expression to match lines to be // transformed. - std::string xform = "^([ \t]*#[ \t]*(include|import)[ \t]*)("; + std::string xform = "^([ \t]*[#%][ \t]*(include|import)[ \t]*)("; const char* sep = ""; for (TransformRulesType::const_iterator tri = this->TransformRules.begin(); tri != this->TransformRules.end(); ++tri) { diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index f544e8a..2dffcaa 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -48,6 +48,7 @@ cmExtraCodeBlocksGenerator::GetFactory() #if defined(_WIN32) factory.AddSupportedGlobalGenerator("MinGW Makefiles"); factory.AddSupportedGlobalGenerator("NMake Makefiles"); + factory.AddSupportedGlobalGenerator("NMake Makefiles JOM"); // disable until somebody actually tests it: // this->AddSupportedGlobalGenerator("MSYS Makefiles"); #endif @@ -741,7 +742,7 @@ std::string cmExtraCodeBlocksGenerator::BuildMakeCommand( } std::string generator = this->GlobalGenerator->GetName(); - if (generator == "NMake Makefiles") { + if (generator == "NMake Makefiles" || generator == "NMake Makefiles JOM") { // For Windows ConvertToOutputPath already adds quotes when required. // These need to be escaped, see // https://gitlab.kitware.com/cmake/cmake/issues/13952 diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index dfefefe..36ba520 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -323,16 +323,12 @@ std::string cmExtraSublimeTextGenerator::BuildMakeCommand( std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile); command += ", \"/NOLOGO\", \"/f\", \""; command += makefileName + "\""; - command += ", \"VERBOSE=1\", \""; - command += target; - command += "\""; + command += ", \"" + target + "\""; } else if (generator == "Ninja") { std::string makefileName = cmSystemTools::ConvertToOutputPath(makefile); command += ", \"-f\", \""; command += makefileName + "\""; - command += ", \"-v\", \""; - command += target; - command += "\""; + command += ", \"" + target + "\""; } else { std::string makefileName; if (generator == "MinGW Makefiles") { @@ -344,9 +340,7 @@ std::string cmExtraSublimeTextGenerator::BuildMakeCommand( } command += ", \"-f\", \""; command += makefileName + "\""; - command += ", \"VERBOSE=1\", \""; - command += target; - command += "\""; + command += ", \"" + target + "\""; } return command; } diff --git a/Source/cmFileMonitor.cxx b/Source/cmFileMonitor.cxx index 03bbf42..909be78 100644 --- a/Source/cmFileMonitor.cxx +++ b/Source/cmFileMonitor.cxx @@ -334,6 +334,9 @@ void cmFileMonitor::MonitorPaths(const std::vector<std::string>& paths, rootSegment)); // Can not be both filename and root part of the path! const std::string& currentSegment = pathSegments[i]; + if (currentSegment.empty()) { + continue; + } cmIBaseWatcher* nextWatcher = currentWatcher->Find(currentSegment); if (!nextWatcher) { diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index dde6e82..e27615a 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -425,20 +425,6 @@ std::string cmGlobalVisualStudio10Generator::FindMSBuildCommand() } } - // Search where VS15Preview places it. - mskey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7;"; - mskey += this->GetIDEVersion(); - if (cmSystemTools::ReadRegistryValue(mskey.c_str(), msbuild, - cmSystemTools::KeyWOW64_32)) { - cmSystemTools::ConvertToUnixSlashes(msbuild); - msbuild += "/MSBuild/"; - msbuild += this->GetIDEVersion(); - msbuild += "/Bin/MSBuild.exe"; - if (cmSystemTools::FileExists(msbuild, true)) { - return msbuild; - } - } - msbuild = "MSBuild.exe"; return msbuild; } diff --git a/Source/cmGlobalVisualStudio15Generator.cxx b/Source/cmGlobalVisualStudio15Generator.cxx index 20d30bc..d11ee7c 100644 --- a/Source/cmGlobalVisualStudio15Generator.cxx +++ b/Source/cmGlobalVisualStudio15Generator.cxx @@ -8,6 +8,7 @@ #include "cmMakefile.h" #include "cmVS141CLFlagTable.h" #include "cmVS141CSharpFlagTable.h" +#include "cmVSSetupHelper.h" static const char vs15generatorName[] = "Visual Studio 15 2017"; @@ -80,11 +81,7 @@ cmGlobalVisualStudio15Generator::cmGlobalVisualStudio15Generator( cmake* cm, const std::string& name, const std::string& platformName) : cmGlobalVisualStudio14Generator(cm, name, platformName) { - std::string vc15Express; - this->ExpressEdition = cmSystemTools::ReadRegistryValue( - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\15.0\\Setup\\VC;" - "ProductDir", - vc15Express, cmSystemTools::KeyWOW64_32); + this->ExpressEdition = false; this->DefaultPlatformToolset = "v141"; this->DefaultClFlagTable = cmVS141CLFlagTable; this->DefaultCSharpFlagTable = cmVS141CSharpFlagTable; @@ -118,7 +115,7 @@ bool cmGlobalVisualStudio15Generator::SelectWindowsStoreToolset( if (cmHasLiteralPrefix(this->SystemVersion, "10.0")) { if (this->IsWindowsStoreToolsetInstalled() && this->IsWindowsDesktopToolsetInstalled()) { - toolset = "v140"; // VS 15 uses v140 toolset + toolset = "v141"; // VS 15 uses v141 toolset return true; } else { return false; @@ -130,21 +127,44 @@ bool cmGlobalVisualStudio15Generator::SelectWindowsStoreToolset( bool cmGlobalVisualStudio15Generator::IsWindowsDesktopToolsetInstalled() const { - const char desktop10Key[] = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" - "VisualStudio\\15.0\\VC\\Runtimes"; - - std::vector<std::string> vc15; - return cmSystemTools::GetRegistrySubKeys(desktop10Key, vc15, - cmSystemTools::KeyWOW64_32); + return vsSetupAPIHelper.IsVS2017Installed(); } bool cmGlobalVisualStudio15Generator::IsWindowsStoreToolsetInstalled() const { - const char universal10Key[] = - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\" - "VisualStudio\\15.0\\Setup\\Build Tools for Windows 10;SrcPath"; + return vsSetupAPIHelper.IsWin10SDKInstalled(); +} + +std::string cmGlobalVisualStudio15Generator::FindMSBuildCommand() +{ + std::string msbuild; + + // Ask Visual Studio Installer tool. + std::string vs; + if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) { + msbuild = vs + "/MSBuild/15.0/Bin/MSBuild.exe"; + if (cmSystemTools::FileExists(msbuild)) { + return msbuild; + } + } + + msbuild = "MSBuild.exe"; + return msbuild; +} + +std::string cmGlobalVisualStudio15Generator::FindDevEnvCommand() +{ + std::string devenv; + + // Ask Visual Studio Installer tool. + std::string vs; + if (vsSetupAPIHelper.GetVSInstanceInfo(vs)) { + devenv = vs + "/Common7/IDE/devenv.com"; + if (cmSystemTools::FileExists(devenv)) { + return devenv; + } + } - std::string win10SDK; - return cmSystemTools::ReadRegistryValue(universal10Key, win10SDK, - cmSystemTools::KeyWOW64_32); + devenv = "devenv.com"; + return devenv; } diff --git a/Source/cmGlobalVisualStudio15Generator.h b/Source/cmGlobalVisualStudio15Generator.h index 59eb11a..781b41e 100644 --- a/Source/cmGlobalVisualStudio15Generator.h +++ b/Source/cmGlobalVisualStudio15Generator.h @@ -9,6 +9,7 @@ #include <string> #include "cmGlobalVisualStudio14Generator.h" +#include "cmVSSetupHelper.h" class cmGlobalGeneratorFactory; class cmake; @@ -39,7 +40,11 @@ protected: // of the toolset is installed bool IsWindowsStoreToolsetInstalled() const; + std::string FindMSBuildCommand() CM_OVERRIDE; + std::string FindDevEnvCommand() CM_OVERRIDE; + private: class Factory; + mutable cmVSSetupAPIHelper vsSetupAPIHelper; }; #endif diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 736aa91..96535eb 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1977,6 +1977,22 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, buildSettings->AddAttribute("HEADER_SEARCH_PATHS", dirs.CreateList()); } + if (this->XcodeVersion >= 60) { + // Add those per-language flags in addition to HEADER_SEARCH_PATHS to gain + // system include directory awareness. We need to also keep on setting + // HEADER_SEARCH_PATHS to work around a missing compile options flag for + // GNU assembly files (#16449) + for (std::set<std::string>::iterator li = languages.begin(); + li != languages.end(); ++li) { + std::string includeFlags = this->CurrentLocalGenerator->GetIncludeFlags( + includes, gtgt, *li, true, false, configName); + + if (!includeFlags.empty()) { + cflags[*li] += " " + includeFlags; + } + } + } + bool same_gflags = true; std::map<std::string, std::string> gflags; std::string const* last_gflag = 0; diff --git a/Source/cmLinkLineComputer.cxx b/Source/cmLinkLineComputer.cxx index cf0cf88..e728632 100644 --- a/Source/cmLinkLineComputer.cxx +++ b/Source/cmLinkLineComputer.cxx @@ -184,3 +184,9 @@ std::string cmLinkLineComputer::ComputeLinkLibraries( return fout.str(); } + +std::string cmLinkLineComputer::GetLinkerLanguage(cmGeneratorTarget* target, + std::string const& config) +{ + return target->GetLinkerLanguage(config); +} diff --git a/Source/cmLinkLineComputer.h b/Source/cmLinkLineComputer.h index bb13717..57a70bc 100644 --- a/Source/cmLinkLineComputer.h +++ b/Source/cmLinkLineComputer.h @@ -11,6 +11,7 @@ #include "cmStateDirectory.h" class cmComputeLinkInformation; +class cmGeneratorTarget; class cmOutputConverter; class cmLinkLineComputer @@ -36,6 +37,9 @@ public: virtual std::string ComputeLinkLibraries(cmComputeLinkInformation& cli, std::string const& stdLibString); + virtual std::string GetLinkerLanguage(cmGeneratorTarget* target, + std::string const& config); + protected: std::string ComputeLinkLibs(cmComputeLinkInformation& cli); std::string ComputeRPath(cmComputeLinkInformation& cli); diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx index 75e5ef5..6a700ff 100644 --- a/Source/cmLinkLineDeviceComputer.cxx +++ b/Source/cmLinkLineDeviceComputer.cxx @@ -59,6 +59,12 @@ std::string cmLinkLineDeviceComputer::ComputeLinkLibraries( return fout.str(); } +std::string cmLinkLineDeviceComputer::GetLinkerLanguage(cmGeneratorTarget*, + std::string const&) +{ + return "CUDA"; +} + cmNinjaLinkLineDeviceComputer::cmNinjaLinkLineDeviceComputer( cmOutputConverter* outputConverter, cmStateDirectory stateDir, cmGlobalNinjaGenerator const* gg) diff --git a/Source/cmLinkLineDeviceComputer.h b/Source/cmLinkLineDeviceComputer.h index d1079d7..f4bb3eb 100644 --- a/Source/cmLinkLineDeviceComputer.h +++ b/Source/cmLinkLineDeviceComputer.h @@ -17,6 +17,9 @@ public: std::string ComputeLinkLibraries(cmComputeLinkInformation& cli, std::string const& stdLibString) CM_OVERRIDE; + + std::string GetLinkerLanguage(cmGeneratorTarget* target, + std::string const& config) CM_OVERRIDE; }; class cmNinjaLinkLineDeviceComputer : public cmLinkLineDeviceComputer diff --git a/Source/cmListFileLexer.c b/Source/cmListFileLexer.c index 31faca1..56559f6 100644 --- a/Source/cmListFileLexer.c +++ b/Source/cmListFileLexer.c @@ -2518,7 +2518,7 @@ static void cmListFileLexerDestroy(cmListFileLexer* lexer) } /*--------------------------------------------------------------------------*/ -cmListFileLexer* cmListFileLexer_New() +cmListFileLexer* cmListFileLexer_New(void) { cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer)); if (!lexer) { diff --git a/Source/cmListFileLexer.h b/Source/cmListFileLexer.h index dfbad5e..c9fb6da 100644 --- a/Source/cmListFileLexer.h +++ b/Source/cmListFileLexer.h @@ -46,7 +46,7 @@ typedef struct cmListFileLexer_s cmListFileLexer; extern "C" { #endif -cmListFileLexer* cmListFileLexer_New(); +cmListFileLexer* cmListFileLexer_New(void); int cmListFileLexer_SetFileName(cmListFileLexer*, const char*, cmListFileLexer_BOM* bom); int cmListFileLexer_SetString(cmListFileLexer*, const char*); diff --git a/Source/cmListFileLexer.in.l b/Source/cmListFileLexer.in.l index 4b389b9..dd64923 100644 --- a/Source/cmListFileLexer.in.l +++ b/Source/cmListFileLexer.in.l @@ -398,7 +398,7 @@ static void cmListFileLexerDestroy(cmListFileLexer* lexer) } /*--------------------------------------------------------------------------*/ -cmListFileLexer* cmListFileLexer_New() +cmListFileLexer* cmListFileLexer_New(void) { cmListFileLexer* lexer = (cmListFileLexer*)malloc(sizeof(cmListFileLexer)); if (!lexer) { diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index ead1e72..44c390c 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -13,6 +13,7 @@ #include "cmInstallScriptGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmLinkLineComputer.h" +#include "cmLinkLineDeviceComputer.h" #include "cmMakefile.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" @@ -979,7 +980,9 @@ void cmLocalGenerator::GetTargetFlags( linkFlags += this->Makefile->GetSafeDefinition(build); linkFlags += " "; } - std::string linkLanguage = target->GetLinkerLanguage(buildType); + + const std::string linkLanguage = + linkLineComputer->GetLinkerLanguage(target, buildType); if (linkLanguage.empty()) { cmSystemTools::Error( "CMake can not determine linker language for target: ", diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index ba17f81..41a4caf 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1592,8 +1592,8 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( // Provide a "/fast" version of the target. depends.clear(); - if ((targetName == "install") || (targetName == "install_local") || - (targetName == "install_strip")) { + if ((targetName == "install") || (targetName == "install/local") || + (targetName == "install/strip")) { // Provide a fast install target that does not depend on all // but has the same command. depends.push_back("preinstall/fast"); diff --git a/Source/cmLocale.h b/Source/cmLocale.h index e8e751d..cca7cf5 100644 --- a/Source/cmLocale.h +++ b/Source/cmLocale.h @@ -6,10 +6,11 @@ #include <cmConfigure.h> #include <locale.h> +#include <string> class cmLocaleRAII { - const char* OldLocale; + std::string OldLocale; public: cmLocaleRAII() @@ -17,7 +18,7 @@ public: { setlocale(LC_CTYPE, ""); } - ~cmLocaleRAII() { setlocale(LC_CTYPE, this->OldLocale); } + ~cmLocaleRAII() { setlocale(LC_CTYPE, this->OldLocale.c_str()); } }; #endif diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index fccb486..cfc0495 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -2215,7 +2215,7 @@ const char* cmMakefile::GetRequiredDefinition(const std::string& name) const const char* ret = this->GetDefinition(name); if (!ret) { cmSystemTools::Error("Error required internal CMake variable not " - "set, cmake may be not be built correctly.\n", + "set, cmake may not be built correctly.\n", "Missing variable is:\n", name.c_str()); return ""; } diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 069011d..b76ddeb 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -104,10 +104,12 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( // Get the language to use for linking this library. std::string linkLanguage = "CUDA"; + std::string const objExt = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION"); // Get the name of the device object to generate. std::string const targetOutputReal = - this->GeneratorTarget->ObjectDirectory + "cmake_device_link.o"; + this->GeneratorTarget->ObjectDirectory + "cmake_device_link" + objExt; this->DeviceLinkObject = targetOutputReal; this->NumberOfProgressActions++; @@ -155,15 +157,6 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( this->LocalGenerator->AppendFlags( linkFlags, this->GeneratorTarget->GetProperty(linkFlagsConfig)); - { - CM_AUTO_PTR<cmLinkLineComputer> linkLineComputer( - this->CreateLinkLineComputer( - this->LocalGenerator, - this->LocalGenerator->GetStateSnapshot().GetDirectory())); - - this->AddModuleDefinitionFlag(linkLineComputer.get(), linkFlags); - } - // Construct a list of files associated with this executable that // may need to be cleaned. std::vector<std::string> exeCleanFiles; @@ -228,6 +221,11 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal), output); + std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB(); + std::string targetOutPathCompilePDB = + this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB, + cmOutputConverter::SHELL); + vars.Language = linkLanguage.c_str(); vars.Objects = buildObjs.c_str(); vars.ObjectDir = objectDir.c_str(); @@ -235,6 +233,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule( vars.LinkLibraries = linkLibs.c_str(); vars.Flags = flags.c_str(); vars.LinkFlags = linkFlags.c_str(); + vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); std::string launcher; diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index 2b0e1b1..27b7c21 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -281,6 +281,8 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( // Get the language to use for linking this library. std::string linkLanguage = "CUDA"; + std::string const objExt = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION"); // Create set of linking flags. std::string linkFlags; @@ -288,7 +290,7 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( // Get the name of the device object to generate. std::string const targetOutputReal = - this->GeneratorTarget->ObjectDirectory + "cmake_device_link.o"; + this->GeneratorTarget->ObjectDirectory + "cmake_device_link" + objExt; this->DeviceLinkObject = targetOutputReal; this->NumberOfProgressActions++; @@ -364,12 +366,18 @@ void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( this->LocalGenerator->GetCurrentBinaryDirectory(), targetOutputReal), output); + std::string targetFullPathCompilePDB = this->ComputeTargetCompilePDB(); + std::string targetOutPathCompilePDB = + this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB, + cmOutputConverter::SHELL); + vars.Objects = buildObjs.c_str(); vars.ObjectDir = objectDir.c_str(); vars.Target = target.c_str(); vars.LinkLibraries = linkLibs.c_str(); vars.ObjectsQuoted = buildObjs.c_str(); vars.LinkFlags = linkFlags.c_str(); + vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); // Add language feature flags. std::string langFlags; diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 0db5687..b172478 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -229,6 +229,7 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile) vars.SONameFlag = "$SONAME_FLAG"; vars.TargetSOName = "$SONAME"; vars.TargetPDB = "$TARGET_PDB"; + vars.TargetCompilePDB = "$TARGET_COMPILE_PDB"; vars.Flags = "$FLAGS"; vars.LinkFlags = "$LINK_FLAGS"; @@ -602,10 +603,12 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() // First and very important step is to make sure while inside this // step our link language is set to CUDA std::string cudaLinkLanguage = "CUDA"; + std::string const objExt = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION"); std::string const cfgName = this->GetConfigName(); - std::string const targetOutputReal = - ConvertToNinjaPath(genTarget.ObjectDirectory + "cmake_device_link.o"); + std::string const targetOutputReal = ConvertToNinjaPath( + genTarget.ObjectDirectory + "cmake_device_link" + objExt); std::string const targetOutputImplib = ConvertToNinjaPath(genTarget.GetFullPath(cfgName, @@ -660,7 +663,6 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() this->addPoolNinjaVariable("JOB_POOL_LINK", &genTarget, vars); - this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"]); vars["LINK_FLAGS"] = cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]); @@ -714,6 +716,8 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement() this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL); EnsureDirectoryExists(objPath); + this->SetMsvcTargetPdbVariable(vars); + if (this->GetGlobalGenerator()->IsGCCOnWindows()) { // ar.exe can't handle backslashes in rsp files (implicitly used by gcc) std::string& linkLibraries = vars["LINK_LIBRARIES"]; diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 23caead..8ad2efe 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -344,7 +344,8 @@ bool cmNinjaTargetGenerator::SetMsvcTargetPdbVariable(cmNinjaVars& vars) const { cmMakefile* mf = this->GetMakefile(); if (mf->GetDefinition("MSVC_C_ARCHITECTURE_ID") || - mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID")) { + mf->GetDefinition("MSVC_CXX_ARCHITECTURE_ID") || + mf->GetDefinition("MSVC_CUDA_ARCHITECTURE_ID")) { std::string pdbPath; std::string compilePdbPath = this->ComputeTargetCompilePDB(); if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE || diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index f0847b1..825eba0 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -99,39 +99,64 @@ static std::string GetQtMajorVersion(cmGeneratorTarget const* target) } static void SetupSourceFiles(cmGeneratorTarget const* target, - std::vector<std::string>& skipMoc, - std::vector<std::string>& mocSources, - std::vector<std::string>& mocHeaders, - std::vector<std::string>& skipUic) + std::vector<std::string>& mocUicSources, + std::vector<std::string>& mocUicHeaders, + std::vector<std::string>& skipMocList, + std::vector<std::string>& skipUicList) { cmMakefile* makefile = target->Target->GetMakefile(); std::vector<cmSourceFile*> srcFiles; target->GetConfigCommonSourceFiles(srcFiles); + const bool targetMoc = target->GetPropertyAsBool("AUTOMOC"); + const bool targetUic = target->GetPropertyAsBool("AUTOUIC"); + cmFilePathChecksum fpathCheckSum(makefile); for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; + const cmSystemTools::FileFormat fileType = + cmSystemTools::GetFileFormat(sf->GetExtension().c_str()); + + if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) && + !(fileType == cmSystemTools::HEADER_FILE_FORMAT)) { + continue; + } + if (cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { + continue; + } const std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); - const std::string ext = sf->GetExtension(); - - if (cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOUIC"))) { - skipUic.push_back(absFile); - } - - if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { - if (cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC"))) { - skipMoc.push_back(absFile); - } else { - cmSystemTools::FileFormat fileType = - cmSystemTools::GetFileFormat(ext.c_str()); - if (fileType == cmSystemTools::CXX_FILE_FORMAT) { - mocSources.push_back(absFile); - } else if (fileType == cmSystemTools::HEADER_FILE_FORMAT) { - mocHeaders.push_back(absFile); - } + // Skip flags + const bool skipAll = + cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOGEN")); + const bool skipMoc = + skipAll || cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC")); + const bool skipUic = + skipAll || cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOUIC")); + // Add file name to skip lists. + // Do this even when the file is not added to the sources/headers lists + // because the file name may be extracted from an other file when + // processing + if (skipMoc) { + skipMocList.push_back(absFile); + } + if (skipUic) { + skipUicList.push_back(absFile); + } + + if ((targetMoc && !skipMoc) || (targetUic && !skipUic)) { + // Add file name to sources or headers list + switch (fileType) { + case cmSystemTools::CXX_FILE_FORMAT: + mocUicSources.push_back(absFile); + break; + case cmSystemTools::HEADER_FILE_FORMAT: + mocUicHeaders.push_back(absFile); + break; + default: + break; } } } @@ -158,7 +183,6 @@ static void GetCompileDefinitionsAndDirectories( static void MocSetupAutoTarget( cmGeneratorTarget const* target, const std::string& autogenTargetName, std::vector<std::string> const& skipMoc, - std::vector<std::string> const& mocHeaders, std::map<std::string, std::string>& configIncludes, std::map<std::string, std::string>& configDefines) { @@ -172,9 +196,6 @@ static void MocSetupAutoTarget( makefile->AddDefinition( "_skip_moc", cmOutputConverter::EscapeForCMake(cmJoin(skipMoc, ";")).c_str()); - makefile->AddDefinition( - "_moc_headers", - cmOutputConverter::EscapeForCMake(cmJoin(mocHeaders, ";")).c_str()); bool relaxedMode = makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE"); makefile->AddDefinition("_moc_relaxed_mode", relaxedMode ? "TRUE" : "FALSE"); @@ -569,7 +590,9 @@ static void RccSetupAutoTarget(cmGeneratorTarget const* target, std::string ext = sf->GetExtension(); if (ext == "qrc") { std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); - bool skip = cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC")); + const bool skip = + cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOGEN")) || + cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC")); if (!skip) { _rcc_files += sepRccFiles; @@ -632,7 +655,8 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenSources( cmMakefile* makefile = target->Target->GetMakefile(); const std::string mocCppFile = GetAutogenTargetBuildDir(target) + "moc_compilation.cpp"; - makefile->GetOrCreateSource(mocCppFile, true); + cmSourceFile* gf = makefile->GetOrCreateSource(mocCppFile, true); + gf->SetProperty("SKIP_AUTOGEN", "On"); target->AddSource(mocCppFile); } } @@ -650,6 +674,14 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( const std::string qtMajorVersion = GetQtMajorVersion(target); std::vector<std::string> autogenOutputFiles; + // Remove old settings on cleanup + { + std::string fname = GetAutogenTargetFilesDir(target); + fname += "/AutogenOldSettings.cmake"; + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fname.c_str(), + false); + } + // Create autogen target build directory and add it to the clean files cmSystemTools::MakeDirectory(autogenBuildDir); makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", @@ -747,6 +779,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; if (sf->GetExtension() == "qrc" && + !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOGEN")) && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { { const std::string absFile = @@ -763,7 +796,8 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( rccOutputFile += ".cpp"; // Add rcc output file to origin target sources - makefile->GetOrCreateSource(rccOutputFile, true); + cmSourceFile* gf = makefile->GetOrCreateSource(rccOutputFile, true); + gf->SetProperty("SKIP_AUTOGEN", "On"); target->AddSource(rccOutputFile); // Register rcc output file as generated autogenOutputFiles.push_back(rccOutputFile); @@ -850,10 +884,10 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( cmOutputConverter::EscapeForCMake(target->GetName()).c_str()); makefile->AddDefinition("_target_qt_version", qtMajorVersion.c_str()); - std::vector<std::string> skipUic; + std::vector<std::string> mocUicSources; + std::vector<std::string> mocUicHeaders; std::vector<std::string> skipMoc; - std::vector<std::string> mocSources; - std::vector<std::string> mocHeaders; + std::vector<std::string> skipUic; std::map<std::string, std::string> configMocIncludes; std::map<std::string, std::string> configMocDefines; std::map<std::string, std::string> configUicOptions; @@ -861,14 +895,18 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( if (target->GetPropertyAsBool("AUTOMOC") || target->GetPropertyAsBool("AUTOUIC") || target->GetPropertyAsBool("AUTORCC")) { - SetupSourceFiles(target, skipMoc, mocSources, mocHeaders, skipUic); + SetupSourceFiles(target, mocUicSources, mocUicHeaders, skipMoc, skipUic); } makefile->AddDefinition( - "_cpp_files", - cmOutputConverter::EscapeForCMake(cmJoin(mocSources, ";")).c_str()); + "_moc_uic_sources", + cmOutputConverter::EscapeForCMake(cmJoin(mocUicSources, ";")).c_str()); + makefile->AddDefinition( + "_moc_uic_headers", + cmOutputConverter::EscapeForCMake(cmJoin(mocUicHeaders, ";")).c_str()); + if (target->GetPropertyAsBool("AUTOMOC")) { - MocSetupAutoTarget(target, autogenTargetName, skipMoc, mocHeaders, - configMocIncludes, configMocDefines); + MocSetupAutoTarget(target, autogenTargetName, skipMoc, configMocIncludes, + configMocDefines); } if (target->GetPropertyAsBool("AUTOUIC")) { UicSetupAutoTarget(target, skipUic, configUicOptions); diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index a9a9c49..c84fe4f 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -6,7 +6,6 @@ #include <assert.h> #include <cmConfigure.h> #include <cmsys/FStream.hxx> -#include <cmsys/RegularExpression.hxx> #include <cmsys/Terminal.h> #include <iostream> #include <sstream> @@ -28,28 +27,39 @@ #include <unistd.h> #endif -static bool requiresMocing(const std::string& text, std::string& macroName) -{ - // this simple check is much much faster than the regexp - if (strstr(text.c_str(), "Q_OBJECT") == CM_NULLPTR && - strstr(text.c_str(), "Q_GADGET") == CM_NULLPTR) { - return false; - } +// -- Static variables - cmsys::RegularExpression qObjectRegExp("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); - if (qObjectRegExp.find(text)) { - macroName = "Q_OBJECT"; - return true; +static const char* MocOldSettingsKey = "AM_MOC_OLD_SETTINGS"; +static const char* UicOldSettingsKey = "AM_UIC_OLD_SETTINGS"; +static const char* RccOldSettingsKey = "AM_RCC_OLD_SETTINGS"; + +// -- Static functions + +static std::string GetConfigDefinition(cmMakefile* makefile, + const std::string& key, + const std::string& config) +{ + std::string keyConf = key; + if (!config.empty()) { + keyConf += "_"; + keyConf += config; } - cmsys::RegularExpression qGadgetRegExp("[\n][ \t]*Q_GADGET[^a-zA-Z0-9_]"); - if (qGadgetRegExp.find(text)) { - macroName = "Q_GADGET"; - return true; + const char* valueConf = makefile->GetDefinition(keyConf); + if (valueConf != CM_NULLPTR) { + return valueConf; } - return false; + return makefile->GetSafeDefinition(key); } -static std::string findMatchingHeader( +static std::string OldSettingsFile(const std::string& targetDirectory) +{ + std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); + cmSystemTools::ConvertToUnixSlashes(filename); + filename += "/AutogenOldSettings.cmake"; + return filename; +} + +static std::string FindMatchingHeader( const std::string& absPath, const std::string& mocSubDir, const std::string& basename, const std::vector<std::string>& headerExtensions) @@ -62,6 +72,7 @@ static std::string findMatchingHeader( header = sourceFilePath; break; } + // Try subdirectory instead if (!mocSubDir.empty()) { sourceFilePath = mocSubDir + basename + "." + (*ext); if (cmsys::SystemTools::FileExists(sourceFilePath.c_str())) { @@ -74,7 +85,7 @@ static std::string findMatchingHeader( return header; } -static std::string extractSubDir(const std::string& absPath, +static std::string ExtractSubDir(const std::string& absPath, const std::string& currentMoc) { std::string subDir; @@ -101,29 +112,69 @@ static bool FileNameIsUnique(const std::string& filePath, return true; } -cmQtAutoGenerators::cmQtAutoGenerators() - : Verbose(cmsys::SystemTools::HasEnv("VERBOSE")) - , ColorOutput(true) - , RunMocFailed(false) - , RunUicFailed(false) - , RunRccFailed(false) - , GenerateAll(false) +static std::string ReadAll(const std::string& filename) { + cmsys::ifstream file(filename.c_str()); + std::ostringstream stream; + stream << file.rdbuf(); + file.close(); + return stream.str(); +} - std::string colorEnv; - cmsys::SystemTools::GetEnv("COLOR", colorEnv); - if (!colorEnv.empty()) { - if (cmSystemTools::IsOn(colorEnv.c_str())) { - this->ColorOutput = true; - } else { - this->ColorOutput = false; +/** + * @brief Tests if buildFile doesn't exist or is older than sourceFile + * @return True if buildFile doesn't exist or is older than sourceFile + */ +static bool FileAbsentOrOlder(const std::string& buildFile, + const std::string& sourceFile) +{ + int result = 0; + bool success = + cmsys::SystemTools::FileTimeCompare(buildFile, sourceFile, &result); + return (!success || (result <= 0)); +} + +static bool ListContains(const std::vector<std::string>& list, + const std::string& entry) +{ + return (std::find(list.begin(), list.end(), entry) != list.end()); +} + +static std::string JoinOptions(const std::map<std::string, std::string>& opts) +{ + std::string result; + for (std::map<std::string, std::string>::const_iterator it = opts.begin(); + it != opts.end(); ++it) { + if (it != opts.begin()) { + result += "%%%"; + } + result += it->first; + result += "==="; + result += it->second; + } + return result; +} + +static std::string JoinExts(const std::vector<std::string>& lst) +{ + std::string result; + if (!lst.empty()) { + const std::string separator = ","; + for (std::vector<std::string>::const_iterator it = lst.begin(); + it != lst.end(); ++it) { + if (it != lst.begin()) { + result += separator; + } + result += '.'; + result += *it; } } + return result; } -void cmQtAutoGenerators::MergeUicOptions( - std::vector<std::string>& opts, const std::vector<std::string>& fileOpts, - bool isQt5) +static void UicMergeOptions(std::vector<std::string>& opts, + const std::vector<std::string>& fileOpts, + bool isQt5) { static const char* valueOptions[] = { "tr", "translate", "postfix", "generator", @@ -155,6 +206,39 @@ void cmQtAutoGenerators::MergeUicOptions( opts.insert(opts.end(), extraOpts.begin(), extraOpts.end()); } +// -- Class methods + +cmQtAutoGenerators::cmQtAutoGenerators() + : Verbose(cmsys::SystemTools::HasEnv("VERBOSE")) + , ColorOutput(true) + , RunMocFailed(false) + , RunUicFailed(false) + , RunRccFailed(false) + , GenerateMocAll(false) + , GenerateUicAll(false) + , GenerateRccAll(false) +{ + + std::string colorEnv; + cmsys::SystemTools::GetEnv("COLOR", colorEnv); + if (!colorEnv.empty()) { + if (cmSystemTools::IsOn(colorEnv.c_str())) { + this->ColorOutput = true; + } else { + this->ColorOutput = false; + } + } + + // Precompile regular expressions + this->RegExpQObject.compile("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); + this->RegExpQGadget.compile("[\n][ \t]*Q_GADGET[^a-zA-Z0-9_]"); + this->RegExpMocInclude.compile( + "[\n][ \t]*#[ \t]*include[ \t]+" + "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); + this->RegExpUicInclude.compile("[\n][ \t]*#[ \t]*include[ \t]+" + "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); +} + bool cmQtAutoGenerators::Run(const std::string& targetDirectory, const std::string& config) { @@ -174,15 +258,20 @@ bool cmQtAutoGenerators::Run(const std::string& targetDirectory, if (!this->ReadAutogenInfoFile(mf.get(), targetDirectory, config)) { return false; } - this->ReadOldMocDefinitionsFile(mf.get(), targetDirectory); + // Read old settings + this->OldSettingsReadFile(mf.get(), targetDirectory); + // Init and run this->Init(); - if (this->QtMajorVersion == "4" || this->QtMajorVersion == "5") { if (!this->RunAutogen(mf.get())) { return false; } } - return this->WriteOldMocDefinitionsFile(targetDirectory); + // Write latest settings + if (!this->OldSettingsWriteFile(targetDirectory)) { + return false; + } + return true; } bool cmQtAutoGenerators::ReadAutogenInfoFile( @@ -195,7 +284,7 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( if (!makefile->ReadListFile(filename.c_str())) { std::ostringstream err; - err << "AUTOGEN: error processing file: " << filename << std::endl; + err << "AutoGen: error processing file: " << filename << std::endl; this->LogError(err.str()); return false; } @@ -224,59 +313,38 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( this->RccExecutable = makefile->GetSafeDefinition("AM_QT_RCC_EXECUTABLE"); // - File Lists - this->Sources = makefile->GetSafeDefinition("AM_SOURCES"); - this->Headers = makefile->GetSafeDefinition("AM_HEADERS"); + cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition("AM_SOURCES"), + this->Sources); + cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition("AM_HEADERS"), + this->Headers); // - Moc - this->SkipMoc = makefile->GetSafeDefinition("AM_SKIP_MOC"); - { - std::string compileDefsPropOrig = "AM_MOC_COMPILE_DEFINITIONS"; - std::string compileDefsProp = compileDefsPropOrig; - if (!config.empty()) { - compileDefsProp += "_"; - compileDefsProp += config; - } - const char* compileDefs = makefile->GetDefinition(compileDefsProp); - this->MocCompileDefinitionsStr = compileDefs - ? compileDefs - : makefile->GetSafeDefinition(compileDefsPropOrig); - } - { - std::string includesPropOrig = "AM_MOC_INCLUDES"; - std::string includesProp = includesPropOrig; - if (!config.empty()) { - includesProp += "_"; - includesProp += config; - } - const char* includes = makefile->GetDefinition(includesProp); - this->MocIncludesStr = - includes ? includes : makefile->GetSafeDefinition(includesPropOrig); - } + cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition("AM_SKIP_MOC"), + this->SkipMoc); + this->MocCompileDefinitionsStr = + GetConfigDefinition(makefile, "AM_MOC_COMPILE_DEFINITIONS", config); + this->MocIncludesStr = + GetConfigDefinition(makefile, "AM_MOC_INCLUDES", config); this->MocOptionsStr = makefile->GetSafeDefinition("AM_MOC_OPTIONS"); // - Uic - this->SkipUic = makefile->GetSafeDefinition("AM_SKIP_UIC"); + cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition("AM_SKIP_UIC"), + this->SkipUic); + cmSystemTools::ExpandListArgument( + GetConfigDefinition(makefile, "AM_UIC_TARGET_OPTIONS", config), + this->UicTargetOptions); { - const char* uicOptionsFiles = - makefile->GetSafeDefinition("AM_UIC_OPTIONS_FILES"); - std::string uicOptionsPropOrig = "AM_UIC_TARGET_OPTIONS"; - std::string uicOptionsProp = uicOptionsPropOrig; - if (!config.empty()) { - uicOptionsProp += "_"; - uicOptionsProp += config; - } - const char* uicTargetOptions = makefile->GetSafeDefinition(uicOptionsProp); - cmSystemTools::ExpandListArgument( - uicTargetOptions ? uicTargetOptions - : makefile->GetSafeDefinition(uicOptionsPropOrig), - this->UicTargetOptions); - const char* uicOptionsOptions = - makefile->GetSafeDefinition("AM_UIC_OPTIONS_OPTIONS"); std::vector<std::string> uicFilesVec; - cmSystemTools::ExpandListArgument(uicOptionsFiles, uicFilesVec); std::vector<std::string> uicOptionsVec; - cmSystemTools::ExpandListArgument(uicOptionsOptions, uicOptionsVec); + cmSystemTools::ExpandListArgument( + makefile->GetSafeDefinition("AM_UIC_OPTIONS_FILES"), uicFilesVec); + cmSystemTools::ExpandListArgument( + makefile->GetSafeDefinition("AM_UIC_OPTIONS_OPTIONS"), uicOptionsVec); if (uicFilesVec.size() != uicOptionsVec.size()) { + std::ostringstream err; + err << "AutoGen: Error: Uic files/options lists size missmatch in: " + << filename << std::endl; + this->LogError(err.str()); return false; } for (std::vector<std::string>::iterator fileIt = uicFilesVec.begin(), @@ -288,20 +356,20 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } // - Rcc + cmSystemTools::ExpandListArgument( + makefile->GetSafeDefinition("AM_RCC_SOURCES"), this->RccSources); { - std::string rccSources = makefile->GetSafeDefinition("AM_RCC_SOURCES"); - cmSystemTools::ExpandListArgument(rccSources, this->RccSources); - } - { - const char* rccOptionsFiles = - makefile->GetSafeDefinition("AM_RCC_OPTIONS_FILES"); - const char* rccOptionsOptions = - makefile->GetSafeDefinition("AM_RCC_OPTIONS_OPTIONS"); std::vector<std::string> rccFilesVec; - cmSystemTools::ExpandListArgument(rccOptionsFiles, rccFilesVec); std::vector<std::string> rccOptionsVec; - cmSystemTools::ExpandListArgument(rccOptionsOptions, rccOptionsVec); + cmSystemTools::ExpandListArgument( + makefile->GetSafeDefinition("AM_RCC_OPTIONS_FILES"), rccFilesVec); + cmSystemTools::ExpandListArgument( + makefile->GetSafeDefinition("AM_RCC_OPTIONS_OPTIONS"), rccOptionsVec); if (rccFilesVec.size() != rccOptionsVec.size()) { + std::ostringstream err; + err << "AutoGen: Error: RCC files/options lists size missmatch in: " + << filename << std::endl; + this->LogError(err.str()); return false; } for (std::vector<std::string>::iterator fileIt = rccFilesVec.begin(), @@ -310,10 +378,11 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";"); this->RccOptions[*fileIt] = *optionIt; } - - const char* rccInputs = makefile->GetSafeDefinition("AM_RCC_INPUTS"); + } + { std::vector<std::string> rccInputLists; - cmSystemTools::ExpandListArgument(rccInputs, rccInputLists); + cmSystemTools::ExpandListArgument( + makefile->GetSafeDefinition("AM_RCC_INPUTS"), rccInputLists); // qrc files in the end of the list may have been empty if (rccInputLists.size() < this->RccSources.size()) { @@ -321,26 +390,21 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } if (this->RccSources.size() != rccInputLists.size()) { std::ostringstream err; - err << "AUTOGEN: RCC sources lists size missmatch in: " << filename; - err << std::endl; + err << "AutoGen: Error: RCC sources/inputs lists size missmatch in: " + << filename << std::endl; this->LogError(err.str()); return false; } - for (std::vector<std::string>::iterator fileIt = this->RccSources.begin(), inputIt = rccInputLists.begin(); fileIt != this->RccSources.end(); ++fileIt, ++inputIt) { cmSystemTools::ReplaceString(*inputIt, "@list_sep@", ";"); std::vector<std::string> rccInputFiles; cmSystemTools::ExpandListArgument(*inputIt, rccInputFiles); - this->RccInputs[*fileIt] = rccInputFiles; } } - // - Settings - this->CurrentCompileSettingsStr = this->MakeCompileSettingsString(makefile); - // - Flags this->IncludeProjectDirsBefore = makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); @@ -349,58 +413,124 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( return true; } -std::string cmQtAutoGenerators::MakeCompileSettingsString(cmMakefile* makefile) +std::string cmQtAutoGenerators::MocSettingsStringCompose() { - std::string s; - s += makefile->GetSafeDefinition("AM_MOC_COMPILE_DEFINITIONS"); - s += " ~~~ "; - s += makefile->GetSafeDefinition("AM_MOC_INCLUDES"); - s += " ~~~ "; - s += makefile->GetSafeDefinition("AM_MOC_OPTIONS"); - s += " ~~~ "; - s += makefile->IsOn("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE") ? "TRUE" - : "FALSE"; - s += " ~~~ "; - - return s; + std::string res; + res += this->MocCompileDefinitionsStr; + res += " ~~~ "; + res += this->MocIncludesStr; + res += " ~~~ "; + res += this->MocOptionsStr; + res += " ~~~ "; + res += this->IncludeProjectDirsBefore ? "TRUE" : "FALSE"; + res += " ~~~ "; + return res; } -void cmQtAutoGenerators::ReadOldMocDefinitionsFile( - cmMakefile* makefile, const std::string& targetDirectory) +std::string cmQtAutoGenerators::UicSettingsStringCompose() { - std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); - cmSystemTools::ConvertToUnixSlashes(filename); - filename += "/AutomocOldMocDefinitions.cmake"; + std::string res; + res += cmJoin(this->UicTargetOptions, "@osep@"); + res += " ~~~ "; + res += JoinOptions(this->UicOptions); + res += " ~~~ "; + return res; +} + +std::string cmQtAutoGenerators::RccSettingsStringCompose() +{ + std::string res; + res += JoinOptions(this->RccOptions); + res += " ~~~ "; + return res; +} - if (makefile->ReadListFile(filename.c_str())) { - this->OldCompileSettingsStr = - makefile->GetSafeDefinition("AM_OLD_COMPILE_SETTINGS"); +void cmQtAutoGenerators::OldSettingsReadFile( + cmMakefile* makefile, const std::string& targetDirectory) +{ + if (!this->MocExecutable.empty() || !this->UicExecutable.empty() || + !this->RccExecutable.empty()) { + // Compose current settings strings + this->MocSettingsString = this->MocSettingsStringCompose(); + this->UicSettingsString = this->UicSettingsStringCompose(); + this->RccSettingsString = this->RccSettingsStringCompose(); + + // Read old settings + const std::string filename = OldSettingsFile(targetDirectory); + if (makefile->ReadListFile(filename.c_str())) { + if (!this->MocExecutable.empty()) { + const std::string sol = makefile->GetSafeDefinition(MocOldSettingsKey); + if (sol != this->MocSettingsString) { + this->GenerateMocAll = true; + } + } + if (!this->UicExecutable.empty()) { + const std::string sol = makefile->GetSafeDefinition(UicOldSettingsKey); + if (sol != this->UicSettingsString) { + this->GenerateUicAll = true; + } + } + if (!this->RccExecutable.empty()) { + const std::string sol = makefile->GetSafeDefinition(RccOldSettingsKey); + if (sol != this->RccSettingsString) { + this->GenerateRccAll = true; + } + } + // In case any setting changed remove the old settings file. + // This triggers a full rebuild on the next run if the current + // build is aborted before writing the current settings in the end. + if (this->GenerateMocAll || this->GenerateUicAll || + this->GenerateRccAll) { + cmSystemTools::RemoveFile(filename); + } + } else { + // If the file could not be read re-generate everythiung. + this->GenerateMocAll = true; + this->GenerateUicAll = true; + this->GenerateRccAll = true; + } } } -bool cmQtAutoGenerators::WriteOldMocDefinitionsFile( +bool cmQtAutoGenerators::OldSettingsWriteFile( const std::string& targetDirectory) { bool success = true; - - std::string filename(cmSystemTools::CollapseFullPath(targetDirectory)); - cmSystemTools::ConvertToUnixSlashes(filename); - filename += "/AutomocOldMocDefinitions.cmake"; - - { + // Only write if any setting changed + if (this->GenerateMocAll || this->GenerateUicAll || this->GenerateRccAll) { + const std::string filename = OldSettingsFile(targetDirectory); cmsys::ofstream outfile; outfile.open(filename.c_str(), std::ios::trunc); if (outfile) { - outfile << "set(AM_OLD_COMPILE_SETTINGS " - << cmOutputConverter::EscapeForCMake( - this->CurrentCompileSettingsStr) - << ")\n"; + if (!this->MocExecutable.empty()) { + outfile << "set(" << MocOldSettingsKey << " " + << cmOutputConverter::EscapeForCMake(this->MocSettingsString) + << ")\n"; + } + if (!this->UicExecutable.empty()) { + outfile << "set(" << UicOldSettingsKey << " " + << cmOutputConverter::EscapeForCMake(this->UicSettingsString) + << ")\n"; + } + if (!this->RccExecutable.empty()) { + outfile << "set(" << RccOldSettingsKey << " " + << cmOutputConverter::EscapeForCMake(this->RccSettingsString) + << ")\n"; + } success = outfile.good(); + outfile.close(); } else { success = false; + // Remove old settings file to trigger full rebuild on next run + cmSystemTools::RemoveFile(filename); + { + std::ostringstream err; + err << "AutoGen: Error: Writing old settings file failed: " << filename + << std::endl; + this->LogError(err.str()); + } } } - return success; } @@ -455,7 +585,6 @@ void cmQtAutoGenerators::Init() if (this->IncludeProjectDirsBefore) { const std::string binDir = "-I" + this->ProjectBinaryDir; - const std::string srcDir = "-I" + this->ProjectSourceDir; std::list<std::string> sortedMocIncludes; @@ -484,22 +613,8 @@ void cmQtAutoGenerators::Init() } } -static std::string ReadAll(const std::string& filename) -{ - cmsys::ifstream file(filename.c_str()); - std::ostringstream stream; - stream << file.rdbuf(); - file.close(); - return stream.str(); -} - bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile) { - // If settings changed everything needs to be re-generated. - if (this->OldCompileSettingsStr != this->CurrentCompileSettingsStr) { - this->GenerateAll = true; - } - // the program goes through all .cpp files to see which moc files are // included. It is not really interesting how the moc file is named, but // what file the moc is created from. Once a moc is included the same moc @@ -510,269 +625,353 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile) // key = moc source filepath, value = moc output filepath std::map<std::string, std::string> includedMocs; - // collect all headers which may need to be mocced - std::set<std::string> headerFiles; - - std::vector<std::string> sourceFiles; - cmSystemTools::ExpandListArgument(this->Sources, sourceFiles); - - const std::vector<std::string>& headerExtensions = - makefile->GetCMakeInstance()->GetHeaderExtensions(); - + std::map<std::string, std::string> notIncludedMocs; std::map<std::string, std::vector<std::string> > includedUis; - std::map<std::string, std::vector<std::string> > skippedUis; - std::vector<std::string> uicSkipped; - cmSystemTools::ExpandListArgument(this->SkipUic, uicSkipped); - - for (std::vector<std::string>::const_iterator it = sourceFiles.begin(); - it != sourceFiles.end(); ++it) { - const bool skipUic = - std::find(uicSkipped.begin(), uicSkipped.end(), *it) != uicSkipped.end(); - std::map<std::string, std::vector<std::string> >& uiFiles = - skipUic ? skippedUis : includedUis; - const std::string& absFilename = *it; - if (this->Verbose) { - std::ostringstream err; - err << "AUTOGEN: Checking " << absFilename << std::endl; - this->LogInfo(err.str()); - } - if (this->MocRelaxedMode) { - if (!this->ParseCppFile(absFilename, headerExtensions, includedMocs, - uiFiles)) { - return false; - } - } else { - if (!this->StrictParseCppFile(absFilename, headerExtensions, - includedMocs, uiFiles)) { + // collects all headers which may need to be mocced + std::set<std::string> headerFilesMoc; + std::set<std::string> headerFilesUic; + + // Parse sources + { + const std::vector<std::string>& headerExtensions = + makefile->GetCMakeInstance()->GetHeaderExtensions(); + + for (std::vector<std::string>::const_iterator it = this->Sources.begin(); + it != this->Sources.end(); ++it) { + const std::string& absFilename = *it; + // Parse source file for MOC/UIC + if (!this->ParseSourceFile(absFilename, headerExtensions, includedMocs, + includedUis, this->MocRelaxedMode)) { return false; } + // Find additional headers + this->SearchHeadersForSourceFile(absFilename, headerExtensions, + headerFilesMoc, headerFilesUic); } - this->SearchHeadersForCppFile(absFilename, headerExtensions, headerFiles); } - { - std::vector<std::string> mocSkipped; - cmSystemTools::ExpandListArgument(this->SkipMoc, mocSkipped); - for (std::vector<std::string>::const_iterator it = mocSkipped.begin(); - it != mocSkipped.end(); ++it) { - if (std::find(uicSkipped.begin(), uicSkipped.end(), *it) != - uicSkipped.end()) { - const std::string& absFilename = *it; - if (this->Verbose) { - std::ostringstream err; - err << "AUTOGEN: Checking " << absFilename << std::endl; - this->LogInfo(err.str()); - } - this->ParseForUic(absFilename, includedUis); - } + // Parse headers + for (std::vector<std::string>::const_iterator it = this->Headers.begin(); + it != this->Headers.end(); ++it) { + const std::string& headerName = *it; + if (!this->MocSkipTest(headerName)) { + headerFilesMoc.insert(this->Headers.begin(), this->Headers.end()); + } + if (!this->UicSkipTest(headerName)) { + headerFilesUic.insert(this->Headers.begin(), this->Headers.end()); } } + this->ParseHeaders(headerFilesMoc, headerFilesUic, includedMocs, + notIncludedMocs, includedUis); - std::vector<std::string> headerFilesVec; - cmSystemTools::ExpandListArgument(this->Headers, headerFilesVec); - headerFiles.insert(headerFilesVec.begin(), headerFilesVec.end()); + // Generate files + if (!this->MocGenerateAll(includedMocs, notIncludedMocs)) { + return false; + } + if (!this->UicGenerateAll(includedUis)) { + return false; + } + if (!this->QrcGenerateAll()) { + return false; + } - // key = moc source filepath, value = moc output filename - std::map<std::string, std::string> notIncludedMocs; - this->ParseHeaders(headerFiles, includedMocs, notIncludedMocs, includedUis); + return true; +} - if (!this->MocExecutable.empty()) { - if (!this->GenerateMocFiles(includedMocs, notIncludedMocs)) { - return false; +/** + * @brief Tests if the C++ content requires moc processing + * @return True if moc is required + */ +bool cmQtAutoGenerators::MocRequired(const std::string& text, + std::string& macroName) +{ + // Run a simple check before an expensive regular expression check + if (strstr(text.c_str(), "Q_OBJECT") != CM_NULLPTR) { + if (this->RegExpQObject.find(text)) { + macroName = "Q_OBJECT"; + return true; } } - if (!this->UicExecutable.empty()) { - if (!this->GenerateUiFiles(includedUis)) { - return false; + if (strstr(text.c_str(), "Q_GADGET") != CM_NULLPTR) { + if (this->RegExpQGadget.find(text)) { + macroName = "Q_GADGET"; + return true; } } - if (!this->RccExecutable.empty()) { - if (!this->GenerateQrcFiles()) { + return false; +} + +/** + * @brief Tests if the file should be ignored for moc scanning + * @return True if the file should be ignored + */ +bool cmQtAutoGenerators::MocSkipTest(const std::string& absFilename) +{ + // Test if moc scanning is enabled + if (!this->MocExecutable.empty()) { + // Test if the file name is on the skip list + if (!ListContains(this->SkipMoc, absFilename)) { return false; } } + return true; +} +/** + * @brief Tests if the file name is in the skip list + */ +bool cmQtAutoGenerators::UicSkipTest(const std::string& absFilename) +{ + // Test if uic scanning is enabled + if (!this->UicExecutable.empty()) { + // Test if the file name is on the skip list + if (!ListContains(this->SkipUic, absFilename)) { + return false; + } + } return true; } /** * @return True on success */ -bool cmQtAutoGenerators::ParseCppFile( +bool cmQtAutoGenerators::ParseSourceFile( const std::string& absFilename, const std::vector<std::string>& headerExtensions, std::map<std::string, std::string>& includedMocs, - std::map<std::string, std::vector<std::string> >& includedUis) + std::map<std::string, std::vector<std::string> >& includedUis, bool relaxed) { - cmsys::RegularExpression mocIncludeRegExp( - "[\n][ \t]*#[ \t]*include[ \t]+" - "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); - + bool success = true; const std::string contentsString = ReadAll(absFilename); if (contentsString.empty()) { std::ostringstream err; - err << "AUTOGEN: warning: " << absFilename << ": file is empty\n" - << std::endl; + err << "AutoGen: Warning: " << absFilename << "\n" + << "The file is empty\n"; this->LogWarning(err.str()); - return true; + } else { + // Parse source contents for MOC + if (success && !this->MocSkipTest(absFilename)) { + success = this->ParseContentForMoc( + absFilename, contentsString, headerExtensions, includedMocs, relaxed); + } + // Parse source contents for UIC + if (success && !this->UicSkipTest(absFilename)) { + this->ParseContentForUic(absFilename, contentsString, includedUis); + } } - this->ParseForUic(absFilename, contentsString, includedUis); - if (this->MocExecutable.empty()) { - return true; + return success; +} + +void cmQtAutoGenerators::ParseContentForUic( + const std::string& absFilename, const std::string& contentsString, + std::map<std::string, std::vector<std::string> >& includedUis) +{ + // Process + if (this->Verbose) { + std::ostringstream err; + err << "AutoUic: Checking " << absFilename << "\n"; + this->LogInfo(err.str()); + } + + const std::string realName = cmsys::SystemTools::GetRealPath(absFilename); + const char* contentChars = contentsString.c_str(); + if (strstr(contentChars, "ui_") != CM_NULLPTR) { + while (this->RegExpUicInclude.find(contentChars)) { + const std::string currentUi = this->RegExpUicInclude.match(1); + const std::string basename = + cmsys::SystemTools::GetFilenameWithoutLastExtension(currentUi); + // basename should be the part of the ui filename used for + // finding the correct header, so we need to remove the ui_ part + includedUis[realName].push_back(basename.substr(3)); + contentChars += this->RegExpUicInclude.end(); + } + } +} + +/** + * @return True on success + */ +bool cmQtAutoGenerators::ParseContentForMoc( + const std::string& absFilename, const std::string& contentsString, + const std::vector<std::string>& headerExtensions, + std::map<std::string, std::string>& includedMocs, bool relaxed) +{ + // Process + if (this->Verbose) { + std::ostringstream err; + err << "AutoMoc: Checking " << absFilename << "\n"; + this->LogInfo(err.str()); } - const std::string absPath = cmsys::SystemTools::GetFilenamePath( - cmsys::SystemTools::GetRealPath(absFilename)) + + const std::string scannedFileAbsPath = + cmsys::SystemTools::GetFilenamePath( + cmsys::SystemTools::GetRealPath(absFilename)) + '/'; const std::string scannedFileBasename = cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); + std::string macroName; - const bool requiresMoc = requiresMocing(contentsString, macroName); - bool dotMocIncluded = false; - bool mocUnderscoreIncluded = false; + const bool requiresMoc = this->MocRequired(contentsString, macroName); + bool ownDotMocIncluded = false; + bool ownMocUnderscoreIncluded = false; std::string ownMocUnderscoreFile; - std::string ownDotMocFile; std::string ownMocHeaderFile; - std::string::size_type matchOffset = 0; // first a simple string check for "moc" is *much* faster than the regexp, // and if the string search already fails, we don't have to try the // expensive regexp - if ((strstr(contentsString.c_str(), "moc") != CM_NULLPTR) && - (mocIncludeRegExp.find(contentsString))) { - // for every moc include in the file - do { - const std::string currentMoc = mocIncludeRegExp.match(1); - + const char* contentChars = contentsString.c_str(); + if (strstr(contentChars, "moc") != CM_NULLPTR) { + // Iterate over all included moc files + while (this->RegExpMocInclude.find(contentChars)) { + const std::string currentMoc = this->RegExpMocInclude.match(1); + // Basename of the current moc include std::string basename = cmsys::SystemTools::GetFilenameWithoutLastExtension(currentMoc); - const bool moc_style = cmHasLiteralPrefix(basename, "moc_"); // If the moc include is of the moc_foo.cpp style we expect // the Q_OBJECT class declaration in a header file. // If the moc include is of the foo.moc style we need to look for // a Q_OBJECT macro in the current source file, if it contains the // macro we generate the moc file from the source file. - // Q_OBJECT - if (moc_style) { + if (cmHasLiteralPrefix(basename, "moc_")) { + // Include: moc_FOO.cxx // basename should be the part of the moc filename used for // finding the correct header, so we need to remove the moc_ part basename = basename.substr(4); - std::string mocSubDir = extractSubDir(absPath, currentMoc); - std::string headerToMoc = - findMatchingHeader(absPath, mocSubDir, basename, headerExtensions); + const std::string mocSubDir = + ExtractSubDir(scannedFileAbsPath, currentMoc); + const std::string headerToMoc = FindMatchingHeader( + scannedFileAbsPath, mocSubDir, basename, headerExtensions); if (!headerToMoc.empty()) { includedMocs[headerToMoc] = currentMoc; - if (basename == scannedFileBasename) { - mocUnderscoreIncluded = true; + if (relaxed && (basename == scannedFileBasename)) { + ownMocUnderscoreIncluded = true; ownMocUnderscoreFile = currentMoc; ownMocHeaderFile = headerToMoc; } } else { std::ostringstream err; - err << "AUTOGEN: error: " << absFilename << ": The file " - << "includes the moc file \"" << currentMoc << "\", " - << "but could not find header \"" << basename << '{' - << this->JoinExts(headerExtensions) << "}\" "; + err << "AutoMoc: Error: " << absFilename << "\n" + << "The file includes the moc file \"" << currentMoc + << "\", but could not find header \"" << basename << '{' + << JoinExts(headerExtensions) << "}\" "; if (mocSubDir.empty()) { - err << "in " << absPath << "\n" << std::endl; + err << "in " << scannedFileAbsPath << "\n"; } else { - err << "neither in " << absPath << " nor in " << mocSubDir << "\n" - << std::endl; + err << "neither in " << scannedFileAbsPath << " nor in " + << mocSubDir << "\n"; } this->LogError(err.str()); return false; } } else { - std::string fileToMoc = absFilename; - if (!requiresMoc || basename != scannedFileBasename) { - std::string mocSubDir = extractSubDir(absPath, currentMoc); - std::string headerToMoc = - findMatchingHeader(absPath, mocSubDir, basename, headerExtensions); - if (!headerToMoc.empty()) { - // this is for KDE4 compatibility: - fileToMoc = headerToMoc; - if (!requiresMoc && basename == scannedFileBasename) { - std::ostringstream err; - err << "AUTOGEN: warning: " << absFilename - << ": The file " - "includes the moc file \"" - << currentMoc << "\", but does not contain a " << macroName - << " macro. Running moc on " - << "\"" << headerToMoc << "\" ! Include \"moc_" << basename - << ".cpp\" for a compatibility with " - "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n" - << std::endl; - this->LogWarning(err.str()); + // Include: FOO.moc + std::string fileToMoc; + if (relaxed) { + // Mode: Relaxed + if (!requiresMoc || basename != scannedFileBasename) { + const std::string mocSubDir = + ExtractSubDir(scannedFileAbsPath, currentMoc); + const std::string headerToMoc = FindMatchingHeader( + scannedFileAbsPath, mocSubDir, basename, headerExtensions); + if (!headerToMoc.empty()) { + // This is for KDE4 compatibility: + fileToMoc = headerToMoc; + if (!requiresMoc && basename == scannedFileBasename) { + std::ostringstream err; + err << "AutoMoc: Warning: " << absFilename << "\n" + << "The file includes the moc file \"" << currentMoc + << "\", but does not contain a " << macroName + << " macro. Running moc on " + << "\"" << headerToMoc << "\" ! Include \"moc_" << basename + << ".cpp\" for a compatibility with " + "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"; + this->LogWarning(err.str()); + } else { + std::ostringstream err; + err << "AutoMoc: Warning: " << absFilename << "\n" + << "The file includes the moc file \"" << currentMoc + << "\" instead of \"moc_" << basename + << ".cpp\". Running moc on " + << "\"" << headerToMoc << "\" ! Include \"moc_" << basename + << ".cpp\" for compatibility with " + "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"; + this->LogWarning(err.str()); + } } else { std::ostringstream err; - err << "AUTOGEN: warning: " << absFilename - << ": The file " - "includes the moc file \"" - << currentMoc << "\" instead of \"moc_" << basename - << ".cpp\". " - "Running moc on " - << "\"" << headerToMoc << "\" ! Include \"moc_" << basename - << ".cpp\" for compatibility with " - "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n" - << std::endl; - this->LogWarning(err.str()); + err << "AutoMoc: Error: " << absFilename << "\n" + << "The file includes the moc file \"" << currentMoc + << "\", which seems to be the moc file from a different " + "source file. CMake also could not find a matching " + "header.\n"; + this->LogError(err.str()); + return false; } } else { + // Include self + fileToMoc = absFilename; + ownDotMocIncluded = true; + } + } else { + // Mode: Strict + if (basename == scannedFileBasename) { + // Include self + fileToMoc = absFilename; + ownDotMocIncluded = true; + } else { + // Don't allow FOO.moc include other than self in strict mode std::ostringstream err; - err << "AUTOGEN: error: " << absFilename - << ": The file " - "includes the moc file \"" - << currentMoc + err << "AutoMoc: Error: " << absFilename << "\n" + << "The file includes the moc file \"" << currentMoc << "\", which seems to be the moc file from a different " - "source file. CMake also could not find a matching " - "header.\n" - << std::endl; + "source file. This is not supported. Include \"" + << scannedFileBasename + << ".moc\" to run moc on this source file.\n"; this->LogError(err.str()); return false; } - } else { - dotMocIncluded = true; - ownDotMocFile = currentMoc; } - includedMocs[fileToMoc] = currentMoc; + if (!fileToMoc.empty()) { + includedMocs[fileToMoc] = currentMoc; + } } - matchOffset += mocIncludeRegExp.end(); - } while (mocIncludeRegExp.find(contentsString.c_str() + matchOffset)); + // Forward content pointer + contentChars += this->RegExpMocInclude.end(); + } } // In this case, check whether the scanned file itself contains a Q_OBJECT. // If this is the case, the moc_foo.cpp should probably be generated from // foo.cpp instead of foo.h, because otherwise it won't build. // But warn, since this is not how it is supposed to be used. - if (!dotMocIncluded && requiresMoc) { - if (mocUnderscoreIncluded) { - // this is for KDE4 compatibility: + if (requiresMoc && !ownDotMocIncluded) { + if (relaxed && ownMocUnderscoreIncluded) { + // This is for KDE4 compatibility: std::ostringstream err; - err << "AUTOGEN: warning: " << absFilename << ": The file " - << "contains a " << macroName << " macro, but does not " - "include " - << "\"" << scannedFileBasename << ".moc\", but instead " - "includes " + err << "AutoMoc: Warning: " << absFilename << "\n" + << "The file contains a " << macroName + << " macro, but does not include " + << "\"" << scannedFileBasename << ".moc\", but instead includes " << "\"" << ownMocUnderscoreFile << "\". Running moc on " << "\"" << absFilename << "\" ! Better include \"" << scannedFileBasename << ".moc\" for compatibility with " - "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n" - << std::endl; + "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"; this->LogWarning(err.str()); + // Use scanned source file instead of scanned header file as moc source includedMocs[absFilename] = ownMocUnderscoreFile; includedMocs.erase(ownMocHeaderFile); } else { - // otherwise always error out since it will not compile: + // Otherwise always error out since it will not compile: std::ostringstream err; - err << "AUTOGEN: error: " << absFilename << ": The file " - << "contains a " << macroName << " macro, but does not " - "include " - << "\"" << scannedFileBasename << ".moc\" !\n" - << std::endl; + err << "AutoMoc: Error: " << absFilename << "\n" + << "The file contains a " << macroName + << " macro, but does not include " + << "\"" << scannedFileBasename << ".moc\" !\n"; this->LogError(err.str()); return false; } @@ -781,244 +980,101 @@ bool cmQtAutoGenerators::ParseCppFile( return true; } -/** - * @return True on success - */ -bool cmQtAutoGenerators::StrictParseCppFile( +void cmQtAutoGenerators::SearchHeadersForSourceFile( const std::string& absFilename, const std::vector<std::string>& headerExtensions, - std::map<std::string, std::string>& includedMocs, - std::map<std::string, std::vector<std::string> >& includedUis) -{ - cmsys::RegularExpression mocIncludeRegExp( - "[\n][ \t]*#[ \t]*include[ \t]+" - "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); - - const std::string contentsString = ReadAll(absFilename); - if (contentsString.empty()) { - std::ostringstream err; - err << "AUTOGEN: warning: " << absFilename << ": file is empty\n" - << std::endl; - this->LogWarning(err.str()); - return true; - } - this->ParseForUic(absFilename, contentsString, includedUis); - if (this->MocExecutable.empty()) { - return true; - } - - const std::string absPath = cmsys::SystemTools::GetFilenamePath( - cmsys::SystemTools::GetRealPath(absFilename)) + - '/'; - const std::string scannedFileBasename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); - - bool dotMocIncluded = false; - - std::string::size_type matchOffset = 0; - // first a simple string check for "moc" is *much* faster than the regexp, - // and if the string search already fails, we don't have to try the - // expensive regexp - if ((strstr(contentsString.c_str(), "moc") != CM_NULLPTR) && - (mocIncludeRegExp.find(contentsString))) { - // for every moc include in the file - do { - const std::string currentMoc = mocIncludeRegExp.match(1); - - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(currentMoc); - const bool mocUnderscoreStyle = cmHasLiteralPrefix(basename, "moc_"); - - // If the moc include is of the moc_foo.cpp style we expect - // the Q_OBJECT class declaration in a header file. - // If the moc include is of the foo.moc style we need to look for - // a Q_OBJECT macro in the current source file, if it contains the - // macro we generate the moc file from the source file. - if (mocUnderscoreStyle) { - // basename should be the part of the moc filename used for - // finding the correct header, so we need to remove the moc_ part - basename = basename.substr(4); - std::string mocSubDir = extractSubDir(absPath, currentMoc); - std::string headerToMoc = - findMatchingHeader(absPath, mocSubDir, basename, headerExtensions); - - if (!headerToMoc.empty()) { - includedMocs[headerToMoc] = currentMoc; - } else { - std::ostringstream err; - err << "AUTOGEN: error: " << absFilename << " The file " - << "includes the moc file \"" << currentMoc << "\", " - << "but could not find header \"" << basename << '{' - << this->JoinExts(headerExtensions) << "}\" "; - if (mocSubDir.empty()) { - err << "in " << absPath << "\n" << std::endl; - } else { - err << "neither in " << absPath << " nor in " << mocSubDir << "\n" - << std::endl; - } - this->LogError(err.str()); - return false; - } - } else { - if (basename != scannedFileBasename) { - std::ostringstream err; - err << "AUTOGEN: error: " << absFilename - << ": The file " - "includes the moc file \"" - << currentMoc - << "\", which seems to be the moc file from a different " - "source file. This is not supported. " - "Include \"" - << scannedFileBasename << ".moc\" to run " - "moc on this source file.\n" - << std::endl; - this->LogError(err.str()); - return false; - } - dotMocIncluded = true; - includedMocs[absFilename] = currentMoc; - } - matchOffset += mocIncludeRegExp.end(); - } while (mocIncludeRegExp.find(contentsString.c_str() + matchOffset)); - } - - // In this case, check whether the scanned file itself contains a Q_OBJECT. - // If this is the case, the moc_foo.cpp should probably be generated from - // foo.cpp instead of foo.h, because otherwise it won't build. - // But warn, since this is not how it is supposed to be used. - std::string macroName; - if (!dotMocIncluded && requiresMocing(contentsString, macroName)) { - // otherwise always error out since it will not compile: - std::ostringstream err; - err << "AUTOGEN: error: " << absFilename << ": The file " - << "contains a " << macroName << " macro, but does not include " - << "\"" << scannedFileBasename << ".moc\" !\n" - << std::endl; - this->LogError(err.str()); - return false; - } - - return true; -} - -void cmQtAutoGenerators::ParseForUic( - const std::string& absFilename, - std::map<std::string, std::vector<std::string> >& includedUis) -{ - if (this->UicExecutable.empty()) { - return; - } - const std::string contentsString = ReadAll(absFilename); - if (contentsString.empty()) { - std::ostringstream err; - err << "AUTOGEN: warning: " << absFilename << ": file is empty\n" - << std::endl; - this->LogWarning(err.str()); - return; - } - this->ParseForUic(absFilename, contentsString, includedUis); -} - -void cmQtAutoGenerators::ParseForUic( - const std::string& absFilename, const std::string& contentsString, - std::map<std::string, std::vector<std::string> >& includedUis) -{ - if (this->UicExecutable.empty()) { - return; - } - cmsys::RegularExpression uiIncludeRegExp( - "[\n][ \t]*#[ \t]*include[ \t]+" - "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); - - std::string::size_type matchOffset = 0; - - const std::string realName = cmsys::SystemTools::GetRealPath(absFilename); - - matchOffset = 0; - if ((strstr(contentsString.c_str(), "ui_") != CM_NULLPTR) && - (uiIncludeRegExp.find(contentsString))) { - do { - const std::string currentUi = uiIncludeRegExp.match(1); - - std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(currentUi); - - // basename should be the part of the ui filename used for - // finding the correct header, so we need to remove the ui_ part - basename = basename.substr(3); - - includedUis[realName].push_back(basename); - - matchOffset += uiIncludeRegExp.end(); - } while (uiIncludeRegExp.find(contentsString.c_str() + matchOffset)); - } -} - -void cmQtAutoGenerators::SearchHeadersForCppFile( - const std::string& absFilename, - const std::vector<std::string>& headerExtensions, - std::set<std::string>& absHeaders) + std::set<std::string>& absHeadersMoc, std::set<std::string>& absHeadersUic) { // search for header files and private header files we may need to moc: - const std::string basename = - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); - const std::string absPath = cmsys::SystemTools::GetFilenamePath( - cmsys::SystemTools::GetRealPath(absFilename)) + - '/'; + std::string basepath = cmsys::SystemTools::GetFilenamePath( + cmsys::SystemTools::GetRealPath(absFilename)); + basepath += '/'; + basepath += cmsys::SystemTools::GetFilenameWithoutLastExtension(absFilename); + // Search for regular header for (std::vector<std::string>::const_iterator ext = headerExtensions.begin(); ext != headerExtensions.end(); ++ext) { - const std::string headerName = absPath + basename + "." + (*ext); + const std::string headerName = basepath + "." + (*ext); if (cmsys::SystemTools::FileExists(headerName.c_str())) { - absHeaders.insert(headerName); + // Moc headers + if (!this->MocSkipTest(absFilename) && !this->MocSkipTest(headerName)) { + absHeadersMoc.insert(headerName); + } + // Uic headers + if (!this->UicSkipTest(absFilename) && !this->UicSkipTest(headerName)) { + absHeadersUic.insert(headerName); + } break; } } + // Search for private header for (std::vector<std::string>::const_iterator ext = headerExtensions.begin(); ext != headerExtensions.end(); ++ext) { - const std::string privateHeaderName = absPath + basename + "_p." + (*ext); - if (cmsys::SystemTools::FileExists(privateHeaderName.c_str())) { - absHeaders.insert(privateHeaderName); + const std::string headerName = basepath + "_p." + (*ext); + if (cmsys::SystemTools::FileExists(headerName.c_str())) { + // Moc headers + if (!this->MocSkipTest(absFilename) && !this->MocSkipTest(headerName)) { + absHeadersMoc.insert(headerName); + } + // Uic headers + if (!this->UicSkipTest(absFilename) && !this->UicSkipTest(headerName)) { + absHeadersUic.insert(headerName); + } break; } } } void cmQtAutoGenerators::ParseHeaders( - const std::set<std::string>& absHeaders, + const std::set<std::string>& absHeadersMoc, + const std::set<std::string>& absHeadersUic, const std::map<std::string, std::string>& includedMocs, std::map<std::string, std::string>& notIncludedMocs, std::map<std::string, std::vector<std::string> >& includedUis) { - for (std::set<std::string>::const_iterator hIt = absHeaders.begin(); - hIt != absHeaders.end(); ++hIt) { + // Merged header files list to read files only once + std::set<std::string> headerFiles; + headerFiles.insert(absHeadersMoc.begin(), absHeadersMoc.end()); + headerFiles.insert(absHeadersUic.begin(), absHeadersUic.end()); + + for (std::set<std::string>::const_iterator hIt = headerFiles.begin(); + hIt != headerFiles.end(); ++hIt) { const std::string& headerName = *hIt; const std::string contents = ReadAll(headerName); - if (!this->MocExecutable.empty() && - includedMocs.find(headerName) == includedMocs.end()) { + // Parse header content for MOC + if ((absHeadersMoc.find(headerName) != absHeadersMoc.end()) && + (includedMocs.find(headerName) == includedMocs.end())) { + // Process if (this->Verbose) { std::ostringstream err; - err << "AUTOGEN: Checking " << headerName << std::endl; + err << "AutoMoc: Checking " << headerName << "\n"; this->LogInfo(err.str()); } - std::string macroName; - if (requiresMocing(contents, macroName)) { + if (this->MocRequired(contents, macroName)) { notIncludedMocs[headerName] = fpathCheckSum.getPart(headerName) + "/moc_" + cmsys::SystemTools::GetFilenameWithoutLastExtension(headerName) + ".cpp"; } } - this->ParseForUic(headerName, contents, includedUis); + + // Parse header content for UIC + if (absHeadersUic.find(headerName) != absHeadersUic.end()) { + this->ParseContentForUic(headerName, contents, includedUis); + } } } -bool cmQtAutoGenerators::GenerateMocFiles( +bool cmQtAutoGenerators::MocGenerateAll( const std::map<std::string, std::string>& includedMocs, const std::map<std::string, std::string>& notIncludedMocs) { + if (this->MocExecutable.empty()) { + return true; + } + // look for name collisions { std::multimap<std::string, std::string> collisions; @@ -1027,7 +1083,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( mergedMocs.insert(notIncludedMocs.begin(), notIncludedMocs.end()); if (this->NameCollisionTest(mergedMocs, collisions)) { std::ostringstream err; - err << "AUTOGEN: error: " + err << "AutoMoc: Error: " "The same moc file will be generated " "from different sources." << std::endl @@ -1045,7 +1101,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( for (std::map<std::string, std::string>::const_iterator it = includedMocs.begin(); it != includedMocs.end(); ++it) { - if (!this->GenerateMoc(it->first, it->second, subDirPrefix)) { + if (!this->MocGenerateFile(it->first, it->second, subDirPrefix)) { if (this->RunMocFailed) { return false; } @@ -1060,7 +1116,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( for (std::map<std::string, std::string>::const_iterator it = notIncludedMocs.begin(); it != notIncludedMocs.end(); ++it) { - if (this->GenerateMoc(it->first, it->second, subDirPrefix)) { + if (this->MocGenerateFile(it->first, it->second, subDirPrefix)) { automocCppChanged = true; } else { if (this->RunMocFailed) { @@ -1098,7 +1154,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( // nothing changed: don't touch the moc_compilation.cpp file if (this->Verbose) { std::ostringstream err; - err << "AUTOGEN: " << this->OutMocCppFilenameRel << " still up to date" + err << "AutoMoc: " << this->OutMocCppFilenameRel << " still up to date" << std::endl; this->LogInfo(err.str()); } @@ -1113,14 +1169,14 @@ bool cmQtAutoGenerators::GenerateMocFiles( this->LogBold(msg); } // Make sure the parent directory exists - bool success = this->makeParentDirectory(this->OutMocCppFilenameAbs); + bool success = this->MakeParentDirectory(this->OutMocCppFilenameAbs); if (success) { cmsys::ofstream outfile; outfile.open(this->OutMocCppFilenameAbs.c_str(), std::ios::trunc); if (!outfile) { success = false; std::ostringstream err; - err << "AUTOGEN: error opening " << this->OutMocCppFilenameAbs << "\n"; + err << "AutoMoc: error opening " << this->OutMocCppFilenameAbs << "\n"; this->LogError(err.str()); } else { outfile << automocSource; @@ -1128,7 +1184,7 @@ bool cmQtAutoGenerators::GenerateMocFiles( if (!outfile.good()) { success = false; std::ostringstream err; - err << "AUTOGEN: error writing " << this->OutMocCppFilenameAbs << "\n"; + err << "AutoMoc: error writing " << this->OutMocCppFilenameAbs << "\n"; this->LogError(err.str()); } } @@ -1139,22 +1195,25 @@ bool cmQtAutoGenerators::GenerateMocFiles( /** * @return True if a moc file was created. False may indicate an error. */ -bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile, - const std::string& mocFileName, - const std::string& subDirPrefix) +bool cmQtAutoGenerators::MocGenerateFile(const std::string& sourceFile, + const std::string& mocFileName, + const std::string& subDirPrefix) { const std::string mocFileRel = this->AutogenBuildSubDir + subDirPrefix + mocFileName; const std::string mocFileAbs = this->CurrentBinaryDir + mocFileRel; - int sourceNewerThanMoc = 0; - bool success = cmsys::SystemTools::FileTimeCompare(sourceFile, mocFileAbs, - &sourceNewerThanMoc); - if (this->GenerateAll || !success || sourceNewerThanMoc >= 0) { + + bool generateMoc = this->GenerateMocAll; + // Test if the source file is newer that the build file + if (!generateMoc) { + generateMoc = FileAbsentOrOlder(mocFileAbs, sourceFile); + } + if (generateMoc) { // Log this->LogBold("Generating MOC source " + mocFileRel); // Make sure the parent directory exists - if (!this->makeParentDirectory(mocFileAbs)) { + if (!this->MakeParentDirectory(mocFileAbs)) { this->RunMocFailed = true; return false; } @@ -1185,7 +1244,7 @@ bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile, if (!result || retVal) { { std::ostringstream err; - err << "AUTOGEN: error: moc process for " << mocFileRel << " failed:\n" + err << "AutoMoc: Error: moc process for " << mocFileRel << " failed:\n" << output << std::endl; this->LogError(err.str()); } @@ -1198,9 +1257,13 @@ bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile, return false; } -bool cmQtAutoGenerators::GenerateUiFiles( +bool cmQtAutoGenerators::UicGenerateAll( const std::map<std::string, std::vector<std::string> >& includedUis) { + if (this->UicExecutable.empty()) { + return true; + } + // single map with input / output names std::map<std::string, std::map<std::string, std::string> > uiGenMap; std::map<std::string, std::string> testMap; @@ -1228,7 +1291,7 @@ bool cmQtAutoGenerators::GenerateUiFiles( std::multimap<std::string, std::string> collisions; if (this->NameCollisionTest(testMap, collisions)) { std::ostringstream err; - err << "AUTOGEN: error: The same ui_NAME.h file will be generated " + err << "AutoUic: Error: The same ui_NAME.h file will be generated " "from different sources." << std::endl << "To avoid this error rename the source files." << std::endl; @@ -1246,7 +1309,7 @@ bool cmQtAutoGenerators::GenerateUiFiles( for (std::map<std::string, std::string>::const_iterator sit = it->second.begin(); sit != it->second.end(); ++sit) { - if (!this->GenerateUi(it->first, sit->first, sit->second)) { + if (!this->UicGenerateFile(it->first, sit->first, sit->second)) { if (this->RunUicFailed) { return false; } @@ -1260,23 +1323,25 @@ bool cmQtAutoGenerators::GenerateUiFiles( /** * @return True if a uic file was created. False may indicate an error. */ -bool cmQtAutoGenerators::GenerateUi(const std::string& realName, - const std::string& uiInputFile, - const std::string& uiOutputFile) +bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, + const std::string& uiInputFile, + const std::string& uiOutputFile) { const std::string uicFileRel = this->AutogenBuildSubDir + "include/" + uiOutputFile; const std::string uicFileAbs = this->CurrentBinaryDir + uicFileRel; - int sourceNewerThanUi = 0; - bool success = cmsys::SystemTools::FileTimeCompare(uiInputFile, uicFileAbs, - &sourceNewerThanUi); - if (this->GenerateAll || !success || sourceNewerThanUi >= 0) { + bool generateUic = this->GenerateUicAll; + // Test if the source file is newer that the build file + if (!generateUic) { + generateUic = FileAbsentOrOlder(uicFileAbs, uiInputFile); + } + if (generateUic) { // Log this->LogBold("Generating UIC header " + uicFileRel); // Make sure the parent directory exists - if (!this->makeParentDirectory(uicFileAbs)) { + if (!this->MakeParentDirectory(uicFileAbs)) { this->RunUicFailed = true; return false; } @@ -1290,8 +1355,7 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, if (optionIt != this->UicOptions.end()) { std::vector<std::string> fileOpts; cmSystemTools::ExpandListArgument(optionIt->second, fileOpts); - cmQtAutoGenerators::MergeUicOptions(opts, fileOpts, - this->QtMajorVersion == "5"); + UicMergeOptions(opts, fileOpts, this->QtMajorVersion == "5"); } command.insert(command.end(), opts.begin(), opts.end()); @@ -1309,7 +1373,7 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, if (!result || retVal) { { std::ostringstream err; - err << "AUTOUIC: error: uic process for " << uicFileRel + err << "AutoUic: Error: uic process for " << uicFileRel << " needed by\n \"" << realName << "\"\nfailed:\n" << output << std::endl; this->LogError(err.str()); @@ -1323,24 +1387,12 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName, return false; } -bool cmQtAutoGenerators::InputFilesNewerThanQrc(const std::string& qrcFile, - const std::string& rccOutput) +bool cmQtAutoGenerators::QrcGenerateAll() { - std::vector<std::string> const& files = this->RccInputs[qrcFile]; - for (std::vector<std::string>::const_iterator it = files.begin(); - it != files.end(); ++it) { - int inputNewerThanQrc = 0; - bool success = - cmsys::SystemTools::FileTimeCompare(*it, rccOutput, &inputNewerThanQrc); - if (!success || inputNewerThanQrc >= 0) { - return true; - } + if (this->RccExecutable.empty()) { + return true; } - return false; -} -bool cmQtAutoGenerators::GenerateQrcFiles() -{ // generate single map with input / output names std::map<std::string, std::string> qrcGenMap; for (std::vector<std::string>::const_iterator si = this->RccSources.begin(); @@ -1358,7 +1410,7 @@ bool cmQtAutoGenerators::GenerateQrcFiles() std::multimap<std::string, std::string> collisions; if (this->NameCollisionTest(qrcGenMap, collisions)) { std::ostringstream err; - err << "AUTOGEN: error: The same qrc_NAME.cpp file" + err << "AutoRcc: Error: The same qrc_NAME.cpp file" " will be generated from different sources." << std::endl << "To avoid this error rename the source .qrc files." << std::endl; @@ -1372,7 +1424,7 @@ bool cmQtAutoGenerators::GenerateQrcFiles() qrcGenMap.begin(); si != qrcGenMap.end(); ++si) { bool unique = FileNameIsUnique(si->first, qrcGenMap); - if (!this->GenerateQrc(si->first, si->second, unique)) { + if (!this->QrcGenerateFile(si->first, si->second, unique)) { if (this->RunRccFailed) { return false; } @@ -1384,9 +1436,9 @@ bool cmQtAutoGenerators::GenerateQrcFiles() /** * @return True if a rcc file was created. False may indicate an error. */ -bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, - const std::string& qrcOutputFile, - bool unique_n) +bool cmQtAutoGenerators::QrcGenerateFile(const std::string& qrcInputFile, + const std::string& qrcOutputFile, + bool unique_n) { std::string symbolName = cmsys::SystemTools::GetFilenameWithoutLastExtension(qrcInputFile); @@ -1400,14 +1452,23 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, const std::string qrcBuildFile = this->CurrentBinaryDir + qrcOutputFile; - int sourceNewerThanQrc = 0; - bool generateQrc = !cmsys::SystemTools::FileTimeCompare( - qrcInputFile, qrcBuildFile, &sourceNewerThanQrc); - generateQrc = generateQrc || (sourceNewerThanQrc >= 0); - generateQrc = - generateQrc || this->InputFilesNewerThanQrc(qrcInputFile, qrcBuildFile); - - if (this->GenerateAll || generateQrc) { + bool generateQrc = this->GenerateRccAll; + // Test if the resources list file is newer than build file + if (!generateQrc) { + generateQrc = FileAbsentOrOlder(qrcBuildFile, qrcInputFile); + } + // Test if any resource file is newer than the build file + if (!generateQrc) { + const std::vector<std::string>& files = this->RccInputs[qrcInputFile]; + for (std::vector<std::string>::const_iterator it = files.begin(); + it != files.end(); ++it) { + if (FileAbsentOrOlder(qrcBuildFile, *it)) { + generateQrc = true; + break; + } + } + } + if (generateQrc) { { std::string msg = "Generating RCC source "; msg += qrcOutputFile; @@ -1415,7 +1476,7 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, } // Make sure the parent directory exists - if (!this->makeParentDirectory(qrcOutputFile)) { + if (!this->MakeParentDirectory(qrcOutputFile)) { this->RunRccFailed = true; return false; } @@ -1445,7 +1506,7 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, if (!result || retVal) { { std::ostringstream err; - err << "AUTORCC: error: rcc process for " << qrcOutputFile + err << "AutoRcc: Error: rcc process for " << qrcOutputFile << " failed:\n" << output << std::endl; this->LogError(err.str()); @@ -1459,36 +1520,6 @@ bool cmQtAutoGenerators::GenerateQrc(const std::string& qrcInputFile, return false; } -/** - * @brief Collects name collisions as output/input pairs - * @return True if there were collisions - */ -bool cmQtAutoGenerators::NameCollisionTest( - const std::map<std::string, std::string>& genFiles, - std::multimap<std::string, std::string>& collisions) -{ - typedef std::map<std::string, std::string>::const_iterator Iter; - typedef std::map<std::string, std::string>::value_type VType; - for (Iter ait = genFiles.begin(); ait != genFiles.end(); ++ait) { - bool first_match(true); - for (Iter bit = (++Iter(ait)); bit != genFiles.end(); ++bit) { - if (ait->second == bit->second) { - if (first_match) { - if (collisions.find(ait->second) != collisions.end()) { - // We already know of this collision from before - break; - } - collisions.insert(VType(ait->second, ait->first)); - first_match = false; - } - collisions.insert(VType(bit->second, bit->first)); - } - } - } - - return !collisions.empty(); -} - void cmQtAutoGenerators::LogErrorNameCollision( const std::string& message, const std::multimap<std::string, std::string>& collisions) @@ -1548,10 +1579,40 @@ void cmQtAutoGenerators::LogCommand(const std::vector<std::string>& command) } /** + * @brief Collects name collisions as output/input pairs + * @return True if there were collisions + */ +bool cmQtAutoGenerators::NameCollisionTest( + const std::map<std::string, std::string>& genFiles, + std::multimap<std::string, std::string>& collisions) +{ + typedef std::map<std::string, std::string>::const_iterator Iter; + typedef std::map<std::string, std::string>::value_type VType; + for (Iter ait = genFiles.begin(); ait != genFiles.end(); ++ait) { + bool first_match(true); + for (Iter bit = (++Iter(ait)); bit != genFiles.end(); ++bit) { + if (ait->second == bit->second) { + if (first_match) { + if (collisions.find(ait->second) != collisions.end()) { + // We already know of this collision from before + break; + } + collisions.insert(VType(ait->second, ait->first)); + first_match = false; + } + collisions.insert(VType(bit->second, bit->first)); + } + } + } + + return !collisions.empty(); +} + +/** * @brief Generates the parent directory of the given file on demand * @return True on success */ -bool cmQtAutoGenerators::makeParentDirectory(const std::string& filename) +bool cmQtAutoGenerators::MakeParentDirectory(const std::string& filename) { bool success = true; const std::string dirName = cmSystemTools::GetFilenamePath(filename); @@ -1559,28 +1620,9 @@ bool cmQtAutoGenerators::makeParentDirectory(const std::string& filename) success = cmsys::SystemTools::MakeDirectory(dirName); if (!success) { std::ostringstream err; - err << "AUTOGEN: Directory creation failed: " << dirName << std::endl; + err << "AutoGen: Directory creation failed: " << dirName << std::endl; this->LogError(err.str()); } } return success; } - -std::string cmQtAutoGenerators::JoinExts(const std::vector<std::string>& lst) -{ - if (lst.empty()) { - return ""; - } - - std::string result; - std::string separator = ","; - for (std::vector<std::string>::const_iterator it = lst.begin(); - it != lst.end(); ++it) { - if (it != lst.begin()) { - result += separator; - } - result += '.' + (*it); - } - result.erase(result.end() - 1); - return result; -} diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index c241579..7891eb9 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -5,6 +5,7 @@ #include <cmConfigure.h> // IWYU pragma: keep #include <cmFilePathChecksum.h> +#include <cmsys/RegularExpression.hxx> #include <list> #include <map> @@ -21,67 +22,78 @@ public: bool Run(const std::string& targetDirectory, const std::string& config); private: + // - Configuration bool ReadAutogenInfoFile(cmMakefile* makefile, const std::string& targetDirectory, const std::string& config); - void ReadOldMocDefinitionsFile(cmMakefile* makefile, - const std::string& targetDirectory); - bool WriteOldMocDefinitionsFile(const std::string& targetDirectory); - std::string MakeCompileSettingsString(cmMakefile* makefile); + std::string MocSettingsStringCompose(); + std::string UicSettingsStringCompose(); + std::string RccSettingsStringCompose(); + void OldSettingsReadFile(cmMakefile* makefile, + const std::string& targetDirectory); + bool OldSettingsWriteFile(const std::string& targetDirectory); + // - Init and run + void Init(); bool RunAutogen(cmMakefile* makefile); - bool GenerateMocFiles( - const std::map<std::string, std::string>& includedMocs, - const std::map<std::string, std::string>& notIncludedMocs); - bool GenerateMoc(const std::string& sourceFile, - const std::string& mocFileName, - const std::string& subDirPrefix); + // - Content analysis + bool MocRequired(const std::string& text, std::string& macroName); + bool MocSkipTest(const std::string& absFilename); + bool UicSkipTest(const std::string& absFilename); - bool GenerateUiFiles( - const std::map<std::string, std::vector<std::string> >& includedUis); - bool GenerateUi(const std::string& realName, const std::string& uiInputFile, - const std::string& uiOutputFile); - - bool GenerateQrcFiles(); - bool GenerateQrc(const std::string& qrcInputFile, - const std::string& qrcOutputFile, bool unique_n); - - bool ParseCppFile( + bool ParseSourceFile( const std::string& absFilename, const std::vector<std::string>& headerExtensions, std::map<std::string, std::string>& includedMocs, - std::map<std::string, std::vector<std::string> >& includedUis); - bool StrictParseCppFile( - const std::string& absFilename, - const std::vector<std::string>& headerExtensions, - std::map<std::string, std::string>& includedMocs, - std::map<std::string, std::vector<std::string> >& includedUis); - void SearchHeadersForCppFile( + std::map<std::string, std::vector<std::string> >& includedUis, + bool relaxed); + + void SearchHeadersForSourceFile( const std::string& absFilename, const std::vector<std::string>& headerExtensions, - std::set<std::string>& absHeaders); + std::set<std::string>& absHeadersMoc, + std::set<std::string>& absHeadersUic); void ParseHeaders( - const std::set<std::string>& absHeaders, + const std::set<std::string>& absHeadersMoc, + const std::set<std::string>& absHeadersUic, const std::map<std::string, std::string>& includedMocs, std::map<std::string, std::string>& notIncludedMocs, std::map<std::string, std::vector<std::string> >& includedUis); - void ParseForUic( + void ParseContentForUic( const std::string& fileName, const std::string& contentsString, std::map<std::string, std::vector<std::string> >& includedUis); - void ParseForUic( - const std::string& fileName, - std::map<std::string, std::vector<std::string> >& includedUis); + bool ParseContentForMoc(const std::string& absFilename, + const std::string& contentsString, + const std::vector<std::string>& headerExtensions, + std::map<std::string, std::string>& includedMocs, + bool relaxed); - void Init(); + // - Moc file generation + bool MocGenerateAll( + const std::map<std::string, std::string>& includedMocs, + const std::map<std::string, std::string>& notIncludedMocs); + bool MocGenerateFile(const std::string& sourceFile, + const std::string& mocFileName, + const std::string& subDirPrefix); - bool NameCollisionTest(const std::map<std::string, std::string>& genFiles, - std::multimap<std::string, std::string>& collisions); + // - Uic file generation + bool UicGenerateAll( + const std::map<std::string, std::vector<std::string> >& includedUis); + bool UicGenerateFile(const std::string& realName, + const std::string& uiInputFile, + const std::string& uiOutputFile); + + // - Qrc file generation + bool QrcGenerateAll(); + bool QrcGenerateFile(const std::string& qrcInputFile, + const std::string& qrcOutputFile, bool unique_n); + // - Logging void LogErrorNameCollision( const std::string& message, const std::multimap<std::string, std::string>& collisions); @@ -91,16 +103,10 @@ private: void LogError(const std::string& message); void LogCommand(const std::vector<std::string>& command); - bool makeParentDirectory(const std::string& filename); - - std::string JoinExts(const std::vector<std::string>& lst); - - static void MergeUicOptions(std::vector<std::string>& opts, - const std::vector<std::string>& fileOpts, - bool isQt5); - - bool InputFilesNewerThanQrc(const std::string& qrcFile, - const std::string& rccOutput); + // - Utility + bool NameCollisionTest(const std::map<std::string, std::string>& genFiles, + std::multimap<std::string, std::string>& collisions); + bool MakeParentDirectory(const std::string& filename); // - Target names std::string OriginTargetName; @@ -117,10 +123,10 @@ private: std::string UicExecutable; std::string RccExecutable; // - File lists - std::string Sources; - std::string Headers; + std::vector<std::string> Sources; + std::vector<std::string> Headers; // - Moc - std::string SkipMoc; + std::vector<std::string> SkipMoc; std::string MocCompileDefinitionsStr; std::string MocIncludesStr; std::string MocOptionsStr; @@ -129,19 +135,23 @@ private: std::list<std::string> MocIncludes; std::list<std::string> MocDefinitions; std::vector<std::string> MocOptions; + std::string MocSettingsString; // - Uic - std::string SkipUic; + std::vector<std::string> SkipUic; std::vector<std::string> UicTargetOptions; std::map<std::string, std::string> UicOptions; + std::string UicSettingsString; // - Rcc std::vector<std::string> RccSources; std::map<std::string, std::string> RccOptions; std::map<std::string, std::vector<std::string> > RccInputs; - // - Settings - std::string CurrentCompileSettingsStr; - std::string OldCompileSettingsStr; + std::string RccSettingsString; // - Utility cmFilePathChecksum fpathCheckSum; + cmsys::RegularExpression RegExpQObject; + cmsys::RegularExpression RegExpQGadget; + cmsys::RegularExpression RegExpMocInclude; + cmsys::RegularExpression RegExpUicInclude; // - Flags bool IncludeProjectDirsBefore; bool Verbose; @@ -149,7 +159,9 @@ private: bool RunMocFailed; bool RunUicFailed; bool RunRccFailed; - bool GenerateAll; + bool GenerateMocAll; + bool GenerateUicAll; + bool GenerateRccAll; bool MocRelaxedMode; }; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index f47cb33..334a05a 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -731,12 +731,16 @@ static Json::Value DumpTarget(cmGeneratorTarget* target, Json::Value result = Json::objectValue; result[kNAME_KEY] = target->GetName(); - result[kTYPE_KEY] = typeName; - result[kFULL_NAME_KEY] = target->GetFullName(config); result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory(); result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory(); + if (type == cmStateEnums::INTERFACE_LIBRARY) { + return result; + } + + result[kFULL_NAME_KEY] = target->GetFullName(config); + if (target->HaveWellDefinedOutputFiles()) { Json::Value artifacts = Json::arrayValue; artifacts.append(target->GetFullPath(config, false)); @@ -997,6 +1001,8 @@ cmServerResponse cmServerProtocol1_0::ProcessConfigure( } } + cmSystemTools::ResetErrorOccuredFlag(); // Reset error state + if (cm->AddCMakePaths() != 1) { return request.ReportError("Failed to set CMake paths."); } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index ee4ff39..9261ca8 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -858,6 +858,12 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); return; } + if (prop == "TYPE") { + std::ostringstream e; + e << "TYPE property is read-only\n"; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + return; + } if (prop == "EXPORT_NAME" && this->IsImported()) { std::ostringstream e; e << "EXPORT_NAME property can't be set on imported targets (\"" diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx new file mode 100644 index 0000000..c2ff664 --- /dev/null +++ b/Source/cmVSSetupHelper.cxx @@ -0,0 +1,366 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmVSSetupHelper.h" + +#ifndef VSSetupConstants +#define VSSetupConstants +/* clang-format off */ +const IID IID_ISetupConfiguration = { + 0x42843719, 0xDB4C, 0x46C2, + { 0x8E, 0x7C, 0x64, 0xF1, 0x81, 0x6E, 0xFD, 0x5B } +}; +const IID IID_ISetupConfiguration2 = { + 0x26AAB78C, 0x4A60, 0x49D6, + { 0xAF, 0x3B, 0x3C, 0x35, 0xBC, 0x93, 0x36, 0x5D } +}; +const IID IID_ISetupPackageReference = { + 0xda8d8a16, 0xb2b6, 0x4487, + { 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5 } +}; +const IID IID_ISetupHelper = { + 0x42b21b78, 0x6192, 0x463e, + { 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c } +}; +const IID IID_IEnumSetupInstances = { + 0x6380BCFF, 0x41D3, 0x4B2E, + { 0x8B, 0x2E, 0xBF, 0x8A, 0x68, 0x10, 0xC8, 0x48 } +}; +const IID IID_ISetupInstance2 = { + 0x89143C9A, 0x05AF, 0x49B0, + { 0xB7, 0x17, 0x72, 0xE2, 0x18, 0xA2, 0x18, 0x5C } +}; +const IID IID_ISetupInstance = { + 0xB41463C3, 0x8866, 0x43B5, + { 0xBC, 0x33, 0x2B, 0x06, 0x76, 0xF7, 0xF4, 0x2E } +}; +const CLSID CLSID_SetupConfiguration = { + 0x177F0C4A, 0x1CD3, 0x4DE7, + { 0xA3, 0x2C, 0x71, 0xDB, 0xBB, 0x9F, 0xA3, 0x6D } +}; +/* clang-format on */ +#endif + +const WCHAR* VCToolsetComponent = + L"Microsoft.VisualStudio.Component.VC.Tools.x86.x64"; +const WCHAR* Win10SDKComponent = + L"Microsoft.VisualStudio.Component.Windows10SDK"; +const WCHAR* Win81SDKComponent = + L"Microsoft.VisualStudio.Component.Windows81SDK"; +const WCHAR* ComponentType = L"Component"; + +cmVSSetupAPIHelper::cmVSSetupAPIHelper() + : setupConfig(NULL) + , setupConfig2(NULL) + , setupHelper(NULL) + , initializationFailure(false) +{ + comInitialized = CoInitializeEx(NULL, 0); + if (SUCCEEDED(comInitialized)) { + Initialize(); + } else { + initializationFailure = true; + } +} + +cmVSSetupAPIHelper::~cmVSSetupAPIHelper() +{ + setupHelper = NULL; + setupConfig2 = NULL; + setupConfig = NULL; + if (SUCCEEDED(comInitialized)) + CoUninitialize(); +} + +bool cmVSSetupAPIHelper::IsVS2017Installed() +{ + return this->EnumerateAndChooseVSInstance(); +} + +bool cmVSSetupAPIHelper::IsWin10SDKInstalled() +{ + return (this->EnumerateAndChooseVSInstance() && + chosenInstanceInfo.IsWin10SDKInstalled); +} + +bool cmVSSetupAPIHelper::IsWin81SDKInstalled() +{ + return (this->EnumerateAndChooseVSInstance() && + chosenInstanceInfo.IsWin81SDKInstalled); +} + +bool cmVSSetupAPIHelper::CheckInstalledComponent( + SmartCOMPtr<ISetupPackageReference> package, bool& bVCToolset, + bool& bWin10SDK, bool& bWin81SDK) +{ + bool ret = false; + bVCToolset = bWin10SDK = bWin81SDK = false; + SmartBSTR bstrId; + if (FAILED(package->GetId(&bstrId))) { + return ret; + } + + SmartBSTR bstrType; + if (FAILED(package->GetType(&bstrType))) { + return ret; + } + + std::wstring id = std::wstring(bstrId); + std::wstring type = std::wstring(bstrType); + if (id.compare(VCToolsetComponent) == 0 && + type.compare(ComponentType) == 0) { + bVCToolset = true; + ret = true; + } + + // Checks for any version of Win10 SDK. The version is appended at the end of + // the + // component name ex: Microsoft.VisualStudio.Component.Windows10SDK.10240 + if (id.find(Win10SDKComponent) != std::wstring::npos && + type.compare(ComponentType) == 0) { + bWin10SDK = true; + ret = true; + } + + if (id.compare(Win81SDKComponent) == 0 && type.compare(ComponentType) == 0) { + bWin81SDK = true; + ret = true; + } + + return ret; +} + +// Gather additional info such as if VCToolset, WinSDKs are installed, location +// of VS and version information. +bool cmVSSetupAPIHelper::GetVSInstanceInfo( + SmartCOMPtr<ISetupInstance2> pInstance, VSInstanceInfo& vsInstanceInfo) +{ + bool isVCToolSetInstalled = false; + if (pInstance == NULL) + return false; + + SmartBSTR bstrId; + if (SUCCEEDED(pInstance->GetInstanceId(&bstrId))) { + vsInstanceInfo.InstanceId = std::wstring(bstrId); + } else { + return false; + } + + InstanceState state; + if (FAILED(pInstance->GetState(&state))) { + return false; + } + + ULONGLONG ullVersion = 0; + SmartBSTR bstrVersion; + if (FAILED(pInstance->GetInstallationVersion(&bstrVersion))) { + return false; + } else { + vsInstanceInfo.Version = std::wstring(bstrVersion); + if (FAILED(setupHelper->ParseVersion(bstrVersion, &ullVersion))) { + vsInstanceInfo.ullVersion = 0; + } else { + vsInstanceInfo.ullVersion = ullVersion; + } + } + + // Reboot may have been required before the installation path was created. + SmartBSTR bstrInstallationPath; + if ((eLocal & state) == eLocal) { + if (FAILED(pInstance->GetInstallationPath(&bstrInstallationPath))) { + return false; + } else { + vsInstanceInfo.VSInstallLocation = std::wstring(bstrInstallationPath); + } + } + + // Reboot may have been required before the product package was registered + // (last). + if ((eRegistered & state) == eRegistered) { + SmartCOMPtr<ISetupPackageReference> product; + if (FAILED(pInstance->GetProduct(&product)) || !product) { + return false; + } + + LPSAFEARRAY lpsaPackages; + if (FAILED(pInstance->GetPackages(&lpsaPackages)) || + lpsaPackages == NULL) { + return false; + } + + int lower = lpsaPackages->rgsabound[0].lLbound; + int upper = lpsaPackages->rgsabound[0].cElements + lower; + + IUnknown** ppData = (IUnknown**)lpsaPackages->pvData; + for (int i = lower; i < upper; i++) { + SmartCOMPtr<ISetupPackageReference> package = NULL; + if (FAILED(ppData[i]->QueryInterface(IID_ISetupPackageReference, + (void**)&package)) || + package == NULL) + continue; + + bool vcToolsetInstalled = false, win10SDKInstalled = false, + win81SDkInstalled = false; + bool ret = CheckInstalledComponent(package, vcToolsetInstalled, + win10SDKInstalled, win81SDkInstalled); + if (ret) { + isVCToolSetInstalled |= vcToolsetInstalled; + vsInstanceInfo.IsWin10SDKInstalled |= win10SDKInstalled; + vsInstanceInfo.IsWin81SDKInstalled |= win81SDkInstalled; + } + } + + SafeArrayDestroy(lpsaPackages); + } + + return isVCToolSetInstalled; +} + +bool cmVSSetupAPIHelper::GetVSInstanceInfo(std::string& vsInstallLocation) +{ + vsInstallLocation = ""; + bool isInstalled = this->EnumerateAndChooseVSInstance(); + + if (isInstalled) { + std::string str(chosenInstanceInfo.VSInstallLocation.begin(), + chosenInstanceInfo.VSInstallLocation.end()); + vsInstallLocation = str; + } + + return isInstalled; +} + +bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() +{ + bool isVSInstanceExists = false; + if (chosenInstanceInfo.VSInstallLocation.compare(L"") != 0) { + return true; + } + + if (initializationFailure || setupConfig == NULL || setupConfig2 == NULL || + setupHelper == NULL) + return false; + + std::vector<VSInstanceInfo> vecVSInstances; + SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL; + if (FAILED( + setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) || + !enumInstances) { + return false; + } + + SmartCOMPtr<ISetupInstance> instance; + while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) { + SmartCOMPtr<ISetupInstance2> instance2 = NULL; + if (FAILED( + instance->QueryInterface(IID_ISetupInstance2, (void**)&instance2)) || + !instance2) { + instance = NULL; + continue; + } + + VSInstanceInfo instanceInfo; + bool isInstalled = GetVSInstanceInfo(instance2, instanceInfo); + instance = instance2 = NULL; + + if (isInstalled) { + vecVSInstances.push_back(instanceInfo); + } + } + + if (vecVSInstances.size() > 0) { + isVSInstanceExists = true; + int index = ChooseVSInstance(vecVSInstances); + chosenInstanceInfo = vecVSInstances[index]; + } + + return isVSInstanceExists; +} + +int cmVSSetupAPIHelper::ChooseVSInstance( + const std::vector<VSInstanceInfo>& vecVSInstances) +{ + if (vecVSInstances.size() == 0) + return -1; + + if (vecVSInstances.size() == 1) + return 0; + + unsigned int chosenIndex = 0; + for (unsigned int i = 1; i < vecVSInstances.size(); i++) { + // If the current has Win10 SDK but not the chosen one, then choose the + // current VS instance + if (!vecVSInstances[chosenIndex].IsWin10SDKInstalled && + vecVSInstances[i].IsWin10SDKInstalled) { + chosenIndex = i; + continue; + } + + // If the chosen one has Win10 SDK but the current one is not, then look at + // the next VS instance even the current + // instance version may be higher + if (vecVSInstances[chosenIndex].IsWin10SDKInstalled && + !vecVSInstances[i].IsWin10SDKInstalled) { + continue; + } + + // If both chosen one and current one doesn't have Win10 SDK but the + // current one has Win8.1 SDK installed, + // then choose the current one + if (!vecVSInstances[chosenIndex].IsWin10SDKInstalled && + !vecVSInstances[i].IsWin10SDKInstalled && + !vecVSInstances[chosenIndex].IsWin81SDKInstalled && + vecVSInstances[i].IsWin81SDKInstalled) { + chosenIndex = i; + continue; + } + + // If there is no difference in WinSDKs then look for the highest version + // of installed VS + if ((vecVSInstances[chosenIndex].IsWin10SDKInstalled == + vecVSInstances[i].IsWin10SDKInstalled) && + (vecVSInstances[chosenIndex].IsWin81SDKInstalled == + vecVSInstances[i].IsWin81SDKInstalled) && + vecVSInstances[chosenIndex].Version < vecVSInstances[i].Version) { + chosenIndex = i; + continue; + } + } + + return chosenIndex; +} + +bool cmVSSetupAPIHelper::Initialize() +{ + if (initializationFailure) + return false; + + if (FAILED(comInitialized)) { + initializationFailure = true; + return false; + } + + if (FAILED(setupConfig.CoCreateInstance(CLSID_SetupConfiguration, NULL, + IID_ISetupConfiguration, + CLSCTX_INPROC_SERVER)) || + setupConfig == NULL) { + initializationFailure = true; + return false; + } + + if (FAILED(setupConfig.QueryInterface(IID_ISetupConfiguration2, + (void**)&setupConfig2)) || + setupConfig2 == NULL) { + initializationFailure = true; + return false; + } + + if (FAILED( + setupConfig.QueryInterface(IID_ISetupHelper, (void**)&setupHelper)) || + setupHelper == NULL) { + initializationFailure = true; + return false; + } + + initializationFailure = false; + return true; +} diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h new file mode 100644 index 0000000..d2f514c --- /dev/null +++ b/Source/cmVSSetupHelper.h @@ -0,0 +1,154 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmVSSetupHelper_h +#define cmVSSetupHelper_h + +#ifndef NOMINMAX +#define NOMINMAX // Undefine min and max defined by windows.h +#endif + +// Published by Visual Studio Setup team +#include "cmvssetup/Setup.Configuration.h" + +#include <string> +#include <vector> + +#include <windows.h> + +template <class T> +class SmartCOMPtr +{ +public: + SmartCOMPtr() { ptr = NULL; } + SmartCOMPtr(T* p) + { + ptr = p; + if (ptr != NULL) + ptr->AddRef(); + } + SmartCOMPtr(const SmartCOMPtr<T>& sptr) + { + ptr = sptr.ptr; + if (ptr != NULL) + ptr->AddRef(); + } + T** operator&() { return &ptr; } + T* operator->() { return ptr; } + T* operator=(T* p) + { + if (*this != p) { + ptr = p; + if (ptr != NULL) + ptr->AddRef(); + } + return *this; + } + operator T*() const { return ptr; } + template <class I> + HRESULT QueryInterface(REFCLSID rclsid, I** pp) + { + if (pp != NULL) { + return ptr->QueryInterface(rclsid, (void**)pp); + } else { + return E_FAIL; + } + } + HRESULT CoCreateInstance(REFCLSID clsid, IUnknown* pUnknown, + REFIID interfaceId, DWORD dwClsContext = CLSCTX_ALL) + { + HRESULT hr = ::CoCreateInstance(clsid, pUnknown, dwClsContext, interfaceId, + (void**)&ptr); + return hr; + } + ~SmartCOMPtr() + { + if (ptr != NULL) + ptr->Release(); + } + +private: + T* ptr; +}; + +class SmartBSTR +{ +public: + SmartBSTR() { str = NULL; } + SmartBSTR(const SmartBSTR& src) + { + if (src.str != NULL) { + str = ::SysAllocStringByteLen((char*)str, ::SysStringByteLen(str)); + } else { + str = ::SysAllocStringByteLen(NULL, 0); + } + } + SmartBSTR& operator=(const SmartBSTR& src) + { + if (str != src.str) { + ::SysFreeString(str); + if (src.str != NULL) { + str = ::SysAllocStringByteLen((char*)str, ::SysStringByteLen(str)); + } else { + str = ::SysAllocStringByteLen(NULL, 0); + } + } + return *this; + } + operator BSTR() const { return str; } + BSTR* operator&() throw() { return &str; } + ~SmartBSTR() throw() { ::SysFreeString(str); } +private: + BSTR str; +}; + +struct VSInstanceInfo +{ + std::wstring InstanceId; + std::wstring VSInstallLocation; + std::wstring Version; + ULONGLONG ullVersion; + bool IsWin10SDKInstalled; + bool IsWin81SDKInstalled; + + VSInstanceInfo() + { + InstanceId = VSInstallLocation = Version = L""; + ullVersion = 0; + IsWin10SDKInstalled = IsWin81SDKInstalled = false; + } +}; + +class cmVSSetupAPIHelper +{ +public: + cmVSSetupAPIHelper(); + ~cmVSSetupAPIHelper(); + + bool IsVS2017Installed(); + bool GetVSInstanceInfo(std::string& vsInstallLocation); + bool IsWin10SDKInstalled(); + bool IsWin81SDKInstalled(); + +private: + bool Initialize(); + bool GetVSInstanceInfo(SmartCOMPtr<ISetupInstance2> instance2, + VSInstanceInfo& vsInstanceInfo); + bool CheckInstalledComponent(SmartCOMPtr<ISetupPackageReference> package, + bool& bVCToolset, bool& bWin10SDK, + bool& bWin81SDK); + int ChooseVSInstance(const std::vector<VSInstanceInfo>& vecVSInstances); + bool EnumerateAndChooseVSInstance(); + + // COM ptrs to query about VS instances + SmartCOMPtr<ISetupConfiguration> setupConfig; + SmartCOMPtr<ISetupConfiguration2> setupConfig2; + SmartCOMPtr<ISetupHelper> setupHelper; + // used to indicate failure in Initialize(), so we don't have to call again + bool initializationFailure; + // indicated if COM initialization is successful + HRESULT comInitialized; + // current best instance of VS selected + VSInstanceInfo chosenInstanceInfo; +}; + +#endif diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 49274c0..89380eb 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -130,9 +130,18 @@ void cmVisualStudio10TargetGenerator::WritePlatformConfigTag( } stream->fill(' '); stream->width(indentLevel * 2); - (*stream) << ""; - (*stream) << "<" << tag << " Condition=\"'$(Configuration)|$(Platform)'=='"; - (*stream) << config << "|" << this->Platform << "'\""; + (*stream) << "<" << tag << " Condition=\""; + (*stream) << "'$(Configuration)|$(Platform)'=='"; + (*stream) << config << "|" << this->Platform; + (*stream) << "'"; + // handle special case for 32 bit C# targets + if (csproj == this->ProjectType && this->Platform == "Win32") { + (*stream) << " Or "; + (*stream) << "'$(Configuration)|$(Platform)'=='"; + (*stream) << config << "|x86"; + (*stream) << "'"; + } + (*stream) << "\""; if (attribute) { (*stream) << attribute; } @@ -159,6 +168,14 @@ void cmVisualStudio10TargetGenerator::WriteString(const char* line, "$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" #define VS10_CXX_TARGETS "$(VCTargetsPath)\\Microsoft.Cpp.targets" +#define VS10_CSharp_DEFAULT_PROPS \ + "$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props" +// This does not seem to exist by default, it's just provided for consistency +// in case users want to have default custom props for C# targets +#define VS10_CSharp_USER_PROPS \ + "$(UserRootDir)\\Microsoft.CSharp.$(Platform).user.props" +#define VS10_CSharp_TARGETS "$(MSBuildToolsPath)\\Microsoft.CSharp.targets" + void cmVisualStudio10TargetGenerator::Generate() { // do not generate external ms projects @@ -257,7 +274,9 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteString("</PropertyGroup>\n", 1); } - this->WriteProjectConfigurations(); + if (csproj != this->ProjectType) { + this->WriteProjectConfigurations(); + } this->WriteString("<PropertyGroup Label=\"Globals\">\n", 1); this->WriteString("<ProjectGUID>", 2); (*this->BuildFileStream) << "{" << this->GUID << "}</ProjectGUID>\n"; @@ -271,9 +290,14 @@ void cmVisualStudio10TargetGenerator::Generate() const char* vsProjectTypes = this->GeneratorTarget->GetProperty("VS_GLOBAL_PROJECT_TYPES"); if (vsProjectTypes) { - this->WriteString("<ProjectTypes>", 2); - (*this->BuildFileStream) << cmVS10EscapeXML(vsProjectTypes) - << "</ProjectTypes>\n"; + std::string tagName = "ProjectTypes"; + if (csproj == this->ProjectType) { + tagName = "ProjectTypeGuids"; + } + this->WriteString("", 2); + (*this->BuildFileStream) << "<" << tagName << ">" + << cmVS10EscapeXML(vsProjectTypes) << "</" + << tagName << ">\n"; } const char* vsProjectName = @@ -371,10 +395,59 @@ void cmVisualStudio10TargetGenerator::Generate() << "</" << globalKey << ">\n"; } + if (this->Managed) { + std::string outputType = "<OutputType>"; + switch (this->GeneratorTarget->GetType()) { + case cmStateEnums::OBJECT_LIBRARY: + case cmStateEnums::STATIC_LIBRARY: + case cmStateEnums::SHARED_LIBRARY: + outputType += "Library"; + break; + case cmStateEnums::MODULE_LIBRARY: + outputType += "Module"; + break; + case cmStateEnums::EXECUTABLE: + if (this->GeneratorTarget->Target->GetPropertyAsBool( + "WIN32_EXECUTABLE")) { + outputType += "WinExe"; + } else { + outputType += "Exe"; + } + break; + case cmStateEnums::UTILITY: + case cmStateEnums::GLOBAL_TARGET: + outputType += "Utility"; + break; + case cmStateEnums::UNKNOWN_LIBRARY: + case cmStateEnums::INTERFACE_LIBRARY: + break; + } + outputType += "</OutputType>\n"; + this->WriteString(outputType.c_str(), 2); + this->WriteString("<AppDesignerFolder>Properties</AppDesignerFolder>\n", + 2); + } + this->WriteString("</PropertyGroup>\n", 1); - this->WriteString("<Import Project=\"" VS10_CXX_DEFAULT_PROPS "\" />\n", 1); + + switch (this->ProjectType) { + case vcxproj: + this->WriteString("<Import Project=\"" VS10_CXX_DEFAULT_PROPS "\" />\n", + 1); + break; + case csproj: + this->WriteString("<Import Project=\"" VS10_CSharp_DEFAULT_PROPS "\" " + "Condition=\"Exists('" VS10_CSharp_DEFAULT_PROPS "')\"" + "/>\n", + 1); + break; + } + this->WriteProjectConfigurationValues(); - this->WriteString("<Import Project=\"" VS10_CXX_PROPS "\" />\n", 1); + + if (vcxproj == this->ProjectType) { + this->WriteString("<Import Project=\"" VS10_CXX_PROPS "\" />\n", 1); + } this->WriteString("<ImportGroup Label=\"ExtensionSettings\">\n", 1); if (this->GlobalGenerator->IsMasmEnabled()) { this->WriteString("<Import Project=\"$(VCTargetsPath)\\" @@ -384,17 +457,26 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteString("</ImportGroup>\n", 1); this->WriteString("<ImportGroup Label=\"PropertySheets\">\n", 1); { - std::string props = VS10_CXX_USER_PROPS; - if (const char* p = - this->GeneratorTarget->GetProperty("VS_USER_PROPS_CXX")) { + std::string props; + switch (this->ProjectType) { + case vcxproj: + props = VS10_CXX_USER_PROPS; + break; + case csproj: + props = VS10_CSharp_USER_PROPS; + break; + } + if (const char* p = this->GeneratorTarget->GetProperty("VS_USER_PROPS")) { props = p; + } + if (!props.empty()) { this->ConvertToWindowsSlash(props); + this->WriteString("", 2); + (*this->BuildFileStream) + << "<Import Project=\"" << cmVS10EscapeXML(props) << "\"" + << " Condition=\"exists('" << cmVS10EscapeXML(props) << "')\"" + << " Label=\"LocalAppDataPlatform\" />\n"; } - this->WriteString("", 2); - (*this->BuildFileStream) - << "<Import Project=\"" << cmVS10EscapeXML(props) << "\"" - << " Condition=\"exists('" << cmVS10EscapeXML(props) << "')\"" - << " Label=\"LocalAppDataPlatform\" />\n"; } this->WritePlatformExtensions(); this->WriteString("</ImportGroup>\n", 1); @@ -410,7 +492,14 @@ void cmVisualStudio10TargetGenerator::Generate() this->WriteWinRTReferences(); this->WriteProjectReferences(); this->WriteSDKReferences(); - this->WriteString("<Import Project=\"" VS10_CXX_TARGETS "\" />\n", 1); + switch (this->ProjectType) { + case vcxproj: + this->WriteString("<Import Project=\"" VS10_CXX_TARGETS "\" />\n", 1); + break; + case csproj: + this->WriteString("<Import Project=\"" VS10_CSharp_TARGETS "\" />\n", 1); + break; + } this->WriteTargetSpecificReferences(); this->WriteString("<ImportGroup Label=\"ExtensionTargets\">\n", 1); @@ -421,6 +510,17 @@ void cmVisualStudio10TargetGenerator::Generate() 2); } this->WriteString("</ImportGroup>\n", 1); + if (csproj == this->ProjectType) { + for (std::vector<std::string>::const_iterator i = + this->Configurations.begin(); + i != this->Configurations.end(); ++i) { + this->WriteString("<PropertyGroup Condition=\"'$(Configuration)' == '", + 1); + (*this->BuildFileStream) << *i << "'\">\n"; + this->WriteEvents(*i); + this->WriteString("</PropertyGroup>\n", 1); + } + } this->WriteString("</Project>", 0); // The groups are stored in a separate file for VS 10 this->WriteGroups(); @@ -661,48 +761,55 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() i != this->Configurations.end(); ++i) { this->WritePlatformConfigTag("PropertyGroup", i->c_str(), 1, " Label=\"Configuration\"", "\n"); - std::string configType = "<ConfigurationType>"; - if (const char* vsConfigurationType = - this->GeneratorTarget->GetProperty("VS_CONFIGURATION_TYPE")) { - configType += cmVS10EscapeXML(vsConfigurationType); - } else { - switch (this->GeneratorTarget->GetType()) { - case cmStateEnums::SHARED_LIBRARY: - case cmStateEnums::MODULE_LIBRARY: - configType += "DynamicLibrary"; - break; - case cmStateEnums::OBJECT_LIBRARY: - case cmStateEnums::STATIC_LIBRARY: - configType += "StaticLibrary"; - break; - case cmStateEnums::EXECUTABLE: - if (this->NsightTegra && - !this->GeneratorTarget->GetPropertyAsBool("ANDROID_GUI")) { - // Android executables are .so too. + + if (csproj != this->ProjectType) { + std::string configType = "<ConfigurationType>"; + if (const char* vsConfigurationType = + this->GeneratorTarget->GetProperty("VS_CONFIGURATION_TYPE")) { + configType += cmVS10EscapeXML(vsConfigurationType); + } else { + switch (this->GeneratorTarget->GetType()) { + case cmStateEnums::SHARED_LIBRARY: + case cmStateEnums::MODULE_LIBRARY: configType += "DynamicLibrary"; - } else { - configType += "Application"; - } - break; - case cmStateEnums::UTILITY: - case cmStateEnums::GLOBAL_TARGET: - if (this->NsightTegra) { - // Tegra-Android platform does not understand "Utility". + break; + case cmStateEnums::OBJECT_LIBRARY: + case cmStateEnums::STATIC_LIBRARY: configType += "StaticLibrary"; - } else { - configType += "Utility"; - } - break; - case cmStateEnums::UNKNOWN_LIBRARY: - case cmStateEnums::INTERFACE_LIBRARY: - break; + break; + case cmStateEnums::EXECUTABLE: + if (this->NsightTegra && + !this->GeneratorTarget->GetPropertyAsBool("ANDROID_GUI")) { + // Android executables are .so too. + configType += "DynamicLibrary"; + } else { + configType += "Application"; + } + break; + case cmStateEnums::UTILITY: + case cmStateEnums::GLOBAL_TARGET: + if (this->NsightTegra) { + // Tegra-Android platform does not understand "Utility". + configType += "StaticLibrary"; + } else { + configType += "Utility"; + } + break; + case cmStateEnums::UNKNOWN_LIBRARY: + case cmStateEnums::INTERFACE_LIBRARY: + break; + } } + configType += "</ConfigurationType>\n"; + this->WriteString(configType.c_str(), 2); } - configType += "</ConfigurationType>\n"; - this->WriteString(configType.c_str(), 2); if (this->MSTools) { - this->WriteMSToolConfigurationValues(*i); + if (!this->Managed) { + this->WriteMSToolConfigurationValues(*i); + } else { + this->WriteMSToolConfigurationValuesManaged(*i); + } } else if (this->NsightTegra) { this->WriteNsightTegraConfigurationValues(*i); } @@ -761,6 +868,61 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( } } +void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( + std::string const& config) +{ + cmGlobalVisualStudio10Generator* gg = + static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); + + Options& o = *(this->ClOptions[config]); + + if (o.IsDebug()) { + this->WriteString("<DebugSymbols>true</DebugSymbols>\n", 2); + this->WriteString("<DefineDebug>true</DefineDebug>\n", 2); + } + + std::string outDir = + this->GeneratorTarget->GetDirectory(config.c_str()) + "/"; + this->ConvertToWindowsSlash(outDir); + this->WriteString("<OutputPath>", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(outDir) << "</OutputPath>\n"; + + if (o.HasFlag("Platform")) { + this->WriteString("<PlatformTarget>", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(o.GetFlag("Platform")) + << "</PlatformTarget>\n"; + o.RemoveFlag("Platform"); + } + + if (const char* toolset = gg->GetPlatformToolset()) { + this->WriteString("<PlatformToolset>", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(toolset) + << "</PlatformToolset>\n"; + } + + std::string postfixName = cmSystemTools::UpperCase(config); + postfixName += "_POSTFIX"; + std::string assemblyName = + this->GeneratorTarget->GetOutputName(config, false); + if (const char* postfix = this->GeneratorTarget->GetProperty(postfixName)) { + assemblyName += postfix; + } + this->WriteString("<AssemblyName>", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(assemblyName) + << "</AssemblyName>\n"; + + if (cmStateEnums::EXECUTABLE == this->GeneratorTarget->GetType()) { + this->WriteString("<StartAction>Program</StartAction>\n", 2); + this->WriteString("<StartProgram>", 2); + (*this->BuildFileStream) << cmVS10EscapeXML(outDir) + << cmVS10EscapeXML(assemblyName) + << ".exe</StartProgram>\n"; + } + + o.OutputFlagMap(*this->BuildFileStream, " "); +} + +//---------------------------------------------------------------------------- void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues( std::string const&) { @@ -924,6 +1086,10 @@ void cmVisualStudio10TargetGenerator::ConvertToWindowsSlash(std::string& s) } void cmVisualStudio10TargetGenerator::WriteGroups() { + if (csproj == this->ProjectType) { + return; + } + // collect up group information std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups(); std::vector<cmSourceFile*> classes; @@ -1182,7 +1348,33 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) std::string shaderEntryPoint; std::string shaderModel; std::string shaderAdditionalFlags; + std::string sourceLink; std::string ext = cmSystemTools::LowerCase(sf->GetExtension()); + if (csproj == this->ProjectType) { + // EVERY extra source file must have a <Link>, otherwise it might not + // be visible in Visual Studio at all. The path relative to current + // source- or binary-dir is used within the link, if the file is + // in none of these paths, it is added with the plain filename without + // any path. This means the file will show up at root-level of the csproj + // (where CMakeLists.txt etc. are). + if (!this->InSourceBuild) { + toolHasSettings = true; + std::string fullFileName = sf->GetFullPath(); + std::string srcDir = this->Makefile->GetCurrentSourceDirectory(); + std::string binDir = this->Makefile->GetCurrentBinaryDirectory(); + if (fullFileName.find(binDir) != std::string::npos) { + sourceLink = ""; + } else if (fullFileName.find(srcDir) != std::string::npos) { + sourceLink = fullFileName.substr(srcDir.length() + 1); + } else { + // fallback: add plain filename without any path + sourceLink = cmsys::SystemTools::GetFilenameName(fullFileName); + } + if (!sourceLink.empty()) { + this->ConvertToWindowsSlash(sourceLink); + } + } + } if (ext == "hlsl") { tool = "FXCompile"; // Figure out the type of shader compiler to use. @@ -1303,6 +1495,10 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource(cmSourceFile const* sf) (*this->BuildFileStream) << cmVS10EscapeXML(shaderAdditionalFlags) << "</AdditionalOptions>\n"; } + if (!sourceLink.empty()) { + this->WriteString("<Link>", 3); + (*this->BuildFileStream) << cmVS10EscapeXML(sourceLink) << "</Link>\n"; + } this->WriteString("</", 2); (*this->BuildFileStream) << tool << ">\n"; } else { @@ -1344,6 +1540,12 @@ void cmVisualStudio10TargetGenerator::WriteSource(std::string const& tool, this->GlobalGenerator->PathTooLong(this->GeneratorTarget, sf, sourceRel); } } + if (csproj == this->ProjectType && this->InSourceBuild) { + std::string srcdir = this->Makefile->GetCurrentSourceDirectory(); + if (sourceFile.find(srcdir) != std::string::npos) { + sourceFile = sourceFile.substr(srcdir.size() + 1); + } + } this->ConvertToWindowsSlash(sourceFile); this->WriteString("<", 2); (*this->BuildFileStream) << tool << " Include=\"" @@ -1394,6 +1596,8 @@ void cmVisualStudio10TargetGenerator::WriteAllSources() tool = "MASM"; } else if (lang == "RC") { tool = "ResourceCompile"; + } else if (lang == "CSharp") { + tool = "Compile"; } if (!tool.empty()) { @@ -1597,6 +1801,37 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( std::string xamlFileName = fileName.substr(0, fileName.find_last_of(".")); (*this->BuildFileStream) << xamlFileName << "</DependentUpon>\n"; } + if (csproj == this->ProjectType) { + std::string f = source->GetFullPath(); + typedef std::map<std::string, std::string> CsPropMap; + CsPropMap sourceFileTags; + // set <Link> tag if necessary + if (!this->InSourceBuild) { + const std::string stripFromPath = + this->Makefile->GetCurrentSourceDirectory(); + if (f.find(stripFromPath) != std::string::npos) { + std::string link = f.substr(stripFromPath.length() + 1); + this->ConvertToWindowsSlash(link); + sourceFileTags["Link"] = link; + } + } + // + // NOTE: in future commits additional props will be added! + // + // write source file specific tags + if (!sourceFileTags.empty()) { + hasFlags = true; + (*this->BuildFileStream) << firstString; + firstString = ""; + for (CsPropMap::const_iterator i = sourceFileTags.begin(); + i != sourceFileTags.end(); ++i) { + this->WriteString("<", 2); + (*this->BuildFileStream) + << i->first << ">" << cmVS10EscapeXML(i->second) << "</" << i->first + << ">\n"; + } + } + } return hasFlags; } @@ -1607,6 +1842,9 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions() if (ttype > cmStateEnums::GLOBAL_TARGET) { return; } + if (csproj == this->ProjectType) { + return; + } this->WriteString("<PropertyGroup>\n", 2); this->WriteString("<_ProjectFileVersion>10.0.20506.1" @@ -1681,6 +1919,9 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental( if (!this->MSTools) { return; } + if (csproj == this->ProjectType) { + return; + } // static libraries and things greater than modules do not need // to set this option if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY || @@ -1735,8 +1976,18 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( cmGlobalVisualStudio10Generator* gg = static_cast<cmGlobalVisualStudio10Generator*>(this->GlobalGenerator); - CM_AUTO_PTR<Options> pOptions(new Options( - this->LocalGenerator, Options::Compiler, gg->GetClFlagTable())); + CM_AUTO_PTR<Options> pOptions; + switch (this->ProjectType) { + case vcxproj: + pOptions = CM_AUTO_PTR<Options>(new Options( + this->LocalGenerator, Options::Compiler, gg->GetClFlagTable())); + break; + case csproj: + pOptions = CM_AUTO_PTR<Options>(new Options(this->LocalGenerator, + Options::CSharpCompiler, + gg->GetCSharpFlagTable())); + break; + } Options& clOptions = *pOptions; std::string flags; @@ -1749,7 +2000,7 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( return false; } if (linkLanguage == "C" || linkLanguage == "CXX" || - linkLanguage == "Fortran") { + linkLanguage == "Fortran" || linkLanguage == "CSharp") { std::string baseFlagVar = "CMAKE_"; baseFlagVar += linkLanguage; baseFlagVar += "_FLAGS"; @@ -1777,16 +2028,26 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( std::string defineFlags = this->GeneratorTarget->Target->GetMakefile()->GetDefineFlags(); if (this->MSTools) { - clOptions.FixExceptionHandlingDefault(); - clOptions.AddFlag("PrecompiledHeader", "NotUsing"); - std::string asmLocation = configName + "/"; - clOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str()); + if (vcxproj == this->ProjectType) { + clOptions.FixExceptionHandlingDefault(); + clOptions.AddFlag("PrecompiledHeader", "NotUsing"); + std::string asmLocation = configName + "/"; + clOptions.AddFlag("AssemblerListingLocation", asmLocation.c_str()); + } } clOptions.Parse(flags.c_str()); clOptions.Parse(defineFlags.c_str()); std::vector<std::string> targetDefines; - this->GeneratorTarget->GetCompileDefinitions(targetDefines, - configName.c_str(), "CXX"); + switch (this->ProjectType) { + case vcxproj: + this->GeneratorTarget->GetCompileDefinitions(targetDefines, + configName.c_str(), "CXX"); + break; + case csproj: + this->GeneratorTarget->GetCompileDefinitions( + targetDefines, configName.c_str(), "CSharp"); + break; + } clOptions.AddDefines(targetDefines); if (this->MSTools) { clOptions.SetVerboseMakefile( @@ -1841,6 +2102,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( std::string const& configName, std::vector<std::string> const& includes) { Options& clOptions = *(this->ClOptions[configName]); + if (this->ProjectType == csproj) { + return; + } this->WriteString("<ClCompile>\n", 2); clOptions.OutputAdditionalOptions(*this->BuildFileStream, " ", ""); clOptions.AppendFlag("AdditionalIncludeDirectories", includes); @@ -2509,6 +2773,9 @@ void cmVisualStudio10TargetGenerator::WriteLinkOptions( this->GeneratorTarget->GetType() > cmStateEnums::MODULE_LIBRARY) { return; } + if (csproj == this->ProjectType) { + return; + } Options& linkOptions = *(this->LinkOptions[config]); this->WriteString("<Link>\n", 2); @@ -2576,6 +2843,9 @@ void cmVisualStudio10TargetGenerator::WriteMidlOptions( if (!this->MSTools) { return; } + if (csproj == this->ProjectType) { + return; + } // This processes *any* of the .idl files specified in the project's file // list (and passed as the item metadata %(Filename) expressing the rule @@ -2637,7 +2907,9 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups() // output midl flags <Midl></Midl> this->WriteMidlOptions(*i, includes); // write events - this->WriteEvents(*i); + if (csproj != this->ProjectType) { + this->WriteEvents(*i); + } // output link flags <Link></Link> this->WriteLinkOptions(*i); // output lib flags <Lib></Lib> @@ -2703,12 +2975,20 @@ void cmVisualStudio10TargetGenerator::WriteEvent( script += cmVS10EscapeXML(lg->ConstructScript(ccg)); } comment = cmVS10EscapeComment(comment); - this->WriteString("<Message>", 3); - (*this->BuildFileStream) << cmVS10EscapeXML(comment) << "</Message>\n"; - this->WriteString("<Command>", 3); + if (csproj != this->ProjectType) { + this->WriteString("<Message>", 3); + (*this->BuildFileStream) << cmVS10EscapeXML(comment) << "</Message>\n"; + this->WriteString("<Command>", 3); + } else { + if (!comment.empty()) { + (*this->BuildFileStream) << "echo " << cmVS10EscapeXML(comment) << "\n"; + } + } (*this->BuildFileStream) << script; - (*this->BuildFileStream) << "</Command>" - << "\n"; + if (csproj != this->ProjectType) { + (*this->BuildFileStream) << "</Command>"; + } + (*this->BuildFileStream) << "\n"; this->WriteString("</", 2); (*this->BuildFileStream) << name << ">\n"; } @@ -2733,6 +3013,10 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() ->TargetIsFortranOnly(dt)) { continue; } + if (csproj == this->ProjectType && + !this->GlobalGenerator->TargetIsCSharpOnly(dt)) { + continue; + } this->WriteString("<ProjectReference Include=\"", 2); cmLocalGenerator* lg = dt->GetLocalGenerator(); std::string name = dt->GetName(); @@ -2749,8 +3033,16 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() this->ConvertToWindowsSlash(path); (*this->BuildFileStream) << cmVS10EscapeXML(path) << "\">\n"; this->WriteString("<Project>", 3); - (*this->BuildFileStream) << this->GlobalGenerator->GetGUID(name.c_str()) - << "</Project>\n"; + if (csproj == this->ProjectType) { + (*this->BuildFileStream) << "{"; + } + (*this->BuildFileStream) << this->GlobalGenerator->GetGUID(name.c_str()); + if (csproj == this->ProjectType) { + (*this->BuildFileStream) << "}"; + } + (*this->BuildFileStream) << "</Project>\n"; + this->WriteString("<Name>", 3); + (*this->BuildFileStream) << name << "</Name>\n"; this->WriteString("</ProjectReference>\n", 2); } this->WriteString("</ItemGroup>\n", 1); diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 027761e..45464c0 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -56,6 +56,7 @@ private: void WriteProjectConfigurations(); void WriteProjectConfigurationValues(); void WriteMSToolConfigurationValues(std::string const& config); + void WriteMSToolConfigurationValuesManaged(std::string const& config); void WriteHeaderSource(cmSourceFile const* sf); void WriteExtraSource(cmSourceFile const* sf); void WriteNsightTegraConfigurationValues(std::string const& config); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 733e0e4..6141f50 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -64,6 +64,7 @@ #include "cmGlobalVisualStudio71Generator.h" #include "cmGlobalVisualStudio8Generator.h" #include "cmGlobalVisualStudio9Generator.h" +#include "cmVSSetupHelper.h" #define CMAKE_HAVE_VS_GENERATORS #endif @@ -1470,18 +1471,23 @@ void cmake::CreateDefaultGlobalGenerator() "\\Setup\\VC;ProductDir", // ";InstallDir" // }; - for (VSVersionedGenerator const* g = cmArrayBegin(vsGenerators); - found.empty() && g != cmArrayEnd(vsGenerators); ++g) { - for (const char* const* v = cmArrayBegin(vsVariants); - found.empty() && v != cmArrayEnd(vsVariants); ++v) { - for (const char* const* e = cmArrayBegin(vsEntries); - found.empty() && e != cmArrayEnd(vsEntries); ++e) { - std::string const reg = vsregBase + *v + g->MSVersion + *e; - std::string dir; - if (cmSystemTools::ReadRegistryValue(reg, dir, - cmSystemTools::KeyWOW64_32) && - cmSystemTools::PathExists(dir)) { - found = g->GeneratorName; + cmVSSetupAPIHelper vsSetupAPIHelper; + if (vsSetupAPIHelper.IsVS2017Installed()) { + found = "Visual Studio 15 2017"; + } else { + for (VSVersionedGenerator const* g = cmArrayBegin(vsGenerators); + found.empty() && g != cmArrayEnd(vsGenerators); ++g) { + for (const char* const* v = cmArrayBegin(vsVariants); + found.empty() && v != cmArrayEnd(vsVariants); ++v) { + for (const char* const* e = cmArrayBegin(vsEntries); + found.empty() && e != cmArrayEnd(vsEntries); ++e) { + std::string const reg = vsregBase + *v + g->MSVersion + *e; + std::string dir; + if (cmSystemTools::ReadRegistryValue(reg, dir, + cmSystemTools::KeyWOW64_32) && + cmSystemTools::PathExists(dir)) { + found = g->GeneratorName; + } } } } |