summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeLists.txt6
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CTest/cmCTestRunTest.cxx34
-rw-r--r--Source/CTest/cmCTestRunTest.h2
-rw-r--r--Source/CTest/cmCTestTestHandler.cxx6
-rw-r--r--Source/CTest/cmCTestTestHandler.h1
-rw-r--r--Source/CursesDialog/cmCursesLongMessageForm.cxx2
-rw-r--r--Source/cmCMakeCommand.cxx81
-rw-r--r--Source/cmCMakeLanguageCommand.cxx111
-rw-r--r--Source/cmCMakeLanguageCommand.h (renamed from Source/cmCMakeCommand.h)8
-rw-r--r--Source/cmCommands.cxx4
-rw-r--r--Source/cmCommonTargetGenerator.cxx28
-rw-r--r--Source/cmCommonTargetGenerator.h3
-rw-r--r--Source/cmComputeLinkInformation.cxx39
-rw-r--r--Source/cmCoreTryCompile.cxx3
-rw-r--r--Source/cmExportBuildAndroidMKGenerator.cxx4
-rw-r--r--Source/cmExportFileGenerator.cxx10
-rw-r--r--Source/cmExportTryCompileFileGenerator.cxx2
-rw-r--r--Source/cmFileCommand.cxx13
-rw-r--r--Source/cmGeneratorTarget.cxx101
-rw-r--r--Source/cmGeneratorTarget.h40
-rw-r--r--Source/cmGlobalGenerator.cxx4
-rw-r--r--Source/cmGlobalGenerator.h2
-rw-r--r--Source/cmGlobalNinjaGenerator.h5
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx1
-rw-r--r--Source/cmLocalGenerator.cxx4
-rw-r--r--Source/cmLocalNinjaGenerator.cxx37
-rw-r--r--Source/cmLocalVisualStudio7Generator.cxx27
-rw-r--r--Source/cmMakefile.cxx12
-rw-r--r--Source/cmMakefileTargetGenerator.cxx12
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx2
-rw-r--r--Source/cmNinjaTargetGenerator.cxx375
-rw-r--r--Source/cmNinjaTargetGenerator.h2
-rw-r--r--Source/cmNinjaUtilityTargetGenerator.cxx5
-rw-r--r--Source/cmOutputConverter.cxx11
-rw-r--r--Source/cmOutputConverter.h8
-rw-r--r--Source/cmPropertyDefinition.cxx39
-rw-r--r--Source/cmPropertyDefinition.h36
-rw-r--r--Source/cmPropertyDefinitionMap.cxx35
-rw-r--r--Source/cmPropertyDefinitionMap.h30
-rw-r--r--Source/cmState.cxx30
-rw-r--r--Source/cmState.h8
-rw-r--r--Source/cmTarget.cxx5
-rw-r--r--Source/cmTarget.h8
-rw-r--r--Source/cmTestGenerator.cxx14
-rw-r--r--Source/cmVisualStudio10TargetGenerator.cxx228
-rw-r--r--Source/cmVisualStudio10TargetGenerator.h11
-rw-r--r--Source/cmVisualStudioGeneratorOptions.cxx28
-rw-r--r--Source/cmVisualStudioGeneratorOptions.h1
-rw-r--r--Source/cmWorkerPool.cxx69
-rw-r--r--Source/cmXCodeScheme.cxx3
-rw-r--r--Source/kwsys/Directory.cxx35
-rw-r--r--Source/kwsys/Directory.hxx.in5
-rw-r--r--Source/kwsys/Glob.cxx14
-rw-r--r--Source/kwsys/Glob.hxx.in1
-rw-r--r--Source/kwsys/testDirectory.cxx37
56 files changed, 974 insertions, 670 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index ec473d2..22d8032 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -383,8 +383,6 @@ set(SRCS
cmProperty.h
cmPropertyDefinition.cxx
cmPropertyDefinition.h
- cmPropertyDefinitionMap.cxx
- cmPropertyDefinitionMap.h
cmPropertyMap.cxx
cmPropertyMap.h
cmQtAutoGen.cxx
@@ -490,10 +488,10 @@ set(SRCS
cmBuildCommand.h
cmBuildNameCommand.cxx
cmBuildNameCommand.h
- cmCMakeCommand.cxx
- cmCMakeCommand.h
cmCMakeHostSystemInformationCommand.cxx
cmCMakeHostSystemInformationCommand.h
+ cmCMakeLanguageCommand.cxx
+ cmCMakeLanguageCommand.h
cmCMakeMinimumRequired.cxx
cmCMakeMinimumRequired.h
cmCMakePolicyCommand.cxx
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index f8d9aee..feb55e8 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 17)
-set(CMake_VERSION_PATCH 20200519)
+set(CMake_VERSION_PATCH 20200525)
#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx
index 7674d7a..ba7d47e 100644
--- a/Source/CTest/cmCTestRunTest.cxx
+++ b/Source/CTest/cmCTestRunTest.cxx
@@ -429,6 +429,7 @@ void cmCTestRunTest::StartFailure(std::string const& output,
this->TestResult.Path = this->TestProperties->Directory;
this->TestResult.Output = output;
this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
}
std::string cmCTestRunTest::GetTestPrefix(size_t completed, size_t total) const
@@ -500,6 +501,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
this->TestResult.Output = "Disabled";
this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
return false;
}
@@ -519,6 +521,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
cmCTestLog(this->CTest, HANDLER_OUTPUT, msg << std::endl);
this->TestResult.Output = msg;
this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
this->TestResult.CompletionStatus = "Fixture dependency failed";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
return false;
@@ -539,6 +542,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
cmCTestLog(this->CTest, ERROR_MESSAGE, msg << std::endl);
this->TestResult.Output = msg;
this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
this->TestResult.CompletionStatus = "Missing Configuration";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
return false;
@@ -554,6 +558,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
"Unable to find required file: " << file << std::endl);
this->TestResult.Output = "Unable to find required file: " + file;
this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
this->TestResult.CompletionStatus = "Required Files Missing";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
return false;
@@ -569,6 +574,7 @@ bool cmCTestRunTest::StartTest(size_t completed, size_t total)
"Unable to find executable: " << args[1] << std::endl);
this->TestResult.Output = "Unable to find executable: " + args[1];
this->TestResult.FullCommandLine.clear();
+ this->TestResult.Environment.clear();
this->TestResult.CompletionStatus = "Unable to find executable";
this->TestResult.Status = cmCTestTestHandler::NOT_RUN;
return false;
@@ -713,25 +719,43 @@ bool cmCTestRunTest::ForkProcess(cmDuration testTimeOut, bool explicitTimeout,
cmSystemTools::SaveRestoreEnvironment sre;
#endif
+ std::ostringstream envMeasurement;
if (environment && !environment->empty()) {
cmSystemTools::AppendEnv(*environment);
+ for (auto const& var : *environment) {
+ envMeasurement << var << std::endl;
+ }
}
if (this->UseAllocatedResources) {
- this->SetupResourcesEnvironment();
+ std::vector<std::string> envLog;
+ this->SetupResourcesEnvironment(&envLog);
+ for (auto const& var : envLog) {
+ envMeasurement << var << std::endl;
+ }
} else {
cmSystemTools::UnsetEnv("CTEST_RESOURCE_GROUP_COUNT");
+ // Signify that this variable is being actively unset
+ envMeasurement << "#CTEST_RESOURCE_GROUP_COUNT=" << std::endl;
}
+ this->TestResult.Environment = envMeasurement.str();
+ // Remove last newline
+ this->TestResult.Environment.erase(this->TestResult.Environment.length() -
+ 1);
+
return this->TestProcess->StartProcess(this->MultiTestHandler.Loop,
affinity);
}
-void cmCTestRunTest::SetupResourcesEnvironment()
+void cmCTestRunTest::SetupResourcesEnvironment(std::vector<std::string>* log)
{
std::string processCount = "CTEST_RESOURCE_GROUP_COUNT=";
processCount += std::to_string(this->AllocatedResources.size());
cmSystemTools::PutEnv(processCount);
+ if (log) {
+ log->push_back(processCount);
+ }
std::size_t i = 0;
for (auto const& process : this->AllocatedResources) {
@@ -757,8 +781,14 @@ void cmCTestRunTest::SetupResourcesEnvironment()
var += "id:" + it2.Id + ",slots:" + std::to_string(it2.Slots);
}
cmSystemTools::PutEnv(var);
+ if (log) {
+ log->push_back(var);
+ }
}
cmSystemTools::PutEnv(resourceList);
+ if (log) {
+ log->push_back(resourceList);
+ }
++i;
}
}
diff --git a/Source/CTest/cmCTestRunTest.h b/Source/CTest/cmCTestRunTest.h
index b1d188a..d831247 100644
--- a/Source/CTest/cmCTestRunTest.h
+++ b/Source/CTest/cmCTestRunTest.h
@@ -119,7 +119,7 @@ private:
// Run post processing of the process output for MemCheck
void MemCheckPostProcess();
- void SetupResourcesEnvironment();
+ void SetupResourcesEnvironment(std::vector<std::string>* log = nullptr);
// Returns "completed/total Test #Index: "
std::string GetTestPrefix(size_t completed, size_t total) const;
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 8fc5cd6..d0dbaae 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -1432,6 +1432,12 @@ void cmCTestTestHandler::GenerateDartOutput(cmXMLWriter& xml)
xml.Attribute("name", "Command Line");
xml.Element("Value", result.FullCommandLine);
xml.EndElement(); // NamedMeasurement
+
+ xml.StartElement("NamedMeasurement");
+ xml.Attribute("type", "text/string");
+ xml.Attribute("name", "Environment");
+ xml.Element("Value", result.Environment);
+ xml.EndElement(); // NamedMeasurement
for (auto const& measure : result.Properties->Measurements) {
xml.StartElement("NamedMeasurement");
xml.Attribute("type", "text/string");
diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h
index 55cecb6..0d88c30 100644
--- a/Source/CTest/cmCTestTestHandler.h
+++ b/Source/CTest/cmCTestTestHandler.h
@@ -169,6 +169,7 @@ public:
std::string Path;
std::string Reason;
std::string FullCommandLine;
+ std::string Environment;
cmDuration ExecutionTime;
std::int64_t ReturnValue;
int Status;
diff --git a/Source/CursesDialog/cmCursesLongMessageForm.cxx b/Source/CursesDialog/cmCursesLongMessageForm.cxx
index 664ba2f..591c546 100644
--- a/Source/CursesDialog/cmCursesLongMessageForm.cxx
+++ b/Source/CursesDialog/cmCursesLongMessageForm.cxx
@@ -68,7 +68,7 @@ void cmCursesLongMessageForm::UpdateStatusBar()
bar[i] = ' ';
}
int width;
- if (x < cmCursesMainForm::MAX_WIDTH) {
+ if (x >= 0 && x < cmCursesMainForm::MAX_WIDTH) {
width = x;
} else {
width = cmCursesMainForm::MAX_WIDTH - 1;
diff --git a/Source/cmCMakeCommand.cxx b/Source/cmCMakeCommand.cxx
deleted file mode 100644
index da15b1a..0000000
--- a/Source/cmCMakeCommand.cxx
+++ /dev/null
@@ -1,81 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmCMakeCommand.h"
-
-#include <algorithm>
-#include <cstddef>
-#include <iosfwd>
-#include <memory>
-#include <string>
-
-#include "cmExecutionStatus.h"
-#include "cmListFileCache.h"
-#include "cmMakefile.h"
-#include "cmRange.h"
-#include "cmStringAlgorithms.h"
-
-inline std::ostream& operator<<(std::ostream& os,
- cmListFileArgument const& arg)
-{
- os << arg.Value;
- return os;
-}
-
-bool cmCMakeCommand(std::vector<cmListFileArgument> const& args,
- cmExecutionStatus& status)
-{
- if (args.empty()) {
- status.SetError("called with incorrect number of arguments");
- return false;
- }
-
- cmMakefile& makefile = status.GetMakefile();
- cmListFileContext context = makefile.GetExecutionContext();
-
- bool result = false;
-
- if (args[0].Value == "INVOKE") {
- if (args.size() == 1) {
- status.SetError("called with incorrect number of arguments");
- return false;
- }
-
- // First argument is the name of the function to call
- cmListFileFunction func;
- func.Name = args[1].Value;
- func.Line = context.Line;
-
- // The rest of the arguments are passed to the function call above
- func.Arguments.resize(args.size() - 1);
- for (size_t i = 2; i < args.size(); ++i) {
- cmListFileArgument lfarg;
- lfarg.Delim = args[i].Delim;
- lfarg.Line = context.Line;
- lfarg.Value = args[i].Value;
- func.Arguments.emplace_back(lfarg);
- }
-
- result = makefile.ExecuteCommand(func, status);
- } else if (args[0].Value == "EVAL") {
- if (args.size() < 2) {
- status.SetError("called with incorrect number of arguments");
- return false;
- }
-
- auto code_iter = std::find_if(
- args.begin(), args.end(),
- [](cmListFileArgument const& arg) { return arg.Value == "CODE"; });
- if (code_iter == args.end()) {
- status.SetError("called without CODE argument");
- return false;
- }
-
- const std::string code = cmJoin(cmMakeRange(++code_iter, args.end()), " ");
- result = makefile.ReadListFileAsString(
- code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL"));
- } else {
- status.SetError("called with unknown meta-operation");
- }
-
- return result;
-}
diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx
new file mode 100644
index 0000000..66857be
--- /dev/null
+++ b/Source/cmCMakeLanguageCommand.cxx
@@ -0,0 +1,111 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmCMakeLanguageCommand.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+
+#include "cmExecutionStatus.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmRange.h"
+#include "cmStringAlgorithms.h"
+
+bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status)
+{
+ if (args.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ cmMakefile& makefile = status.GetMakefile();
+ cmListFileContext context = makefile.GetExecutionContext();
+
+ bool result = false;
+
+ std::vector<std::string> dispatchExpandedArgs;
+ std::vector<cmListFileArgument> dispatchArgs;
+ dispatchArgs.emplace_back(args[0]);
+ makefile.ExpandArguments(dispatchArgs, dispatchExpandedArgs);
+
+ if (dispatchExpandedArgs.empty()) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ if (dispatchExpandedArgs[0] == "CALL") {
+ if ((args.size() == 1 && dispatchExpandedArgs.size() != 2) ||
+ dispatchExpandedArgs.size() > 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ // First argument is the name of the function to call
+ std::string callCommand;
+ size_t startArg;
+ if (dispatchExpandedArgs.size() == 1) {
+ std::vector<std::string> functionExpandedArg;
+ std::vector<cmListFileArgument> functionArg;
+ functionArg.emplace_back(args[1]);
+ makefile.ExpandArguments(functionArg, functionExpandedArg);
+
+ if (functionExpandedArg.size() != 1) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ callCommand = functionExpandedArg[0];
+ startArg = 2;
+ } else {
+ callCommand = dispatchExpandedArgs[1];
+ startArg = 1;
+ }
+
+ cmListFileFunction func;
+ func.Name = callCommand;
+ func.Line = context.Line;
+
+ // The rest of the arguments are passed to the function call above
+ for (size_t i = startArg; i < args.size(); ++i) {
+ cmListFileArgument lfarg;
+ lfarg.Delim = args[i].Delim;
+ lfarg.Line = context.Line;
+ lfarg.Value = args[i].Value;
+ func.Arguments.emplace_back(lfarg);
+ }
+
+ result = makefile.ExecuteCommand(func, status);
+ } else if (dispatchExpandedArgs[0] == "EVAL") {
+ std::vector<std::string> expandedArgs;
+ makefile.ExpandArguments(args, expandedArgs);
+
+ if (expandedArgs.size() < 2) {
+ status.SetError("called with incorrect number of arguments");
+ return false;
+ }
+
+ if (expandedArgs[1] != "CODE") {
+ auto code_iter =
+ std::find(expandedArgs.begin() + 2, expandedArgs.end(), "CODE");
+ if (code_iter == expandedArgs.end()) {
+ status.SetError("called without CODE argument");
+ } else {
+ status.SetError(
+ "called with unsupported arguments between EVAL and CODE arguments");
+ }
+ return false;
+ }
+
+ const std::string code =
+ cmJoin(cmMakeRange(expandedArgs.begin() + 2, expandedArgs.end()), " ");
+ result = makefile.ReadListFileAsString(
+ code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL"));
+ } else {
+ status.SetError("called with unknown meta-operation");
+ }
+
+ return result;
+}
diff --git a/Source/cmCMakeCommand.h b/Source/cmCMakeLanguageCommand.h
index 7dbecff..7306515 100644
--- a/Source/cmCMakeCommand.h
+++ b/Source/cmCMakeLanguageCommand.h
@@ -1,7 +1,7 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
-#ifndef cmCMakeCommand_h
-#define cmCMakeCommand_h
+#ifndef cmCMakeLanguageCommand_h
+#define cmCMakeLanguageCommand_h
#include "cmConfigure.h" // IWYU pragma: keep
@@ -14,7 +14,7 @@ struct cmListFileArgument;
* \brief Calls a scripted or build-in command
*
*/
-bool cmCMakeCommand(std::vector<cmListFileArgument> const& args,
- cmExecutionStatus& status);
+bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
+ cmExecutionStatus& status);
#endif
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx
index 28b4267..c94f128 100644
--- a/Source/cmCommands.cxx
+++ b/Source/cmCommands.cxx
@@ -91,8 +91,8 @@
# include "cmAddLinkOptionsCommand.h"
# include "cmAuxSourceDirectoryCommand.h"
# include "cmBuildNameCommand.h"
-# include "cmCMakeCommand.h"
# include "cmCMakeHostSystemInformationCommand.h"
+# include "cmCMakeLanguageCommand.h"
# include "cmExportCommand.h"
# include "cmExportLibraryDependenciesCommand.h"
# include "cmFLTKWrapUICommand.h"
@@ -197,9 +197,9 @@ void GetScriptingCommands(cmState* state)
"match the opening WHILE command.");
#if !defined(CMAKE_BOOTSTRAP)
- state->AddBuiltinCommand("cmake_command", cmCMakeCommand);
state->AddBuiltinCommand("cmake_host_system_information",
cmCMakeHostSystemInformationCommand);
+ state->AddBuiltinCommand("cmake_language", cmCMakeLanguageCommand);
state->AddBuiltinCommand("load_cache", cmLoadCacheCommand);
state->AddBuiltinCommand("remove", cmRemoveCommand);
state->AddBuiltinCommand("variable_watch", cmVariableWatchCommand);
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx
index 5414409..32a33ee 100644
--- a/Source/cmCommonTargetGenerator.cxx
+++ b/Source/cmCommonTargetGenerator.cxx
@@ -98,6 +98,34 @@ void cmCommonTargetGenerator::AppendFortranFormatFlags(
}
}
+void cmCommonTargetGenerator::AppendFortranPreprocessFlags(
+ std::string& flags, cmSourceFile const& source)
+{
+ const std::string srcpp = source.GetSafeProperty("Fortran_PREPROCESS");
+ cmOutputConverter::FortranPreprocess preprocess =
+ cmOutputConverter::GetFortranPreprocess(srcpp);
+ if (preprocess == cmOutputConverter::FortranPreprocess::Unset) {
+ std::string const& tgtpp =
+ this->GeneratorTarget->GetSafeProperty("Fortran_PREPROCESS");
+ preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp);
+ }
+ const char* var = nullptr;
+ switch (preprocess) {
+ case cmOutputConverter::FortranPreprocess::Needed:
+ var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_ON";
+ break;
+ case cmOutputConverter::FortranPreprocess::NotNeeded:
+ var = "CMAKE_Fortran_COMPILE_OPTIONS_PREPROCESS_OFF";
+ break;
+ default:
+ break;
+ }
+ if (var) {
+ this->LocalCommonGenerator->AppendCompileOptions(
+ flags, this->Makefile->GetSafeDefinition(var));
+ }
+}
+
std::string cmCommonTargetGenerator::GetFlags(const std::string& l,
const std::string& config,
const std::string& arch)
diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h
index 78cedf5..c3c3a3a 100644
--- a/Source/cmCommonTargetGenerator.h
+++ b/Source/cmCommonTargetGenerator.h
@@ -45,6 +45,9 @@ protected:
void AppendFortranFormatFlags(std::string& flags,
cmSourceFile const& source);
+ void AppendFortranPreprocessFlags(std::string& flags,
+ cmSourceFile const& source);
+
virtual void AddIncludeFlags(std::string& flags, std::string const& lang,
const std::string& config) = 0;
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index ea7ede4..8723d08 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -12,7 +12,6 @@
#include <cmext/algorithm>
#include "cmComputeLinkDepends.h"
-#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
#include "cmListFileCache.h"
@@ -587,32 +586,18 @@ void cmComputeLinkInformation::AddImplicitLinkInfo()
}
void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang)
-{ // Add the lang runtime library flags. This is activated by the presence
- // of a default selection whether or not it is overridden by a property.
- std::string defaultVar =
- cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT");
- cmProp langRuntimeLibraryDefault = this->Makefile->GetDef(defaultVar);
- if (langRuntimeLibraryDefault && !langRuntimeLibraryDefault->empty()) {
- cmProp runtimeLibraryValue =
- this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY"));
- if (!runtimeLibraryValue) {
- runtimeLibraryValue = langRuntimeLibraryDefault;
- }
-
- std::string runtimeLibrary =
- cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate(
- *runtimeLibraryValue, this->Target->GetLocalGenerator(), this->Config,
- this->Target));
- if (!runtimeLibrary.empty()) {
- if (const char* runtimeLinkOptions = this->Makefile->GetDefinition(
- "CMAKE_" + lang + "_RUNTIME_LIBRARY_LINK_OPTIONS_" +
- runtimeLibrary)) {
- std::vector<std::string> libsVec = cmExpandedList(runtimeLinkOptions);
- for (std::string const& i : libsVec) {
- if (!cm::contains(this->ImplicitLinkLibs, i)) {
- this->AddItem(i, nullptr);
- }
- }
+{
+ std::string const& runtimeLibrary =
+ this->Target->GetRuntimeLinkLibrary(lang, this->Config);
+ if (runtimeLibrary.empty()) {
+ return;
+ }
+ if (const char* runtimeLinkOptions = this->Makefile->GetDefinition(
+ "CMAKE_" + lang + "_RUNTIME_LIBRARY_LINK_OPTIONS_" + runtimeLibrary)) {
+ std::vector<std::string> libsVec = cmExpandedList(runtimeLinkOptions);
+ for (std::string const& i : libsVec) {
+ if (!cm::contains(this->ImplicitLinkLibs, i)) {
+ this->AddItem(i, nullptr);
}
}
}
diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx
index 4e2caed..cc2cd01 100644
--- a/Source/cmCoreTryCompile.cxx
+++ b/Source/cmCoreTryCompile.cxx
@@ -44,6 +44,8 @@ static std::string const kCMAKE_CUDA_ARCHITECTURES =
"CMAKE_CUDA_ARCHITECTURES";
static std::string const kCMAKE_CUDA_COMPILER_TARGET =
"CMAKE_CUDA_COMPILER_TARGET";
+static std::string const kCMAKE_CUDA_RUNTIME_LIBRARY =
+ "CMAKE_CUDA_RUNTIME_LIBRARY";
static std::string const kCMAKE_ENABLE_EXPORTS = "CMAKE_ENABLE_EXPORTS";
static std::string const kCMAKE_LINK_SEARCH_END_STATIC =
"CMAKE_LINK_SEARCH_END_STATIC";
@@ -717,6 +719,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
vars.insert(kCMAKE_CXX_COMPILER_TARGET);
vars.insert(kCMAKE_CUDA_ARCHITECTURES);
vars.insert(kCMAKE_CUDA_COMPILER_TARGET);
+ vars.insert(kCMAKE_CUDA_RUNTIME_LIBRARY);
vars.insert(kCMAKE_ENABLE_EXPORTS);
vars.insert(kCMAKE_LINK_SEARCH_END_STATIC);
vars.insert(kCMAKE_LINK_SEARCH_START_STATIC);
diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx
index 0ee1259..3641cb2 100644
--- a/Source/cmExportBuildAndroidMKGenerator.cxx
+++ b/Source/cmExportBuildAndroidMKGenerator.cxx
@@ -47,7 +47,9 @@ void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode(
os << "LOCAL_MODULE := ";
os << targetName << "\n";
os << "LOCAL_SRC_FILES := ";
- std::string path = cmSystemTools::ConvertToOutputPath(target->GetFullPath());
+ std::string const noConfig; // FIXME: What config to use here?
+ std::string path =
+ cmSystemTools::ConvertToOutputPath(target->GetFullPath(noConfig));
os << path << "\n";
}
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 28037c6..ed0689a 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -923,12 +923,14 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os)
/* clang-format on */
// Isolate the file policy level.
- // We use 2.6 here instead of the current version because newer
- // versions of CMake should be able to export files imported by 2.6
- // until the import format changes.
+ // Support CMake versions as far back as 2.6 but also support using NEW
+ // policy settings for up to CMake 3.17 (this upper limit may be reviewed
+ // and increased from time to time). This reduces the opportunity for CMake
+ // warnings when an older export file is later used with newer CMake
+ // versions.
/* clang-format off */
os << "cmake_policy(PUSH)\n"
- << "cmake_policy(VERSION 2.6)\n";
+ << "cmake_policy(VERSION 2.6...3.17)\n";
/* clang-format on */
}
diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx
index 6212667..46056c1 100644
--- a/Source/cmExportTryCompileFileGenerator.cxx
+++ b/Source/cmExportTryCompileFileGenerator.cxx
@@ -71,7 +71,7 @@ std::string cmExportTryCompileFileGenerator::FindTargets(
cmTarget dummyHead("try_compile_dummy_exe", cmStateEnums::EXECUTABLE,
cmTarget::VisibilityNormal, tgt->Target->GetMakefile(),
- true);
+ cmTarget::PerConfig::Yes);
cmGeneratorTarget gDummyHead(&dummyHead, tgt->GetLocalGenerator());
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index f3d49c3..268c5d1 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -677,12 +677,12 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse,
}
}
+ cmake* cm = status.GetMakefile().GetCMakeInstance();
std::vector<std::string> files;
bool configureDepends = false;
bool warnConfigureLate = false;
bool warnFollowedSymlinks = false;
- const cmake::WorkingMode workingMode =
- status.GetMakefile().GetCMakeInstance()->GetWorkingMode();
+ const cmake::WorkingMode workingMode = cm->GetWorkingMode();
while (i != args.end()) {
if (*i == "LIST_DIRECTORIES") {
++i; // skip LIST_DIRECTORIES
@@ -770,12 +770,17 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse,
MessageType::AUTHOR_WARNING,
"Cyclic recursion detected while globbing for '" + *i + "':\n" +
globMessage.content);
- } else {
+ } else if (globMessage.type == cmsys::Glob::error) {
status.GetMakefile().IssueMessage(
MessageType::FATAL_ERROR,
"Error has occurred while globbing for '" + *i + "' - " +
globMessage.content);
shouldExit = true;
+ } else if (cm->GetDebugOutput() || cm->GetTrace()) {
+ status.GetMakefile().IssueMessage(
+ MessageType::LOG,
+ cmStrCat("Globbing for\n ", *i, "\nEncountered an error:\n ",
+ globMessage.content));
}
}
if (shouldExit) {
@@ -795,7 +800,7 @@ bool HandleGlobImpl(std::vector<std::string> const& args, bool recurse,
std::sort(foundFiles.begin(), foundFiles.end());
foundFiles.erase(std::unique(foundFiles.begin(), foundFiles.end()),
foundFiles.end());
- status.GetMakefile().GetCMakeInstance()->AddGlobCacheEntry(
+ cm->AddGlobCacheEntry(
recurse, (recurse ? g.GetRecurseListDirs() : g.GetListDirs()),
(recurse ? g.GetRecurseThroughSymlinks() : false),
(g.GetRelative() ? g.GetRelative() : ""), expr, foundFiles, variable,
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 335f7a4..f2a51ab 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -976,51 +976,12 @@ void cmGeneratorTarget::GetExternalObjects(
IMPLEMENT_VISIT(SourceKindExternalObject);
}
-void cmGeneratorTarget::GetExpectedResxHeaders(std::set<std::string>& headers,
- const std::string& config) const
-{
- KindedSources const& kinded = this->GetKindedSources(config);
- headers = kinded.ExpectedResxHeaders;
-}
-
-void cmGeneratorTarget::GetResxSources(std::vector<cmSourceFile const*>& data,
- const std::string& config) const
-{
- IMPLEMENT_VISIT(SourceKindResx);
-}
-
-void cmGeneratorTarget::GetAppManifest(std::vector<cmSourceFile const*>& data,
- const std::string& config) const
-{
- IMPLEMENT_VISIT(SourceKindAppManifest);
-}
-
void cmGeneratorTarget::GetManifests(std::vector<cmSourceFile const*>& data,
const std::string& config) const
{
IMPLEMENT_VISIT(SourceKindManifest);
}
-void cmGeneratorTarget::GetCertificates(std::vector<cmSourceFile const*>& data,
- const std::string& config) const
-{
- IMPLEMENT_VISIT(SourceKindCertificate);
-}
-
-void cmGeneratorTarget::GetExpectedXamlHeaders(std::set<std::string>& headers,
- const std::string& config) const
-{
- KindedSources const& kinded = this->GetKindedSources(config);
- headers = kinded.ExpectedXamlHeaders;
-}
-
-void cmGeneratorTarget::GetExpectedXamlSources(std::set<std::string>& srcs,
- const std::string& config) const
-{
- KindedSources const& kinded = this->GetKindedSources(config);
- srcs = kinded.ExpectedXamlSources;
-}
-
std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const
{
if (!this->UtilityItemsDone) {
@@ -1040,12 +1001,6 @@ std::set<cmLinkItem> const& cmGeneratorTarget::GetUtilityItems() const
return this->UtilityItems;
}
-void cmGeneratorTarget::GetXamlSources(std::vector<cmSourceFile const*>& data,
- const std::string& config) const
-{
- IMPLEMENT_VISIT(SourceKindXaml);
-}
-
const std::string& cmGeneratorTarget::GetLocation(
const std::string& config) const
{
@@ -1097,7 +1052,8 @@ const std::string& cmGeneratorTarget::GetLocationForBuild() const
}
// Now handle the deprecated build-time configuration location.
- location = this->GetDirectory();
+ std::string const noConfig;
+ location = this->GetDirectory(noConfig);
const char* cfgid = this->Makefile->GetDefinition("CMAKE_CFG_INTDIR");
if (cfgid && strcmp(cfgid, ".") != 0) {
location += "/";
@@ -1727,14 +1683,6 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files,
}
} else if (ext == "resx") {
kind = SourceKindResx;
- // Build and save the name of the corresponding .h file
- // This relationship will be used later when building the project files.
- // Both names would have been auto generated from Visual Studio
- // where the user supplied the file name and Visual Studio
- // appended the suffix.
- std::string resx = sf->ResolveFullPath();
- std::string hFileName = resx.substr(0, resx.find_last_of('.')) + ".h";
- files.ExpectedResxHeaders.insert(hFileName);
} else if (ext == "appxmanifest") {
kind = SourceKindAppManifest;
} else if (ext == "manifest") {
@@ -1743,16 +1691,6 @@ void cmGeneratorTarget::ComputeKindedSources(KindedSources& files,
kind = SourceKindCertificate;
} else if (ext == "xaml") {
kind = SourceKindXaml;
- // Build and save the name of the corresponding .h and .cpp file
- // This relationship will be used later when building the project files.
- // Both names would have been auto generated from Visual Studio
- // where the user supplied the file name and Visual Studio
- // appended the suffix.
- std::string xaml = sf->ResolveFullPath();
- std::string hFileName = xaml + ".h";
- std::string cppFileName = xaml + ".cpp";
- files.ExpectedXamlHeaders.insert(hFileName);
- files.ExpectedXamlSources.insert(cppFileName);
} else if (header_regex.find(sf->ResolveFullPath())) {
kind = SourceKindHeader;
} else {
@@ -1810,6 +1748,18 @@ void cmGeneratorTarget::ComputeAllConfigSources() const
}
}
+std::vector<cmGeneratorTarget::AllConfigSource>
+cmGeneratorTarget::GetAllConfigSources(SourceKind kind) const
+{
+ std::vector<AllConfigSource> result;
+ for (AllConfigSource const& source : this->GetAllConfigSources()) {
+ if (source.Kind == kind) {
+ result.push_back(source);
+ }
+ }
+ return result;
+}
+
std::set<std::string> cmGeneratorTarget::GetAllConfigCompileLanguages() const
{
std::set<std::string> languages;
@@ -3914,6 +3864,10 @@ std::string cmGeneratorTarget::GetPchFileObject(const std::string& config,
pchSource, false, cmSourceFileLocationKind::Known);
filename = cmStrCat(this->ObjectDirectory, this->GetObjectName(pchSf));
+ if (this->GetGlobalGenerator()->IsMultiConfig()) {
+ cmSystemTools::ReplaceString(
+ filename, this->GetGlobalGenerator()->GetCMakeCFGIntDir(), config);
+ }
}
return inserted.first->second;
}
@@ -5756,6 +5710,25 @@ void cmGeneratorTarget::GetTargetVersion(const std::string& property,
}
}
+std::string cmGeneratorTarget::GetRuntimeLinkLibrary(
+ std::string const& lang, std::string const& config) const
+{
+ // This is activated by the presence of a default selection whether or
+ // not it is overridden by a property.
+ cmProp runtimeLibraryDefault = this->Makefile->GetDef(
+ cmStrCat("CMAKE_", lang, "_RUNTIME_LIBRARY_DEFAULT"));
+ if (!runtimeLibraryDefault || runtimeLibraryDefault->empty()) {
+ return std::string();
+ }
+ cmProp runtimeLibraryValue =
+ this->Target->GetProperty(cmStrCat(lang, "_RUNTIME_LIBRARY"));
+ if (!runtimeLibraryValue) {
+ runtimeLibraryValue = runtimeLibraryDefault;
+ }
+ return cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate(
+ *runtimeLibraryValue, this->LocalGenerator, config, this));
+}
+
std::string cmGeneratorTarget::GetFortranModuleDirectory(
std::string const& working_dir) const
{
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index ff03914..788fa23 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -117,9 +117,6 @@ public:
struct KindedSources
{
std::vector<SourceAndKind> Sources;
- std::set<std::string> ExpectedResxHeaders;
- std::set<std::string> ExpectedXamlHeaders;
- std::set<std::string> ExpectedXamlSources;
bool Initialized = false;
};
@@ -137,6 +134,9 @@ public:
per-source configurations assigned. */
std::vector<AllConfigSource> const& GetAllConfigSources() const;
+ /** Get all sources needed for all configurations with given kind. */
+ std::vector<AllConfigSource> GetAllConfigSources(SourceKind kind) const;
+
/** Get all languages used to compile sources in any configuration.
This excludes the languages of objects from object libraries. */
std::set<std::string> GetAllConfigCompileLanguages() const;
@@ -151,8 +151,6 @@ public:
void GetModuleDefinitionSources(std::vector<cmSourceFile const*>&,
const std::string& config) const;
- void GetResxSources(std::vector<cmSourceFile const*>&,
- const std::string& config) const;
void GetExternalObjects(std::vector<cmSourceFile const*>&,
const std::string& config) const;
void GetHeaderSources(std::vector<cmSourceFile const*>&,
@@ -161,20 +159,8 @@ public:
const std::string& config) const;
void GetCustomCommands(std::vector<cmSourceFile const*>&,
const std::string& config) const;
- void GetExpectedResxHeaders(std::set<std::string>&,
- const std::string& config) const;
- void GetAppManifest(std::vector<cmSourceFile const*>&,
- const std::string& config) const;
void GetManifests(std::vector<cmSourceFile const*>&,
const std::string& config) const;
- void GetCertificates(std::vector<cmSourceFile const*>&,
- const std::string& config) const;
- void GetXamlSources(std::vector<cmSourceFile const*>&,
- const std::string& config) const;
- void GetExpectedXamlHeaders(std::set<std::string>&,
- const std::string& config) const;
- void GetExpectedXamlSources(std::set<std::string>&,
- const std::string& config) const;
std::set<cmLinkItem> const& GetUtilityItems() const;
@@ -245,7 +231,7 @@ public:
/** Get the full path to the target according to the settings in its
makefile and the configuration type. */
std::string GetFullPath(
- const std::string& config = "",
+ const std::string& config,
cmStateEnums::ArtifactType artifact = cmStateEnums::RuntimeBinaryArtifact,
bool realname = false) const;
std::string NormalGetFullPath(const std::string& config,
@@ -283,7 +269,7 @@ public:
/** Get the full name of the target according to the settings in its
makefile. */
- std::string GetFullName(const std::string& config = "",
+ std::string GetFullName(const std::string& config,
cmStateEnums::ArtifactType artifact =
cmStateEnums::RuntimeBinaryArtifact) const;
@@ -326,8 +312,7 @@ public:
std::string GetSOName(const std::string& config) const;
void GetFullNameComponents(std::string& prefix, std::string& base,
- std::string& suffix,
- const std::string& config = "",
+ std::string& suffix, const std::string& config,
cmStateEnums::ArtifactType artifact =
cmStateEnums::RuntimeBinaryArtifact) const;
@@ -540,7 +525,7 @@ public:
configuration name is given then the generator will add its
subdirectory for that configuration. Otherwise just the canonical
output directory is given. */
- std::string GetDirectory(const std::string& config = "",
+ std::string GetDirectory(const std::string& config,
cmStateEnums::ArtifactType artifact =
cmStateEnums::RuntimeBinaryArtifact) const;
@@ -548,7 +533,7 @@ public:
If the configuration name is given then the generator will add its
subdirectory for that configuration. Otherwise just the canonical
compiler pdb output directory is given. */
- std::string GetCompilePDBDirectory(const std::string& config = "") const;
+ std::string GetCompilePDBDirectory(const std::string& config) const;
/** Get sources that must be built before the given source. */
std::vector<cmSourceFile*> const* GetSourceDepends(
@@ -577,7 +562,7 @@ public:
std::string GetPDBOutputName(const std::string& config) const;
/** Get the name of the pdb file for the target. */
- std::string GetPDBName(const std::string& config = "") const;
+ std::string GetPDBName(const std::string& config) const;
/** Whether this library has soname enabled and platform supports it. */
bool HasSOName(const std::string& config) const;
@@ -595,10 +580,10 @@ public:
bool IsNullImpliedByLinkLibraries(const std::string& p) const;
/** Get the name of the compiler pdb file for the target. */
- std::string GetCompilePDBName(const std::string& config = "") const;
+ std::string GetCompilePDBName(const std::string& config) const;
/** Get the path for the MSVC /Fd option for this target. */
- std::string GetCompilePDBPath(const std::string& config = "") const;
+ std::string GetCompilePDBPath(const std::string& config) const;
// Get the target base name.
std::string GetOutputName(const std::string& config,
@@ -798,6 +783,9 @@ public:
const std::string& fallback_property,
int& major, int& minor, int& patch) const;
+ std::string GetRuntimeLinkLibrary(std::string const& lang,
+ std::string const& config) const;
+
std::string GetFortranModuleDirectory(std::string const& working_dir) const;
const std::string& GetSourcesProperty() const;
diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx
index cfad4c2..0b7ba04 100644
--- a/Source/cmGlobalGenerator.cxx
+++ b/Source/cmGlobalGenerator.cxx
@@ -2535,7 +2535,7 @@ void cmGlobalGenerator::AddGlobalTarget_EditCache(
}
GlobalTargetInfo gti;
gti.Name = editCacheTargetName;
- gti.PerConfig = false;
+ gti.PerConfig = cmTarget::PerConfig::No;
cmCustomCommandLine singleLine;
// Use generator preference for the edit_cache rule if it is defined.
@@ -2571,7 +2571,7 @@ void cmGlobalGenerator::AddGlobalTarget_RebuildCache(
gti.Name = rebuildCacheTargetName;
gti.Message = "Running CMake to regenerate build system...";
gti.UsesTerminal = true;
- gti.PerConfig = false;
+ gti.PerConfig = cmTarget::PerConfig::No;
cmCustomCommandLine singleLine;
singleLine.push_back(cmSystemTools::GetCMakeCommand());
singleLine.push_back("--regenerate-during-build");
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index dcd5a66..57c7808 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -553,7 +553,7 @@ protected:
std::vector<std::string> Depends;
std::string WorkingDir;
bool UsesTerminal = false;
- bool PerConfig = true;
+ cmTarget::PerConfig PerConfig = cmTarget::PerConfig::Yes;
bool StdPipesUTF8 = false;
};
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index b89fb8f..44e632f 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -415,6 +415,11 @@ public:
std::set<std::string> GetCrossConfigs(const std::string& config) const;
+ const std::set<std::string>& GetDefaultConfigs() const
+ {
+ return this->DefaultConfigs;
+ }
+
protected:
void Generate() override;
diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx
index 28bd1ca..0932d06 100644
--- a/Source/cmGlobalVisualStudioGenerator.cxx
+++ b/Source/cmGlobalVisualStudioGenerator.cxx
@@ -112,6 +112,7 @@ void cmGlobalVisualStudioGenerator::WriteSLNHeader(std::ostream& fout)
{
char utf8bom[] = { char(0xEF), char(0xBB), char(0xBF) };
fout.write(utf8bom, 3);
+ fout << '\n';
switch (this->Version) {
case cmGlobalVisualStudioGenerator::VS9:
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index f29c682..ad1cbd8 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -2633,7 +2633,9 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target)
// Exclude the pch files from linking
if (this->Makefile->IsOn("CMAKE_LINK_PCH")) {
if (!ReuseFrom) {
- pch_sf->SetProperty("OBJECT_OUTPUTS", pchFile.c_str());
+ pch_sf->AppendProperty(
+ "OBJECT_OUTPUTS",
+ cmStrCat("$<$<CONFIG:", config, ">:", pchFile, ">"));
} else {
auto reuseTarget =
this->GlobalGenerator->FindGeneratorTarget(*ReuseFrom);
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index d1944a4..e52e0d3 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -97,6 +97,43 @@ void cmLocalNinjaGenerator::Generate()
if (target->Target->IsPerConfig()) {
for (auto const& config : this->GetConfigNames()) {
tg->Generate(config);
+ if (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+ this->GetGlobalGenerator()->IsMultiConfig()) {
+ cmNinjaBuild phonyAlias("phony");
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(
+ target.get(), phonyAlias.Outputs, "");
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(
+ target.get(), phonyAlias.ExplicitDeps, config);
+ this->GetGlobalNinjaGenerator()->WriteBuild(
+ *this->GetGlobalNinjaGenerator()->GetConfigFileStream(config),
+ phonyAlias);
+ }
+ }
+ if (target->GetType() == cmStateEnums::GLOBAL_TARGET &&
+ this->GetGlobalGenerator()->IsMultiConfig()) {
+ if (!this->GetGlobalNinjaGenerator()->GetDefaultConfigs().empty()) {
+ cmNinjaBuild phonyAlias("phony");
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(
+ target.get(), phonyAlias.Outputs, "");
+ for (auto const& config :
+ this->GetGlobalNinjaGenerator()->GetDefaultConfigs()) {
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(
+ target.get(), phonyAlias.ExplicitDeps, config);
+ }
+ this->GetGlobalNinjaGenerator()->WriteBuild(
+ *this->GetGlobalNinjaGenerator()->GetDefaultFileStream(),
+ phonyAlias);
+ }
+ cmNinjaBuild phonyAlias("phony");
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(
+ target.get(), phonyAlias.Outputs, "all");
+ for (auto const& config : this->GetConfigNames()) {
+ this->GetGlobalNinjaGenerator()->AppendTargetOutputs(
+ target.get(), phonyAlias.ExplicitDeps, config);
+ }
+ this->GetGlobalNinjaGenerator()->WriteBuild(
+ *this->GetGlobalNinjaGenerator()->GetDefaultFileStream(),
+ phonyAlias);
}
} else {
tg->Generate("");
diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx
index 0b02724..5d50e2d 100644
--- a/Source/cmLocalVisualStudio7Generator.cxx
+++ b/Source/cmLocalVisualStudio7Generator.cxx
@@ -283,6 +283,7 @@ void cmLocalVisualStudio7Generator::WriteConfigurations(
}
cmVS7FlagTable cmLocalVisualStudio7GeneratorFortranFlagTable[] = {
{ "Preprocess", "fpp", "Run Preprocessor on files", "preprocessYes", 0 },
+ { "Preprocess", "nofpp", "Run Preprocessor on files", "preprocessNo", 0 },
{ "SuppressStartupBanner", "nologo", "SuppressStartupBanner", "true", 0 },
{ "SourceFileFormat", "fixed", "Use Fixed Format", "fileFormatFixed", 0 },
{ "SourceFileFormat", "free", "Use Free Format", "fileFormatFree", 0 },
@@ -681,6 +682,18 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(
default:
break;
}
+
+ switch (cmOutputConverter::GetFortranPreprocess(
+ target->GetSafeProperty("Fortran_PREPROCESS"))) {
+ case cmOutputConverter::FortranPreprocess::Needed:
+ flags += " -fpp";
+ break;
+ case cmOutputConverter::FortranPreprocess::NotNeeded:
+ flags += " -nofpp";
+ break;
+ default:
+ break;
+ }
}
// Get preprocessor definitions for this directory.
@@ -1473,6 +1486,20 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo(
}
if (lg->FortranProject) {
+ switch (cmOutputConverter::GetFortranPreprocess(
+ sf.GetSafeProperty("Fortran_PREPROCESS"))) {
+ case cmOutputConverter::FortranPreprocess::Needed:
+ fc.CompileFlags = cmStrCat("-fpp ", fc.CompileFlags);
+ needfc = true;
+ break;
+ case cmOutputConverter::FortranPreprocess::NotNeeded:
+ fc.CompileFlags = cmStrCat("-nofpp ", fc.CompileFlags);
+ needfc = true;
+ break;
+ default:
+ break;
+ }
+
switch (cmOutputConverter::GetFortranFormat(
sf.GetSafeProperty("Fortran_FORMAT"))) {
case cmOutputConverter::FortranFormatFixed:
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 6f05d45..154da50 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -2081,11 +2081,11 @@ cmTarget* cmMakefile::AddExecutable(const std::string& exeName,
cmTarget* cmMakefile::AddNewTarget(cmStateEnums::TargetType type,
const std::string& name)
{
- auto it =
- this->Targets
- .emplace(name,
- cmTarget(name, type, cmTarget::VisibilityNormal, this, true))
- .first;
+ auto it = this->Targets
+ .emplace(name,
+ cmTarget(name, type, cmTarget::VisibilityNormal, this,
+ cmTarget::PerConfig::Yes))
+ .first;
this->OrderedTargets.push_back(&it->second);
this->GetGlobalGenerator()->IndexTarget(&it->second);
this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name);
@@ -4261,7 +4261,7 @@ cmTarget* cmMakefile::AddImportedTarget(const std::string& name,
new cmTarget(name, type,
global ? cmTarget::VisibilityImportedGlobally
: cmTarget::VisibilityImported,
- this, true));
+ this, cmTarget::PerConfig::Yes));
// Add to the set of available imported targets.
this->ImportedTargets[name] = target.get();
diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx
index 5f0cfcf..c98e3a9 100644
--- a/Source/cmMakefileTargetGenerator.cxx
+++ b/Source/cmMakefileTargetGenerator.cxx
@@ -541,6 +541,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
// Add Fortran format flags.
if (lang == "Fortran") {
this->AppendFortranFormatFlags(flags, source);
+ this->AppendFortranPreprocessFlags(flags, source);
}
// Add flags from source file properties.
@@ -895,9 +896,14 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(
// Check for extra outputs created by the compilation.
std::vector<std::string> outputs(1, relativeObj);
if (cmProp extra_outputs_str = source.GetProperty("OBJECT_OUTPUTS")) {
- // Register these as extra files to clean.
- cmExpandList(*extra_outputs_str, outputs);
- this->CleanFiles.insert(outputs.begin() + 1, outputs.end());
+ std::string evaluated_outputs = cmGeneratorExpression::Evaluate(
+ *extra_outputs_str, this->LocalGenerator, config);
+
+ if (!evaluated_outputs.empty()) {
+ // Register these as extra files to clean.
+ cmExpandList(evaluated_outputs, outputs);
+ this->CleanFiles.insert(outputs.begin() + 1, outputs.end());
+ }
}
// Write the rule.
diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx
index db069ed..f87eba7 100644
--- a/Source/cmNinjaNormalTargetGenerator.cxx
+++ b/Source/cmNinjaNormalTargetGenerator.cxx
@@ -1024,7 +1024,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
std::string prefix;
std::string base;
std::string suffix;
- gt->GetFullNameComponents(prefix, base, suffix);
+ gt->GetFullNameComponents(prefix, base, suffix, config);
std::string dbg_suffix = ".dbg";
// TODO: Where to document?
if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) {
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index efd2fd5..c77a85b 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -106,7 +106,16 @@ std::string cmNinjaTargetGenerator::LanguagePreprocessRule(
std::string const& lang, const std::string& config) const
{
return cmStrCat(
- lang, "_PREPROCESS__",
+ lang, "_PREPROCESS_SCAN__",
+ cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
+ '_', config);
+}
+
+std::string cmNinjaTargetGenerator::LanguageDependencyRule(
+ std::string const& lang, const std::string& config) const
+{
+ return cmStrCat(
+ lang, "_SCAN__",
cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
'_', config);
}
@@ -183,6 +192,7 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
// Add Fortran format flags.
if (language == "Fortran") {
this->AppendFortranFormatFlags(flags, *source);
+ this->AppendFortranPreprocessFlags(flags, *source);
}
// Add source file specific flags.
@@ -508,6 +518,91 @@ void cmNinjaTargetGenerator::WriteLanguageRules(const std::string& language,
this->WriteCompileRule(language, config);
}
+namespace {
+// Create the command to run the dependency scanner
+std::string GetScanCommand(const std::string& cmakeCmd, const std::string& tdi,
+ const std::string& lang, const std::string& ppFile,
+ bool needDyndep, const std::string& ddiFile)
+{
+ std::string ccmd =
+ cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi, " --lang=", lang,
+ " --pp=", ppFile, " --dep=$DEP_FILE");
+ if (needDyndep) {
+ ccmd = cmStrCat(ccmd, " --obj=$OBJ_FILE --ddi=", ddiFile);
+ }
+ return ccmd;
+}
+
+// Helper function to create dependency scanning rule, with optional
+// explicit preprocessing step if preprocessCommand is non-empty
+cmNinjaRule GetPreprocessScanRule(
+ const std::string& ruleName, cmRulePlaceholderExpander::RuleVariables& vars,
+ const std::string& responseFlag, const std::string& flags,
+ const std::string& launcher,
+ cmRulePlaceholderExpander* const rulePlaceholderExpander,
+ std::string scanCommand, cmLocalNinjaGenerator* generator,
+ const std::string& preprocessCommand = "")
+{
+ cmNinjaRule rule(ruleName);
+ // Explicit preprocessing always uses a depfile.
+ rule.DepType = ""; // no deps= for multiple outputs
+ rule.DepFile = "$DEP_FILE";
+
+ cmRulePlaceholderExpander::RuleVariables ppVars;
+ ppVars.CMTargetName = vars.CMTargetName;
+ ppVars.CMTargetType = vars.CMTargetType;
+ ppVars.Language = vars.Language;
+ ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
+ ppVars.PreprocessedSource = "$out";
+ ppVars.DependencyFile = rule.DepFile.c_str();
+
+ // Preprocessing uses the original source, compilation uses
+ // preprocessed output or original source
+ ppVars.Source = vars.Source;
+ vars.Source = "$in";
+
+ // Copy preprocessor definitions to the preprocessor rule.
+ ppVars.Defines = vars.Defines;
+
+ // Copy include directories to the preprocessor rule. The Fortran
+ // compilation rule still needs them for the INCLUDE directive.
+ ppVars.Includes = vars.Includes;
+
+ // Preprocessing and compilation use the same flags.
+ std::string ppFlags = flags;
+
+ // If using a response file, move defines, includes, and flags into it.
+ if (!responseFlag.empty()) {
+ rule.RspFile = "$RSP_FILE";
+ rule.RspContent =
+ cmStrCat(' ', ppVars.Defines, ' ', ppVars.Includes, ' ', ppFlags);
+ ppFlags = cmStrCat(responseFlag, rule.RspFile);
+ ppVars.Defines = "";
+ ppVars.Includes = "";
+ }
+
+ ppVars.Flags = ppFlags.c_str();
+
+ // Rule for preprocessing source file.
+ std::vector<std::string> ppCmds;
+
+ if (!preprocessCommand.empty()) {
+ // Lookup the explicit preprocessing rule.
+ cmExpandList(preprocessCommand, ppCmds);
+ for (std::string& i : ppCmds) {
+ i = cmStrCat(launcher, i);
+ rulePlaceholderExpander->ExpandRuleVariables(generator, i, ppVars);
+ }
+ }
+
+ // Run CMake dependency scanner on either preprocessed output or source file
+ ppCmds.emplace_back(std::move(scanCommand));
+ rule.Command = generator->BuildCommandLine(ppCmds);
+
+ return rule;
+}
+}
+
void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
const std::string& config)
{
@@ -565,82 +660,42 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang,
cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
if (explicitPP) {
- cmNinjaRule rule(this->LanguagePreprocessRule(lang, config));
- // Explicit preprocessing always uses a depfile.
- rule.DepType = ""; // no deps= for multiple outputs
- rule.DepFile = "$DEP_FILE";
+ // Combined preprocessing and dependency scanning
+ const auto ppScanCommand = GetScanCommand(
+ cmakeCmd, tdi, lang, "$out", needDyndep, "$DYNDEP_INTERMEDIATE_FILE");
+ const auto ppVar = cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE");
- cmRulePlaceholderExpander::RuleVariables ppVars;
- ppVars.CMTargetName = vars.CMTargetName;
- ppVars.CMTargetType = vars.CMTargetType;
- ppVars.Language = vars.Language;
- ppVars.Object = "$out"; // for RULE_LAUNCH_COMPILE
- ppVars.PreprocessedSource = "$out";
- ppVars.DependencyFile = rule.DepFile.c_str();
+ auto ppRule = GetPreprocessScanRule(
+ this->LanguagePreprocessRule(lang, config), vars, responseFlag, flags,
+ launcher, rulePlaceholderExpander.get(), ppScanCommand,
+ this->GetLocalGenerator(), mf->GetRequiredDefinition(ppVar));
- // Preprocessing uses the original source,
- // compilation uses preprocessed output.
- ppVars.Source = vars.Source;
- vars.Source = "$in";
+ // Write the rule for preprocessing file of the given language.
+ ppRule.Comment = cmStrCat("Rule for preprocessing ", lang, " files.");
+ ppRule.Description = cmStrCat("Building ", lang, " preprocessed $out");
- // Preprocessing and compilation use the same flags.
- std::string ppFlags = flags;
+ this->GetGlobalGenerator()->AddRule(ppRule);
if (!compilePPWithDefines) {
- // Move preprocessor definitions to the preprocessor rule.
- ppVars.Defines = vars.Defines;
+ // Remove preprocessor definitions from compilation step
vars.Defines = "";
- } else {
- // Copy preprocessor definitions to the preprocessor rule.
- ppVars.Defines = vars.Defines;
}
- // Copy include directories to the preprocessor rule. The Fortran
- // compilation rule still needs them for the INCLUDE directive.
- ppVars.Includes = vars.Includes;
-
- // If using a response file, move defines, includes, and flags into it.
- if (!responseFlag.empty()) {
- rule.RspFile = "$RSP_FILE";
- rule.RspContent =
- cmStrCat(' ', ppVars.Defines, ' ', ppVars.Includes, ' ', ppFlags);
- ppFlags = cmStrCat(responseFlag, rule.RspFile);
- ppVars.Defines = "";
- ppVars.Includes = "";
- }
+ // Just dependency scanning for files that have preprocessing turned off
+ const auto scanCommand =
+ GetScanCommand(cmakeCmd, tdi, lang, "$in", needDyndep, "$out");
- ppVars.Flags = ppFlags.c_str();
+ auto scanRule = GetPreprocessScanRule(
+ this->LanguageDependencyRule(lang, config), vars, "", flags, launcher,
+ rulePlaceholderExpander.get(), scanCommand, this->GetLocalGenerator());
- // Rule for preprocessing source file.
- std::vector<std::string> ppCmds;
- {
- // Lookup the explicit preprocessing rule.
- std::string ppVar = cmStrCat("CMAKE_", lang, "_PREPROCESS_SOURCE");
- cmExpandList(this->GetMakefile()->GetRequiredDefinition(ppVar), ppCmds);
- }
+ // Write the rule for generating dependencies for the given language.
+ scanRule.Comment = cmStrCat("Rule for generating ", lang,
+ " dependencies on non-preprocessed files.");
+ scanRule.Description =
+ cmStrCat("Generating ", lang, " dependencies for $in");
- for (std::string& i : ppCmds) {
- i = cmStrCat(launcher, i);
- rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
- i, ppVars);
- }
-
- // Run CMake dependency scanner on preprocessed output.
- {
- std::string ccmd =
- cmStrCat(cmakeCmd, " -E cmake_ninja_depends --tdi=", tdi,
- " --lang=", lang, " --pp=$out --dep=$DEP_FILE");
- if (needDyndep) {
- ccmd += " --obj=$OBJ_FILE --ddi=$DYNDEP_INTERMEDIATE_FILE";
- }
- ppCmds.emplace_back(std::move(ccmd));
- }
- rule.Command = this->GetLocalGenerator()->BuildCommandLine(ppCmds);
-
- // Write the rule for preprocessing file of the given language.
- rule.Comment = cmStrCat("Rule for preprocessing ", lang, " files.");
- rule.Description = cmStrCat("Building ", lang, " preprocessed $out");
- this->GetGlobalGenerator()->AddRule(rule);
+ this->GetGlobalGenerator()->AddRule(scanRule);
}
if (needDyndep) {
@@ -996,6 +1051,82 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements(
}
}
+namespace {
+cmNinjaBuild GetPreprocessOrScanBuild(
+ const std::string& ruleName, const std::string& ppFileName, bool compilePP,
+ bool compilePPWithDefines, cmNinjaBuild& objBuild, cmNinjaVars& vars,
+ const std::string& depFileName, bool needDyndep,
+ const std::string& objectFileName)
+{
+ // Explicit preprocessing and dependency
+ cmNinjaBuild ppBuild(ruleName);
+
+ if (!ppFileName.empty()) {
+ ppBuild.Outputs.push_back(ppFileName);
+ ppBuild.RspFile = cmStrCat(ppFileName, ".rsp");
+ } else {
+ ppBuild.RspFile = "$out.rsp";
+ }
+
+ if (compilePP) {
+ // Move compilation dependencies to the preprocessing build statement.
+ std::swap(ppBuild.ExplicitDeps, objBuild.ExplicitDeps);
+ std::swap(ppBuild.ImplicitDeps, objBuild.ImplicitDeps);
+ std::swap(ppBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps);
+ std::swap(ppBuild.Variables["IN_ABS"], vars["IN_ABS"]);
+
+ // The actual compilation will now use the preprocessed source.
+ objBuild.ExplicitDeps.push_back(ppFileName);
+ } else {
+ // Copy compilation dependencies to the preprocessing build statement.
+ ppBuild.ExplicitDeps = objBuild.ExplicitDeps;
+ ppBuild.ImplicitDeps = objBuild.ImplicitDeps;
+ ppBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps;
+ ppBuild.Variables["IN_ABS"] = vars["IN_ABS"];
+ }
+
+ // Preprocessing and compilation generally use the same flags.
+ ppBuild.Variables["FLAGS"] = vars["FLAGS"];
+
+ if (compilePP && !compilePPWithDefines) {
+ // Move preprocessor definitions to the preprocessor build statement.
+ std::swap(ppBuild.Variables["DEFINES"], vars["DEFINES"]);
+ } else {
+ // Copy preprocessor definitions to the preprocessor build statement.
+ ppBuild.Variables["DEFINES"] = vars["DEFINES"];
+ }
+
+ // Copy include directories to the preprocessor build statement. The
+ // Fortran compilation build statement still needs them for the INCLUDE
+ // directive.
+ ppBuild.Variables["INCLUDES"] = vars["INCLUDES"];
+
+ // Explicit preprocessing always uses a depfile.
+ ppBuild.Variables["DEP_FILE"] = depFileName;
+ if (compilePP) {
+ // The actual compilation does not need a depfile because it
+ // depends on the already-preprocessed source.
+ vars.erase("DEP_FILE");
+ }
+
+ if (needDyndep) {
+ // Tell dependency scanner the object file that will result from
+ // compiling the source.
+ ppBuild.Variables["OBJ_FILE"] = objectFileName;
+
+ // Tell dependency scanner where to store dyndep intermediate results.
+ std::string const ddiFile = cmStrCat(objectFileName, ".ddi");
+ if (ppFileName.empty()) {
+ ppBuild.Outputs.push_back(ddiFile);
+ } else {
+ ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
+ ppBuild.ImplicitOuts.push_back(ddiFile);
+ }
+ }
+ return ppBuild;
+}
+}
+
void cmNinjaTargetGenerator::WriteObjectBuildStatement(
cmSourceFile const* source, const std::string& config,
const std::string& fileConfig, bool firstForConfig)
@@ -1134,36 +1265,39 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
// For some cases we do an explicit preprocessor invocation.
bool const explicitPP = this->NeedExplicitPreprocessing(language);
if (explicitPP) {
- cmNinjaBuild ppBuild(this->LanguagePreprocessRule(language, config));
- std::string const ppFileName =
- this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source, config));
- ppBuild.Outputs.push_back(ppFileName);
-
- ppBuild.RspFile = cmStrCat(ppFileName, ".rsp");
+ // If source/target has preprocessing turned off, we still need to
+ // generate an explicit dependency step
+ const auto srcpp = source->GetSafeProperty("Fortran_PREPROCESS");
+ cmOutputConverter::FortranPreprocess preprocess =
+ cmOutputConverter::GetFortranPreprocess(srcpp);
+ if (preprocess == cmOutputConverter::FortranPreprocess::Unset) {
+ const auto& tgtpp =
+ this->GeneratorTarget->GetSafeProperty("Fortran_PREPROCESS");
+ preprocess = cmOutputConverter::GetFortranPreprocess(tgtpp);
+ }
- bool const compilePP = this->UsePreprocessedSource(language);
+ bool const compilePP = this->UsePreprocessedSource(language) &&
+ (preprocess != cmOutputConverter::FortranPreprocess::NotNeeded);
bool const compilePPWithDefines =
compilePP && this->CompilePreprocessedSourceWithDefines(language);
- if (compilePP) {
- // Move compilation dependencies to the preprocessing build statement.
- std::swap(ppBuild.ExplicitDeps, objBuild.ExplicitDeps);
- std::swap(ppBuild.ImplicitDeps, objBuild.ImplicitDeps);
- std::swap(ppBuild.OrderOnlyDeps, objBuild.OrderOnlyDeps);
- std::swap(ppBuild.Variables["IN_ABS"], vars["IN_ABS"]);
-
- // The actual compilation will now use the preprocessed source.
- objBuild.ExplicitDeps.push_back(ppFileName);
- } else {
- // Copy compilation dependencies to the preprocessing build statement.
- ppBuild.ExplicitDeps = objBuild.ExplicitDeps;
- ppBuild.ImplicitDeps = objBuild.ImplicitDeps;
- ppBuild.OrderOnlyDeps = objBuild.OrderOnlyDeps;
- ppBuild.Variables["IN_ABS"] = vars["IN_ABS"];
- }
- // Preprocessing and compilation generally use the same flags.
- ppBuild.Variables["FLAGS"] = vars["FLAGS"];
+ std::string const ppFileName = compilePP
+ ? this->ConvertToNinjaPath(this->GetPreprocessedFilePath(source, config))
+ : "";
+
+ std::string const buildName = compilePP
+ ? this->LanguagePreprocessRule(language, config)
+ : this->LanguageDependencyRule(language, config);
+
+ const auto depExtension = compilePP ? ".pp.d" : ".d";
+ const std::string depFileName =
+ this->GetLocalGenerator()->ConvertToOutputFormat(
+ cmStrCat(objectFileName, depExtension), cmOutputConverter::SHELL);
+
+ cmNinjaBuild ppBuild = GetPreprocessOrScanBuild(
+ buildName, ppFileName, compilePP, compilePPWithDefines, objBuild, vars,
+ depFileName, needDyndep, objectFileName);
if (compilePP) {
// In case compilation requires flags that are incompatible with
@@ -1171,22 +1305,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
std::string const& postFlag = this->Makefile->GetSafeDefinition(
cmStrCat("CMAKE_", language, "_POSTPROCESS_FLAG"));
this->LocalGenerator->AppendFlags(vars["FLAGS"], postFlag);
- }
-
- if (compilePP && !compilePPWithDefines) {
- // Move preprocessor definitions to the preprocessor build statement.
- std::swap(ppBuild.Variables["DEFINES"], vars["DEFINES"]);
- } else {
- // Copy preprocessor definitions to the preprocessor build statement.
- ppBuild.Variables["DEFINES"] = vars["DEFINES"];
- }
-
- // Copy include directories to the preprocessor build statement. The
- // Fortran compilation build statement still needs them for the INCLUDE
- // directive.
- ppBuild.Variables["INCLUDES"] = vars["INCLUDES"];
- if (compilePP) {
// Prepend source file's original directory as an include directory
// so e.g. Fortran INCLUDE statements can look for files in it.
std::vector<std::string> sourceDirectory;
@@ -1200,28 +1319,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
vars["INCLUDES"] = cmStrCat(sourceDirectoryFlag, ' ', vars["INCLUDES"]);
}
- // Explicit preprocessing always uses a depfile.
- ppBuild.Variables["DEP_FILE"] =
- this->GetLocalGenerator()->ConvertToOutputFormat(
- cmStrCat(objectFileName, ".pp.d"), cmOutputConverter::SHELL);
- if (compilePP) {
- // The actual compilation does not need a depfile because it
- // depends on the already-preprocessed source.
- vars.erase("DEP_FILE");
- }
-
- if (needDyndep) {
- // Tell dependency scanner the object file that will result from
- // compiling the source.
- ppBuild.Variables["OBJ_FILE"] = objectFileName;
-
- // Tell dependency scanner where to store dyndep intermediate results.
+ if (firstForConfig && needDyndep) {
std::string const ddiFile = cmStrCat(objectFileName, ".ddi");
- ppBuild.Variables["DYNDEP_INTERMEDIATE_FILE"] = ddiFile;
- ppBuild.ImplicitOuts.push_back(ddiFile);
- if (firstForConfig) {
- this->Configs[config].DDIFiles[language].push_back(ddiFile);
- }
+ this->Configs[config].DDIFiles[language].push_back(ddiFile);
}
this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
@@ -1266,14 +1366,19 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
}
if (cmProp objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) {
- cmNinjaBuild build("phony");
- build.Comment = "Additional output files.";
- build.Outputs = cmExpandedList(*objectOutputs);
- std::transform(build.Outputs.begin(), build.Outputs.end(),
- build.Outputs.begin(), MapToNinjaPath());
- build.ExplicitDeps = objBuild.Outputs;
- this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig),
- build);
+ std::string evaluatedObjectOutputs = cmGeneratorExpression::Evaluate(
+ *objectOutputs, this->LocalGenerator, config);
+
+ if (!evaluatedObjectOutputs.empty()) {
+ cmNinjaBuild build("phony");
+ build.Comment = "Additional output files.";
+ build.Outputs = cmExpandedList(evaluatedObjectOutputs);
+ std::transform(build.Outputs.begin(), build.Outputs.end(),
+ build.Outputs.begin(), MapToNinjaPath());
+ build.ExplicitDeps = objBuild.Outputs;
+ this->GetGlobalGenerator()->WriteBuild(
+ this->GetImplFileStream(fileConfig), build);
+ }
}
}
diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h
index 1ac5683..8d4372e 100644
--- a/Source/cmNinjaTargetGenerator.h
+++ b/Source/cmNinjaTargetGenerator.h
@@ -70,6 +70,8 @@ protected:
const std::string& config) const;
std::string LanguagePreprocessRule(std::string const& lang,
const std::string& config) const;
+ std::string LanguageDependencyRule(std::string const& lang,
+ const std::string& config) const;
bool NeedExplicitPreprocessing(std::string const& lang) const;
std::string LanguageDyndepRule(std::string const& lang,
const std::string& config) const;
diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx
index 134924e..b0b7953 100644
--- a/Source/cmNinjaUtilityTargetGenerator.cxx
+++ b/Source/cmNinjaUtilityTargetGenerator.cxx
@@ -160,10 +160,5 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config)
// be per-directory and have one at the top-level anyway.
if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
gg->AddTargetAlias(this->GetTargetName(), genTarget, config);
- } else if (gg->IsMultiConfig() && genTarget->Target->IsPerConfig()) {
- cmNinjaBuild phonyAlias("phony");
- gg->AppendTargetOutputs(genTarget, phonyAlias.Outputs, "");
- phonyAlias.ExplicitDeps = phonyBuild.Outputs;
- gg->WriteBuild(this->GetImplFileStream(config), phonyAlias);
}
}
diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx
index dc324cc..359e9f5 100644
--- a/Source/cmOutputConverter.cxx
+++ b/Source/cmOutputConverter.cxx
@@ -170,6 +170,17 @@ cmOutputConverter::FortranFormat cmOutputConverter::GetFortranFormat(
return format;
}
+cmOutputConverter::FortranPreprocess cmOutputConverter::GetFortranPreprocess(
+ cm::string_view value)
+{
+ if (value.empty()) {
+ return FortranPreprocess::Unset;
+ }
+
+ return cmIsOn(value) ? FortranPreprocess::Needed
+ : FortranPreprocess::NotNeeded;
+}
+
void cmOutputConverter::SetLinkScriptShell(bool linkScriptShell)
{
this->LinkScriptShell = linkScriptShell;
diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h
index 28582df..a8b4528 100644
--- a/Source/cmOutputConverter.h
+++ b/Source/cmOutputConverter.h
@@ -95,6 +95,14 @@ public:
};
static FortranFormat GetFortranFormat(cm::string_view value);
+ enum class FortranPreprocess
+ {
+ Unset,
+ NotNeeded,
+ Needed
+ };
+ static FortranPreprocess GetFortranPreprocess(cm::string_view value);
+
private:
cmState* GetState() const;
diff --git a/Source/cmPropertyDefinition.cxx b/Source/cmPropertyDefinition.cxx
index c8efaf6..1796bb8 100644
--- a/Source/cmPropertyDefinition.cxx
+++ b/Source/cmPropertyDefinition.cxx
@@ -2,17 +2,38 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmPropertyDefinition.h"
-#include <utility>
+#include <tuple>
-cmPropertyDefinition::cmPropertyDefinition(std::string name,
- cmProperty::ScopeType scope,
- std::string shortDescription,
+cmPropertyDefinition::cmPropertyDefinition(std::string shortDescription,
std::string fullDescription,
- bool chain)
- : Name(std::move(name))
- , ShortDescription(std::move(shortDescription))
+ bool chained)
+ : ShortDescription(std::move(shortDescription))
, FullDescription(std::move(fullDescription))
- , Scope(scope)
- , Chained(chain)
+ , Chained(chained)
{
}
+
+void cmPropertyDefinitionMap::DefineProperty(
+ const std::string& name, cmProperty::ScopeType scope,
+ const std::string& ShortDescription, const std::string& FullDescription,
+ bool chain)
+{
+ auto it = this->Map_.find(key_type(name, scope));
+ if (it == this->Map_.end()) {
+ // try_emplace() since C++17
+ this->Map_.emplace(
+ std::piecewise_construct, std::forward_as_tuple(name, scope),
+ std::forward_as_tuple(ShortDescription, FullDescription, chain));
+ }
+}
+
+cmPropertyDefinition const* cmPropertyDefinitionMap::GetPropertyDefinition(
+ const std::string& name, cmProperty::ScopeType scope) const
+{
+ auto it = this->Map_.find(key_type(name, scope));
+ if (it != this->Map_.end()) {
+ return &it->second;
+ }
+
+ return nullptr;
+}
diff --git a/Source/cmPropertyDefinition.h b/Source/cmPropertyDefinition.h
index d2e4467..f83bc4f 100644
--- a/Source/cmPropertyDefinition.h
+++ b/Source/cmPropertyDefinition.h
@@ -5,7 +5,9 @@
#include "cmConfigure.h" // IWYU pragma: keep
+#include <map>
#include <string>
+#include <utility>
#include "cmProperty.h"
@@ -13,25 +15,19 @@
* \brief Property meta-information
*
* This class contains the following meta-information about property:
- * - Name;
* - Various documentation strings;
- * - The scope of the property;
* - If the property is chained.
*/
class cmPropertyDefinition
{
public:
/// Constructor
- cmPropertyDefinition(std::string name, cmProperty::ScopeType scope,
- std::string ShortDescription,
- std::string FullDescription, bool chained = false);
+ cmPropertyDefinition(std::string shortDescription,
+ std::string fullDescription, bool chained);
/// Is the property chained?
bool IsChained() const { return this->Chained; }
- /// Get the scope
- cmProperty::ScopeType GetScope() const { return this->Scope; }
-
/// Get the documentation (short version)
const std::string& GetShortDescription() const
{
@@ -44,12 +40,30 @@ public:
return this->FullDescription;
}
-protected:
- std::string Name;
+private:
std::string ShortDescription;
std::string FullDescription;
- cmProperty::ScopeType Scope;
bool Chained;
};
+/** \class cmPropertyDefinitionMap
+ * \brief Map property name and scope to their definition
+ */
+class cmPropertyDefinitionMap
+{
+public:
+ // define the property
+ void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
+ const std::string& ShortDescription,
+ const std::string& FullDescription, bool chain);
+
+ // get the property definition if present, otherwise nullptr
+ cmPropertyDefinition const* GetPropertyDefinition(
+ const std::string& name, cmProperty::ScopeType scope) const;
+
+private:
+ using key_type = std::pair<std::string, cmProperty::ScopeType>;
+ std::map<key_type, cmPropertyDefinition> Map_;
+};
+
#endif
diff --git a/Source/cmPropertyDefinitionMap.cxx b/Source/cmPropertyDefinitionMap.cxx
deleted file mode 100644
index 614d5a4..0000000
--- a/Source/cmPropertyDefinitionMap.cxx
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmPropertyDefinitionMap.h"
-
-#include <tuple>
-#include <utility>
-
-void cmPropertyDefinitionMap::DefineProperty(
- const std::string& name, cmProperty::ScopeType scope,
- const std::string& ShortDescription, const std::string& FullDescription,
- bool chain)
-{
- auto it = this->find(name);
- if (it == this->end()) {
- // try_emplace() since C++17
- this->emplace(std::piecewise_construct, std::forward_as_tuple(name),
- std::forward_as_tuple(name, scope, ShortDescription,
- FullDescription, chain));
- }
-}
-
-bool cmPropertyDefinitionMap::IsPropertyDefined(const std::string& name) const
-{
- return this->find(name) != this->end();
-}
-
-bool cmPropertyDefinitionMap::IsPropertyChained(const std::string& name) const
-{
- auto it = this->find(name);
- if (it == this->end()) {
- return false;
- }
-
- return it->second.IsChained();
-}
diff --git a/Source/cmPropertyDefinitionMap.h b/Source/cmPropertyDefinitionMap.h
deleted file mode 100644
index 2ae6efb..0000000
--- a/Source/cmPropertyDefinitionMap.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#ifndef cmPropertyDefinitionMap_h
-#define cmPropertyDefinitionMap_h
-
-#include "cmConfigure.h" // IWYU pragma: keep
-
-#include <map>
-#include <string>
-
-#include "cmProperty.h"
-#include "cmPropertyDefinition.h"
-
-class cmPropertyDefinitionMap
- : public std::map<std::string, cmPropertyDefinition>
-{
-public:
- // define the property
- void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
- const std::string& ShortDescription,
- const std::string& FullDescription, bool chain);
-
- // has a named property been defined
- bool IsPropertyDefined(const std::string& name) const;
-
- // is a named property set to chain
- bool IsPropertyChained(const std::string& name) const;
-};
-
-#endif
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index df013f4..18d8537 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -265,7 +265,7 @@ void cmState::RemoveCacheEntryProperty(std::string const& key,
cmStateSnapshot cmState::Reset()
{
this->GlobalProperties.Clear();
- this->PropertyDefinitions.clear();
+ this->PropertyDefinitions = {};
this->GlobVerificationManager->Reset();
cmStateDetail::PositionType pos = this->SnapshotData.Truncate();
@@ -331,39 +331,23 @@ void cmState::DefineProperty(const std::string& name,
const std::string& ShortDescription,
const std::string& FullDescription, bool chained)
{
- this->PropertyDefinitions[scope].DefineProperty(
- name, scope, ShortDescription, FullDescription, chained);
+ this->PropertyDefinitions.DefineProperty(name, scope, ShortDescription,
+ FullDescription, chained);
}
cmPropertyDefinition const* cmState::GetPropertyDefinition(
const std::string& name, cmProperty::ScopeType scope) const
{
- if (this->IsPropertyDefined(name, scope)) {
- cmPropertyDefinitionMap const& defs =
- this->PropertyDefinitions.find(scope)->second;
- return &defs.find(name)->second;
- }
- return nullptr;
-}
-
-bool cmState::IsPropertyDefined(const std::string& name,
- cmProperty::ScopeType scope) const
-{
- auto it = this->PropertyDefinitions.find(scope);
- if (it == this->PropertyDefinitions.end()) {
- return false;
- }
- return it->second.IsPropertyDefined(name);
+ return this->PropertyDefinitions.GetPropertyDefinition(name, scope);
}
bool cmState::IsPropertyChained(const std::string& name,
cmProperty::ScopeType scope) const
{
- auto it = this->PropertyDefinitions.find(scope);
- if (it == this->PropertyDefinitions.end()) {
- return false;
+ if (auto def = this->GetPropertyDefinition(name, scope)) {
+ return def->IsChained();
}
- return it->second.IsPropertyChained(name);
+ return false;
}
void cmState::SetLanguageEnabled(std::string const& l)
diff --git a/Source/cmState.h b/Source/cmState.h
index e966935..f2bd32a 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -17,7 +17,7 @@
#include "cmListFileCache.h"
#include "cmPolicies.h"
#include "cmProperty.h"
-#include "cmPropertyDefinitionMap.h"
+#include "cmPropertyDefinition.h"
#include "cmPropertyMap.h"
#include "cmStatePrivate.h"
#include "cmStateTypes.h"
@@ -25,7 +25,6 @@
class cmCacheManager;
class cmCommand;
class cmGlobVerificationManager;
-class cmPropertyDefinition;
class cmStateSnapshot;
class cmMessenger;
class cmExecutionStatus;
@@ -131,9 +130,6 @@ public:
cmPropertyDefinition const* GetPropertyDefinition(
const std::string& name, cmProperty::ScopeType scope) const;
- // Is a property defined?
- bool IsPropertyDefined(const std::string& name,
- cmProperty::ScopeType scope) const;
bool IsPropertyChained(const std::string& name,
cmProperty::ScopeType scope) const;
@@ -225,7 +221,7 @@ private:
const std::string& variable,
cmListFileBacktrace const& bt);
- std::map<cmProperty::ScopeType, cmPropertyDefinitionMap> PropertyDefinitions;
+ cmPropertyDefinitionMap PropertyDefinitions;
std::vector<std::string> EnabledLanguages;
std::map<std::string, Command> BuiltinCommands;
std::map<std::string, Command> ScriptedCommands;
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index d43fbe5..4bb48fb 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -215,7 +215,7 @@ public:
};
cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
- Visibility vis, cmMakefile* mf, bool perConfig)
+ Visibility vis, cmMakefile* mf, PerConfig perConfig)
: impl(cm::make_unique<cmTargetInternals>())
{
assert(mf);
@@ -231,7 +231,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
(vis == VisibilityImported || vis == VisibilityImportedGlobally);
impl->ImportedGloballyVisible = vis == VisibilityImportedGlobally;
impl->BuildInterfaceIncludesAppended = false;
- impl->PerConfig = perConfig;
+ impl->PerConfig = (perConfig == PerConfig::Yes);
// Check whether this is a DLL platform.
impl->IsDLLPlatform =
@@ -307,6 +307,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
initProp("Fortran_FORMAT");
initProp("Fortran_MODULE_DIRECTORY");
initProp("Fortran_COMPILER_LAUNCHER");
+ initProp("Fortran_PREPROCESS");
initProp("GNUtoMS");
initProp("OSX_ARCHITECTURES");
initProp("IOS_INSTALL_COMBINED");
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 8fecd41..6bd47f7 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -45,8 +45,14 @@ public:
VisibilityImportedGlobally
};
+ enum class PerConfig
+ {
+ Yes,
+ No
+ };
+
cmTarget(std::string const& name, cmStateEnums::TargetType type,
- Visibility vis, cmMakefile* mf, bool perConfig);
+ Visibility vis, cmMakefile* mf, PerConfig perConfig);
cmTarget(cmTarget const&) = delete;
cmTarget(cmTarget&&) noexcept;
diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx
index 025a7b3..4e41993 100644
--- a/Source/cmTestGenerator.cxx
+++ b/Source/cmTestGenerator.cxx
@@ -76,7 +76,7 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
cmGeneratorExpression ge(this->Test->GetBacktrace());
// Start the test command.
- os << indent << "add_test(" << this->Test->GetName() << " ";
+ os << indent << "add_test(\"" << this->Test->GetName() << "\" ";
// Evaluate command line arguments
std::vector<std::string> argv =
@@ -126,8 +126,8 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
os << ")\n";
// Output properties for the test.
- os << indent << "set_tests_properties(" << this->Test->GetName()
- << " PROPERTIES ";
+ os << indent << "set_tests_properties(\"" << this->Test->GetName()
+ << "\" PROPERTIES ";
for (auto const& i : this->Test->GetProperties().GetList()) {
os << " " << i.first << " "
<< cmOutputConverter::EscapeForCMake(
@@ -139,7 +139,8 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os,
void cmTestGenerator::GenerateScriptNoConfig(std::ostream& os, Indent indent)
{
- os << indent << "add_test(" << this->Test->GetName() << " NOT_AVAILABLE)\n";
+ os << indent << "add_test(\"" << this->Test->GetName()
+ << "\" NOT_AVAILABLE)\n";
}
bool cmTestGenerator::NeedsScriptNoConfig() const
@@ -159,9 +160,8 @@ void cmTestGenerator::GenerateOldStyle(std::ostream& fout, Indent indent)
std::string exe = command[0];
cmSystemTools::ConvertToUnixSlashes(exe);
- fout << indent;
- fout << "add_test(";
- fout << this->Test->GetName() << " \"" << exe << "\"";
+ fout << indent << "add_test(\"" << this->Test->GetName() << "\" \"" << exe
+ << "\"";
for (std::string const& arg : cmMakeRange(command).advance(1)) {
// Just double-quote all arguments so they are re-parsed
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index 93c09fe..de88182 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -248,6 +248,7 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator(
this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget);
this->InSourceBuild = (this->Makefile->GetCurrentSourceDirectory() ==
this->Makefile->GetCurrentBinaryDirectory());
+ this->ClassifyAllConfigSources();
}
cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator()
@@ -921,13 +922,11 @@ void cmVisualStudio10TargetGenerator::WriteDotNetDocumentationFile(Elem& e0)
void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0)
{
- std::vector<cmSourceFile const*> resxObjs;
- this->GeneratorTarget->GetResxSources(resxObjs, "");
- if (!resxObjs.empty()) {
+ if (!this->ResxObjs.empty()) {
Elem e1(e0, "ItemGroup");
std::string srcDir = this->Makefile->GetCurrentSourceDirectory();
ConvertToWindowsSlash(srcDir);
- for (cmSourceFile const* oi : resxObjs) {
+ for (cmSourceFile const* oi : this->ResxObjs) {
std::string obj = oi->GetFullPath();
ConvertToWindowsSlash(obj);
bool useRelativePath = false;
@@ -1016,11 +1015,9 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0)
void cmVisualStudio10TargetGenerator::WriteXamlFilesGroup(Elem& e0)
{
- std::vector<cmSourceFile const*> xamlObjs;
- this->GeneratorTarget->GetXamlSources(xamlObjs, "");
- if (!xamlObjs.empty()) {
+ if (!this->XamlObjs.empty()) {
Elem e1(e0, "ItemGroup");
- for (cmSourceFile const* oi : xamlObjs) {
+ for (cmSourceFile const* oi : this->XamlObjs) {
std::string obj = oi->GetFullPath();
std::string xamlType;
cmProp xamlTypeProperty = oi->GetProperty("VS_XAML_TYPE");
@@ -1329,21 +1326,27 @@ void cmVisualStudio10TargetGenerator::WriteNsightTegraConfigurationValues(
void cmVisualStudio10TargetGenerator::WriteCustomCommands(Elem& e0)
{
this->CSharpCustomCommandNames.clear();
- std::vector<cmSourceFile const*> customCommands;
- this->GeneratorTarget->GetCustomCommands(customCommands, "");
- for (cmSourceFile const* si : customCommands) {
- this->WriteCustomCommand(e0, si);
+
+ cmSourceFile const* srcCMakeLists =
+ this->LocalGenerator->CreateVCProjBuildRule();
+
+ for (cmGeneratorTarget::AllConfigSource const& si :
+ this->GeneratorTarget->GetAllConfigSources()) {
+ if (si.Source == srcCMakeLists) {
+ // Skip explicit reference to CMakeLists.txt source.
+ continue;
+ }
+ this->WriteCustomCommand(e0, si.Source);
}
// Add CMakeLists.txt file with rule to re-run CMake for user convenience.
if (this->GeneratorTarget->GetType() != cmStateEnums::GLOBAL_TARGET &&
this->GeneratorTarget->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) {
- if (cmSourceFile const* sf =
- this->LocalGenerator->CreateVCProjBuildRule()) {
+ if (srcCMakeLists) {
// Write directly rather than through WriteCustomCommand because
// we do not want the de-duplication and it has no dependencies.
- if (cmCustomCommand const* command = sf->GetCustomCommand()) {
- this->WriteCustomRule(e0, sf, *command);
+ if (cmCustomCommand const* command = srcCMakeLists->GetCustomCommand()) {
+ this->WriteCustomRule(e0, srcCMakeLists, *command);
}
}
}
@@ -1624,11 +1627,9 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
}
}
- std::vector<cmSourceFile const*> resxObjs;
- this->GeneratorTarget->GetResxSources(resxObjs, "");
- if (!resxObjs.empty()) {
+ if (!this->ResxObjs.empty()) {
Elem e1(e0, "ItemGroup");
- for (cmSourceFile const* oi : resxObjs) {
+ for (cmSourceFile const* oi : this->ResxObjs) {
std::string obj = oi->GetFullPath();
ConvertToWindowsSlash(obj);
Elem e2(e1, "EmbeddedResource");
@@ -1656,7 +1657,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups()
}
}
- if (!resxObjs.empty() || !this->AddedFiles.empty()) {
+ if (!this->ResxObjs.empty() || !this->AddedFiles.empty()) {
std::string guidName = "SG_Filter_Resource Files";
std::string guid = this->GlobalGenerator->GetGUID(guidName);
Elem e2(e1, "Filter");
@@ -2209,10 +2210,10 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0)
}
} break;
case cmGeneratorTarget::SourceKindResx:
- // Handled elsewhere.
+ this->ResxObjs.push_back(si.Source);
break;
case cmGeneratorTarget::SourceKindXaml:
- // Handled elsewhere.
+ this->XamlObjs.push_back(si.Source);
break;
}
@@ -2317,21 +2318,13 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
cmGeneratorExpression::Find(*cincludes) != std::string::npos;
includes += *cincludes;
}
- std::string lang =
- this->GlobalGenerator->GetLanguageFromExtension(sf.GetExtension().c_str());
- std::string sourceLang = this->LocalGenerator->GetSourceFileLanguage(sf);
- const std::string& linkLanguage =
- this->GeneratorTarget->GetLinkerLanguage("");
- bool needForceLang = false;
- // source file does not match its extension language
- if (lang != sourceLang) {
- needForceLang = true;
- lang = sourceLang;
- }
- // if the source file does not match the linker language
- // then force c or c++
+
+ // Force language if the file extension does not match.
+ std::string lang = this->LocalGenerator->GetSourceFileLanguage(sf);
const char* compileAs = 0;
- if (needForceLang || (linkLanguage != lang)) {
+ if (lang !=
+ this->GlobalGenerator->GetLanguageFromExtension(
+ sf.GetExtension().c_str())) {
if (lang == "CXX") {
// force a C++ file type
compileAs = "CompileAsCpp";
@@ -2340,6 +2333,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags(
compileAs = "CompileAsC";
}
}
+
bool noWinRT = this->TargetCompileAsWinRT && lang == "C";
// for the first time we need a new line if there is something
// produced here.
@@ -2736,13 +2730,6 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions(
this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget,
langForClCompile, configName);
}
- // set the correct language
- if (linkLanguage == "C") {
- clOptions.AddFlag("CompileAs", "CompileAsC");
- }
- if (linkLanguage == "CXX") {
- clOptions.AddFlag("CompileAs", "CompileAsCpp");
- }
// Put the IPO enabled configurations into a set.
if (this->GeneratorTarget->IsIPOEnabled(linkLanguage, configName)) {
@@ -3143,6 +3130,17 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions(
cudaOptions.AddIncludes(this->GetIncludes(configName, "CUDA"));
cudaOptions.AddFlag("UseHostInclude", "false");
+ // Add runtime library selection flag.
+ std::string const& cudaRuntime =
+ this->GeneratorTarget->GetRuntimeLinkLibrary("CUDA", configName);
+ if (cudaRuntime == "STATIC") {
+ cudaOptions.AddFlag("CudaRuntime", "Static");
+ } else if (cudaRuntime == "SHARED") {
+ cudaOptions.AddFlag("CudaRuntime", "Shared");
+ } else if (cudaRuntime == "NONE") {
+ cudaOptions.AddFlag("CudaRuntime", "None");
+ }
+
this->CudaOptions[configName] = std::move(pOptions);
return true;
}
@@ -3493,12 +3491,12 @@ void cmVisualStudio10TargetGenerator::WriteAntBuildOptions(
// its location as the root source directory.
std::string rootDir = this->LocalGenerator->GetCurrentSourceDirectory();
{
- std::vector<cmSourceFile const*> extraSources;
- this->GeneratorTarget->GetExtraSources(extraSources, "");
- for (cmSourceFile const* si : extraSources) {
- if ("androidmanifest.xml" ==
- cmSystemTools::LowerCase(si->GetLocation().GetName())) {
- rootDir = si->GetLocation().GetDirectory();
+ for (cmGeneratorTarget::AllConfigSource const& source :
+ this->GeneratorTarget->GetAllConfigSources()) {
+ if (source.Kind == cmGeneratorTarget::SourceKindExtra &&
+ "androidmanifest.xml" ==
+ cmSystemTools::LowerCase(source.Source->GetLocation().GetName())) {
+ rootDir = source.Source->GetLocation().GetDirectory();
break;
}
}
@@ -3657,10 +3655,6 @@ bool cmVisualStudio10TargetGenerator::ComputeLinkOptions(
std::vector<std::string> libVec;
std::vector<std::string> vsTargetVec;
this->AddLibraries(cli, libVec, vsTargetVec, config);
- if (cm::contains(linkClosure->Languages, "CUDA") &&
- this->CudaOptions[config] != nullptr) {
- this->CudaOptions[config]->FixCudaRuntime(this->GeneratorTarget);
- }
std::string standardLibsVar =
cmStrCat("CMAKE_", linkLanguage, "_STANDARD_LIBRARIES");
std::string const& libs = this->Makefile->GetSafeDefinition(standardLibsVar);
@@ -4133,7 +4127,8 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences(Elem& e0)
}
// Don't reference targets that don't produce any output.
- if (dt->GetManagedType("") == cmGeneratorTarget::ManagedType::Undefined) {
+ if (dt->GetManagedType(this->Configurations[0]) ==
+ cmGeneratorTarget::ManagedType::Undefined) {
e2.Element("ReferenceOutputAssembly", "false");
e2.Element("CopyToOutputDirectory", "Never");
}
@@ -4234,12 +4229,13 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile(
this->GlobalGenerator->TargetsWindowsPhone()) &&
(cmStateEnums::EXECUTABLE == this->GeneratorTarget->GetType())) {
std::string pfxFile;
- std::vector<cmSourceFile const*> certificates;
- this->GeneratorTarget->GetCertificates(certificates, "");
- for (cmSourceFile const* si : certificates) {
- pfxFile = this->ConvertPath(si->GetFullPath(), false);
- ConvertToWindowsSlash(pfxFile);
- break;
+ for (cmGeneratorTarget::AllConfigSource const& source :
+ this->GeneratorTarget->GetAllConfigSources()) {
+ if (source.Kind == cmGeneratorTarget::SourceKindCertificate) {
+ pfxFile = this->ConvertPath(source.Source->GetFullPath(), false);
+ ConvertToWindowsSlash(pfxFile);
+ break;
+ }
}
if (this->IsMissingFiles &&
@@ -4285,28 +4281,61 @@ void cmVisualStudio10TargetGenerator::WriteWinRTPackageCertificateKeyFile(
}
}
+void cmVisualStudio10TargetGenerator::ClassifyAllConfigSources()
+{
+ for (cmGeneratorTarget::AllConfigSource const& source :
+ this->GeneratorTarget->GetAllConfigSources()) {
+ this->ClassifyAllConfigSource(source);
+ }
+}
+
+void cmVisualStudio10TargetGenerator::ClassifyAllConfigSource(
+ cmGeneratorTarget::AllConfigSource const& acs)
+{
+ switch (acs.Kind) {
+ case cmGeneratorTarget::SourceKindResx: {
+ // Build and save the name of the corresponding .h file
+ // This relationship will be used later when building the project files.
+ // Both names would have been auto generated from Visual Studio
+ // where the user supplied the file name and Visual Studio
+ // appended the suffix.
+ std::string resx = acs.Source->ResolveFullPath();
+ std::string hFileName = resx.substr(0, resx.find_last_of('.')) + ".h";
+ this->ExpectedResxHeaders.insert(hFileName);
+ } break;
+ case cmGeneratorTarget::SourceKindXaml: {
+ // Build and save the name of the corresponding .h and .cpp file
+ // This relationship will be used later when building the project files.
+ // Both names would have been auto generated from Visual Studio
+ // where the user supplied the file name and Visual Studio
+ // appended the suffix.
+ std::string xaml = acs.Source->ResolveFullPath();
+ std::string hFileName = xaml + ".h";
+ std::string cppFileName = xaml + ".cpp";
+ this->ExpectedXamlHeaders.insert(hFileName);
+ this->ExpectedXamlSources.insert(cppFileName);
+ } break;
+ default:
+ break;
+ }
+}
+
bool cmVisualStudio10TargetGenerator::IsResxHeader(
const std::string& headerFile)
{
- std::set<std::string> expectedResxHeaders;
- this->GeneratorTarget->GetExpectedResxHeaders(expectedResxHeaders, "");
- return expectedResxHeaders.count(headerFile) > 0;
+ return this->ExpectedResxHeaders.count(headerFile) > 0;
}
bool cmVisualStudio10TargetGenerator::IsXamlHeader(
const std::string& headerFile)
{
- std::set<std::string> expectedXamlHeaders;
- this->GeneratorTarget->GetExpectedXamlHeaders(expectedXamlHeaders, "");
- return expectedXamlHeaders.count(headerFile) > 0;
+ return this->ExpectedXamlHeaders.count(headerFile) > 0;
}
bool cmVisualStudio10TargetGenerator::IsXamlSource(
const std::string& sourceFile)
{
- std::set<std::string> expectedXamlSources;
- this->GeneratorTarget->GetExpectedXamlSources(expectedXamlSources, "");
- return expectedXamlSources.count(sourceFile) > 0;
+ return this->ExpectedXamlSources.count(sourceFile) > 0;
}
void cmVisualStudio10TargetGenerator::WriteApplicationTypeSettings(Elem& e1)
@@ -4387,39 +4416,38 @@ void cmVisualStudio10TargetGenerator::VerifyNecessaryFiles()
// For Windows and Windows Phone executables, we will assume that if a
// manifest is not present that we need to add all the necessary files
if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
- std::vector<cmSourceFile const*> manifestSources;
- this->GeneratorTarget->GetAppManifest(manifestSources, "");
- {
- std::string const& v = this->GlobalGenerator->GetSystemVersion();
- if (this->GlobalGenerator->TargetsWindowsPhone()) {
- if (v == "8.0") {
- // Look through the sources for WMAppManifest.xml
- std::vector<cmSourceFile const*> extraSources;
- this->GeneratorTarget->GetExtraSources(extraSources, "");
- bool foundManifest = false;
- for (cmSourceFile const* si : extraSources) {
- // Need to do a lowercase comparison on the filename
- if ("wmappmanifest.xml" ==
- cmSystemTools::LowerCase(si->GetLocation().GetName())) {
- foundManifest = true;
- break;
- }
- }
- if (!foundManifest) {
- this->IsMissingFiles = true;
- }
- } else if (v == "8.1") {
- if (manifestSources.empty()) {
- this->IsMissingFiles = true;
+ std::vector<cmGeneratorTarget::AllConfigSource> manifestSources =
+ this->GeneratorTarget->GetAllConfigSources(
+ cmGeneratorTarget::SourceKindAppManifest);
+ std::string const& v = this->GlobalGenerator->GetSystemVersion();
+ if (this->GlobalGenerator->TargetsWindowsPhone()) {
+ if (v == "8.0") {
+ // Look through the sources for WMAppManifest.xml
+ bool foundManifest = false;
+ for (cmGeneratorTarget::AllConfigSource const& source :
+ this->GeneratorTarget->GetAllConfigSources()) {
+ if (source.Kind == cmGeneratorTarget::SourceKindExtra &&
+ "wmappmanifest.xml" ==
+ cmSystemTools::LowerCase(
+ source.Source->GetLocation().GetName())) {
+ foundManifest = true;
+ break;
}
}
- } else if (this->GlobalGenerator->TargetsWindowsStore()) {
+ if (!foundManifest) {
+ this->IsMissingFiles = true;
+ }
+ } else if (v == "8.1") {
if (manifestSources.empty()) {
- if (v == "8.0") {
- this->IsMissingFiles = true;
- } else if (v == "8.1" || cmHasLiteralPrefix(v, "10.0")) {
- this->IsMissingFiles = true;
- }
+ this->IsMissingFiles = true;
+ }
+ }
+ } else if (this->GlobalGenerator->TargetsWindowsStore()) {
+ if (manifestSources.empty()) {
+ if (v == "8.0") {
+ this->IsMissingFiles = true;
+ } else if (v == "8.1" || cmHasLiteralPrefix(v, "10.0")) {
+ this->IsMissingFiles = true;
}
}
}
diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h
index e3782f4..7c71de3 100644
--- a/Source/cmVisualStudio10TargetGenerator.h
+++ b/Source/cmVisualStudio10TargetGenerator.h
@@ -13,10 +13,11 @@
#include <unordered_map>
#include <vector>
+#include "cmGeneratorTarget.h"
+
class cmComputeLinkInformation;
class cmCustomCommand;
class cmGeneratedFileStream;
-class cmGeneratorTarget;
class cmGlobalVisualStudio10Generator;
class cmLocalVisualStudio10Generator;
class cmMakefile;
@@ -238,6 +239,14 @@ private:
using ToolSourceMap = std::map<std::string, ToolSources>;
ToolSourceMap Tools;
+ std::set<std::string> ExpectedResxHeaders;
+ std::set<std::string> ExpectedXamlHeaders;
+ std::set<std::string> ExpectedXamlSources;
+ std::vector<cmSourceFile const*> ResxObjs;
+ std::vector<cmSourceFile const*> XamlObjs;
+ void ClassifyAllConfigSources();
+ void ClassifyAllConfigSource(cmGeneratorTarget::AllConfigSource const& acs);
+
using ConfigToSettings =
std::unordered_map<std::string,
std::unordered_map<std::string, std::string>>;
diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx
index 7775f62..937b4ce 100644
--- a/Source/cmVisualStudioGeneratorOptions.cxx
+++ b/Source/cmVisualStudioGeneratorOptions.cxx
@@ -151,34 +151,6 @@ bool cmVisualStudioGeneratorOptions::UsingSBCS() const
return false;
}
-void cmVisualStudioGeneratorOptions::FixCudaRuntime(cmGeneratorTarget* target)
-{
- std::map<std::string, FlagValue>::const_iterator i =
- this->FlagMap.find("CudaRuntime");
- if (i == this->FlagMap.end()) {
- // User didn't provide am override so get the property value
- cmProp runtimeLibraryValue = target->GetProperty("CUDA_RUNTIME_LIBRARY");
- if (runtimeLibraryValue) {
- std::string cudaRuntime =
- cmSystemTools::UpperCase(cmGeneratorExpression::Evaluate(
- *runtimeLibraryValue, this->LocalGenerator, this->Configuration,
- target));
- if (cudaRuntime == "STATIC") {
- this->AddFlag("CudaRuntime", "Static");
- }
- if (cudaRuntime == "SHARED") {
- this->AddFlag("CudaRuntime", "Shared");
- }
- if (cudaRuntime == "NONE") {
- this->AddFlag("CudaRuntime", "None");
- }
- } else {
- // nvcc default is static
- this->AddFlag("CudaRuntime", "Static");
- }
- }
-}
-
void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration()
{
// Extract temporary values stored by our flag table.
diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h
index b335694..f9b50a7 100644
--- a/Source/cmVisualStudioGeneratorOptions.h
+++ b/Source/cmVisualStudioGeneratorOptions.h
@@ -63,7 +63,6 @@ public:
bool UsingSBCS() const;
void FixCudaCodeGeneration();
- void FixCudaRuntime(cmGeneratorTarget* target);
void FixManifestUACFlags();
diff --git a/Source/cmWorkerPool.cxx b/Source/cmWorkerPool.cxx
index 9fec936..12aba4f 100644
--- a/Source/cmWorkerPool.cxx
+++ b/Source/cmWorkerPool.cxx
@@ -469,11 +469,9 @@ void cmWorkerPoolWorker::UVProcessStart(uv_async_t* handle)
void cmWorkerPoolWorker::UVProcessFinished()
{
- {
- std::lock_guard<std::mutex> lock(Proc_.Mutex);
- if (Proc_.ROP && (Proc_.ROP->IsFinished() || !Proc_.ROP->IsStarted())) {
- Proc_.ROP.reset();
- }
+ std::lock_guard<std::mutex> lock(Proc_.Mutex);
+ if (Proc_.ROP && (Proc_.ROP->IsFinished() || !Proc_.ROP->IsStarted())) {
+ Proc_.ROP.reset();
}
// Notify idling thread
Proc_.Condition.notify_one();
@@ -532,6 +530,7 @@ public:
unsigned int JobsProcessing = 0;
std::deque<cmWorkerPool::JobHandleT> Queue;
std::condition_variable Condition;
+ std::condition_variable ConditionFence;
std::vector<std::unique_ptr<cmWorkerPoolWorker>> Workers;
// -- References
@@ -593,19 +592,12 @@ bool cmWorkerPoolInternal::Process()
void cmWorkerPoolInternal::Abort()
{
- bool notifyThreads = false;
// Clear all jobs and set abort flag
- {
- std::lock_guard<std::mutex> guard(Mutex);
- if (Processing && !Aborting) {
- // Register abort and clear queue
- Aborting = true;
- Queue.clear();
- notifyThreads = true;
- }
- }
- if (notifyThreads) {
- // Wake threads
+ std::lock_guard<std::mutex> guard(Mutex);
+ if (!Aborting) {
+ // Register abort and clear queue
+ Aborting = true;
+ Queue.clear();
Condition.notify_all();
}
}
@@ -669,7 +661,7 @@ void cmWorkerPoolInternal::Work(unsigned int workerIndex)
if (Aborting) {
break;
}
- // Wait for new jobs
+ // Wait for new jobs on the main CV
if (Queue.empty()) {
++WorkersIdle;
Condition.wait(uLock);
@@ -677,20 +669,34 @@ void cmWorkerPoolInternal::Work(unsigned int workerIndex)
continue;
}
- // Check for fence jobs
- if (FenceProcessing || Queue.front()->IsFence()) {
- if (JobsProcessing != 0) {
- Condition.wait(uLock);
- continue;
- }
- // No jobs get processed. Set the fence job processing flag.
- FenceProcessing = true;
+ // If there is a fence currently active or waiting,
+ // sleep on the main CV and try again.
+ if (FenceProcessing) {
+ Condition.wait(uLock);
+ continue;
}
// Pop next job from queue
jobHandle = std::move(Queue.front());
Queue.pop_front();
+ // Check for fence jobs
+ bool raisedFence = false;
+ if (jobHandle->IsFence()) {
+ FenceProcessing = true;
+ raisedFence = true;
+ // Wait on the Fence CV until all pending jobs are done.
+ while (JobsProcessing != 0 && !Aborting) {
+ ConditionFence.wait(uLock);
+ }
+ // When aborting, explicitly kick all threads alive once more.
+ if (Aborting) {
+ FenceProcessing = false;
+ Condition.notify_all();
+ break;
+ }
+ }
+
// Unlocked scope for job processing
++JobsProcessing;
{
@@ -701,11 +707,18 @@ void cmWorkerPoolInternal::Work(unsigned int workerIndex)
}
--JobsProcessing;
- // Was this a fence job?
- if (FenceProcessing) {
+ // If this was the thread that entered fence processing
+ // originally, notify all idling workers that the fence
+ // is done.
+ if (raisedFence) {
FenceProcessing = false;
Condition.notify_all();
}
+ // If fence processing is still not done, notify the
+ // the fencing worker when all active jobs are done.
+ if (FenceProcessing && JobsProcessing == 0) {
+ ConditionFence.notify_all();
+ }
}
// Decrement running workers count
diff --git a/Source/cmXCodeScheme.cxx b/Source/cmXCodeScheme.cxx
index 9ac1457..f4c2f2d 100644
--- a/Source/cmXCodeScheme.cxx
+++ b/Source/cmXCodeScheme.cxx
@@ -396,7 +396,8 @@ void cmXCodeScheme::WriteBuildableReference(cmXMLWriter& xout,
xout.BreakAttributes();
xout.Attribute("BuildableIdentifier", "primary");
xout.Attribute("BlueprintIdentifier", xcObj->GetId());
- xout.Attribute("BuildableName", xcObj->GetTarget()->GetFullName());
+ std::string const noConfig; // FIXME: What config to use here?
+ xout.Attribute("BuildableName", xcObj->GetTarget()->GetFullName(noConfig));
xout.Attribute("BlueprintName", xcObj->GetTarget()->GetName());
xout.Attribute("ReferencedContainer", "container:" + container);
xout.EndElement();
diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx
index d640948..be9158e 100644
--- a/Source/kwsys/Directory.cxx
+++ b/Source/kwsys/Directory.cxx
@@ -103,7 +103,7 @@ void Directory::Clear()
namespace KWSYS_NAMESPACE {
-bool Directory::Load(const std::string& name)
+bool Directory::Load(const std::string& name, std::string* errorMessage)
{
this->Clear();
# if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__)
@@ -146,7 +146,8 @@ bool Directory::Load(const std::string& name)
return _findclose(srchHandle) != -1;
}
-unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
+unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name,
+ std::string* errorMessage)
{
# if (defined(_MSC_VER) && _MSC_VER < 1300) || defined(__BORLANDC__)
// Older Visual C++ and Embarcadero compilers.
@@ -192,6 +193,8 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
# include <sys/types.h>
# include <dirent.h>
+# include <errno.h>
+# include <string.h>
// PGI with glibc has trouble with dirent and large file support:
// http://www.pgroup.com/userforum/viewtopic.php?
@@ -209,29 +212,46 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
namespace KWSYS_NAMESPACE {
-bool Directory::Load(const std::string& name)
+bool Directory::Load(const std::string& name, std::string* errorMessage)
{
this->Clear();
+ errno = 0;
DIR* dir = opendir(name.c_str());
if (!dir) {
+ if (errorMessage != nullptr) {
+ *errorMessage = std::string(strerror(errno));
+ }
return false;
}
+ errno = 0;
for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) {
this->Internal->Files.emplace_back(d->d_name);
}
+ if (errno != 0) {
+ if (errorMessage != nullptr) {
+ *errorMessage = std::string(strerror(errno));
+ }
+ return false;
+ }
+
this->Internal->Path = name;
closedir(dir);
return true;
}
-unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
+unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name,
+ std::string* errorMessage)
{
+ errno = 0;
DIR* dir = opendir(name.c_str());
if (!dir) {
+ if (errorMessage != nullptr) {
+ *errorMessage = std::string(strerror(errno));
+ }
return 0;
}
@@ -239,6 +259,13 @@ unsigned long Directory::GetNumberOfFilesInDirectory(const std::string& name)
for (kwsys_dirent* d = readdir(dir); d; d = readdir(dir)) {
count++;
}
+ if (errno != 0) {
+ if (errorMessage != nullptr) {
+ *errorMessage = std::string(strerror(errno));
+ }
+ return false;
+ }
+
closedir(dir);
return count;
}
diff --git a/Source/kwsys/Directory.hxx.in b/Source/kwsys/Directory.hxx.in
index 9b0f4c3..7bc9db0 100644
--- a/Source/kwsys/Directory.hxx.in
+++ b/Source/kwsys/Directory.hxx.in
@@ -35,7 +35,7 @@ public:
* in that directory. 0 is returned if the directory can not be
* opened, 1 if it is opened.
*/
- bool Load(const std::string&);
+ bool Load(const std::string&, std::string* errorMessage = nullptr);
/**
* Return the number of files in the current directory.
@@ -46,7 +46,8 @@ public:
* Return the number of files in the specified directory.
* A higher performance static method.
*/
- static unsigned long GetNumberOfFilesInDirectory(const std::string&);
+ static unsigned long GetNumberOfFilesInDirectory(
+ const std::string&, std::string* errorMessage = nullptr);
/**
* Return the file at the given index, the indexing is 0 based
diff --git a/Source/kwsys/Glob.cxx b/Source/kwsys/Glob.cxx
index fad6ee1..5452f73 100644
--- a/Source/kwsys/Glob.cxx
+++ b/Source/kwsys/Glob.cxx
@@ -182,7 +182,15 @@ bool Glob::RecurseDirectory(std::string::size_type start,
const std::string& dir, GlobMessages* messages)
{
kwsys::Directory d;
- if (!d.Load(dir)) {
+ std::string errorMessage;
+ if (!d.Load(dir, &errorMessage)) {
+ if (messages) {
+ if (!errorMessage.empty()) {
+ messages->push_back(Message(Glob::warning,
+ "Error listing directory '" + dir +
+ "'! Reason: '" + errorMessage + "'"));
+ }
+ }
return true;
}
unsigned long cc;
@@ -278,7 +286,9 @@ void Glob::ProcessDirectory(std::string::size_type start,
// std::cout << "ProcessDirectory: " << dir << std::endl;
bool last = (start == this->Internals->Expressions.size() - 1);
if (last && this->Recurse) {
- this->RecurseDirectory(start, dir, messages);
+ if (kwsys::SystemTools::FileIsDirectory(dir)) {
+ this->RecurseDirectory(start, dir, messages);
+ }
return;
}
diff --git a/Source/kwsys/Glob.hxx.in b/Source/kwsys/Glob.hxx.in
index 170766f..b5a34d5 100644
--- a/Source/kwsys/Glob.hxx.in
+++ b/Source/kwsys/Glob.hxx.in
@@ -28,6 +28,7 @@ public:
enum MessageType
{
error,
+ warning,
cyclicRecursion
};
diff --git a/Source/kwsys/testDirectory.cxx b/Source/kwsys/testDirectory.cxx
index b1ab0c8..eb3ca32 100644
--- a/Source/kwsys/testDirectory.cxx
+++ b/Source/kwsys/testDirectory.cxx
@@ -57,7 +57,11 @@ int _doLongPathTest()
Directory testdir;
// Set res to failure if the directory doesn't load
- res += !testdir.Load(testdirpath);
+ std::string errorMessage = "";
+ res += !testdir.Load(testdirpath, &errorMessage);
+ if (errorMessage != "") {
+ std::cerr << "Failed to list directory: " << errorMessage << std::endl;
+ }
// Increment res failure if the directory appears empty
res += testdir.GetNumberOfFiles() == 0;
// Increment res failures if the path has changed from
@@ -73,6 +77,34 @@ int _doLongPathTest()
return res;
}
+int _nonExistentDirectoryTest()
+{
+ using namespace kwsys;
+ int res = 0;
+ std::string testdirpath(TEST_SYSTEMTOOLS_BINARY_DIR
+ "/directory_testing/doesnt_exist/");
+ std::string errorMessage;
+ Directory testdir;
+
+ errorMessage = "foo";
+ // Increment res failure if directory lists
+ res += testdir.Load(testdirpath, &errorMessage);
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ // Increment res failure if errorMessage is unmodified
+ res += (errorMessage == "foo");
+#endif
+
+ errorMessage = "foo";
+ // Increment res failure if directory has files
+ res += (testdir.GetNumberOfFilesInDirectory(testdirpath, &errorMessage) > 0);
+#if !defined(_WIN32) || defined(__CYGWIN__)
+ // Increment res failure if errorMessage is unmodified
+ res += (errorMessage == "foo");
+#endif
+
+ return res;
+}
+
int _copyDirectoryTest()
{
using namespace kwsys;
@@ -106,5 +138,6 @@ int _copyDirectoryTest()
int testDirectory(int, char* [])
{
- return _doLongPathTest() + _copyDirectoryTest();
+ return _doLongPathTest() + _nonExistentDirectoryTest() +
+ _copyDirectoryTest();
}