summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeInstallDestinations.cmake8
-rw-r--r--Source/CMakeLists.txt11
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CPack/cmCPackDebGenerator.cxx6
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.cxx31
-rw-r--r--Source/CTest/cmCTestMemCheckHandler.h1
-rw-r--r--Source/CTest/cmCTestRunTest.cxx2
-rw-r--r--Source/QtDialog/RegexExplorer.cxx34
-rw-r--r--Source/QtDialog/RegexExplorer.h1
-rw-r--r--Source/QtDialog/RegexExplorer.ui37
-rw-r--r--Source/QtIFW/CMake.DeveloperReference.HTML.qs.in4
-rw-r--r--Source/QtIFW/CMake.Dialogs.QtGUI.qs.in (renamed from Source/QtIFW/CMake.Dialogs.QtGUI.qs)4
-rw-r--r--Source/QtIFW/CMake.Documentation.SphinxHTML.qs.in4
-rw-r--r--Source/QtIFW/CMake.qs.in10
-rw-r--r--Source/QtIFW/installscript.qs.in12
-rw-r--r--Source/cmCommonTargetGenerator.cxx7
-rw-r--r--Source/cmDependsC.cxx4
-rw-r--r--Source/cmExtraCodeBlocksGenerator.cxx3
-rw-r--r--Source/cmExtraSublimeTextGenerator.cxx12
-rw-r--r--Source/cmFileMonitor.cxx3
-rw-r--r--Source/cmGlobalVisualStudio10Generator.cxx14
-rw-r--r--Source/cmGlobalVisualStudio15Generator.cxx56
-rw-r--r--Source/cmGlobalVisualStudio15Generator.h5
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx16
-rw-r--r--Source/cmLinkLineComputer.cxx6
-rw-r--r--Source/cmLinkLineComputer.h4
-rw-r--r--Source/cmLinkLineDeviceComputer.cxx6
-rw-r--r--Source/cmLinkLineDeviceComputer.h3
-rw-r--r--Source/cmListFileLexer.c2
-rw-r--r--Source/cmListFileLexer.h2
-rw-r--r--Source/cmListFileLexer.in.l2
-rw-r--r--Source/cmLocalGenerator.cxx5
-rw-r--r--Source/cmLocalUnixMakefileGenerator3.cxx4
-rw-r--r--Source/cmLocale.h5
-rw-r--r--Source/cmMakefile.cxx2
-rw-r--r--Source/cmMakefileExecutableTargetGenerator.cxx19
-rw-r--r--Source/cmMakefileLibraryTargetGenerator.cxx10
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx10
-rw-r--r--Source/cmNinjaTargetGenerator.cxx3
-rw-r--r--Source/cmQtAutoGeneratorInitializer.cxx110
-rw-r--r--Source/cmQtAutoGenerators.cxx1284
-rw-r--r--Source/cmQtAutoGenerators.h120
-rw-r--r--Source/cmServerProtocol.cxx10
-rw-r--r--Source/cmTarget.cxx6
-rw-r--r--Source/cmVSSetupHelper.cxx366
-rw-r--r--Source/cmVSSetupHelper.h154
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx434
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h1
-rw-r--r--Source/cmake.cxx30
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;
+ }
}
}
}