diff options
Diffstat (limited to 'Source')
174 files changed, 4551 insertions, 2571 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index c268a92..e99da49 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -160,6 +160,8 @@ add_library( cmComputeLinkInformation.h cmComputeTargetDepends.h cmComputeTargetDepends.cxx + cmConfigureLog.h + cmConfigureLog.cxx cmConsoleBuf.h cmConsoleBuf.cxx cmConstStack.h @@ -196,9 +198,10 @@ add_library( cmDependsCompiler.h cmDocumentation.cxx cmDocumentationFormatter.cxx - cmDocumentationSection.cxx cmDynamicLoader.cxx cmDynamicLoader.h + cmDyndepCollation.cxx + cmDyndepCollation.h cmELF.h cmELF.cxx cmExprParserHelper.cxx @@ -234,6 +237,8 @@ add_library( cmFileAPICache.h cmFileAPICodemodel.cxx cmFileAPICodemodel.h + cmFileAPIConfigureLog.cxx + cmFileAPIConfigureLog.h cmFileAPICMakeFiles.cxx cmFileAPICMakeFiles.h cmFileAPIToolchains.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 5b9df91..8aad0ae 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 25) -set(CMake_VERSION_PATCH 1) +set(CMake_VERSION_PATCH 20230112) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx index 0579066..68e7ba3 100644 --- a/Source/CPack/cmCPackDragNDropGenerator.cxx +++ b/Source/CPack/cmCPackDragNDropGenerator.cxx @@ -451,7 +451,7 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir, mountpoint_regex.find(attach_output.c_str()); std::string const temp_mount = mountpoint_regex.match(1); std::string const temp_mount_name = - temp_mount.substr(sizeof("/Volumes/") - 1); + temp_mount.substr(cmStrLen("/Volumes/")); // Remove dummy padding file so we have enough space on RW image ... std::ostringstream dummy_padding; diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx index f06946b..c228f07 100644 --- a/Source/CPack/cpack.cxx +++ b/Source/CPack/cpack.cxx @@ -5,10 +5,12 @@ #include <cstddef> #include <functional> #include <iostream> +#include <iterator> #include <map> #include <memory> #include <sstream> #include <string> +#include <type_traits> #include <utility> #include <vector> @@ -25,7 +27,6 @@ #include "cmConsoleBuf.h" #include "cmDocumentation.h" #include "cmDocumentationEntry.h" -#include "cmDocumentationFormatter.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmState.h" @@ -36,19 +37,14 @@ #include "cmake.h" namespace { -const char* cmDocumentationName[][2] = { - { nullptr, " cpack - Packaging driver provided by CMake." }, - { nullptr, nullptr } +const cmDocumentationEntry cmDocumentationName = { + {}, + " cpack - Packaging driver provided by CMake." }; -const char* cmDocumentationUsage[][2] = { - // clang-format off - { nullptr, " cpack [options]" }, - { nullptr, nullptr } - // clang-format on -}; +const cmDocumentationEntry cmDocumentationUsage = { {}, " cpack [options]" }; -const char* cmDocumentationOptions[][2] = { +const cmDocumentationEntry cmDocumentationOptions[14] = { { "-G <generators>", "Override/define CPACK_GENERATOR" }, { "-C <Configuration>", "Specify the project configuration" }, { "-D <var>=<value>", "Set a CPack variable." }, @@ -62,14 +58,30 @@ const char* cmDocumentationOptions[][2] = { { "-B <packageDirectory>", "Override/define CPACK_PACKAGE_DIRECTORY" }, { "--vendor <vendorName>", "Override/define CPACK_PACKAGE_VENDOR" }, { "--preset", "Read arguments from a package preset" }, - { "--list-presets", "List available package presets" }, - { nullptr, nullptr } + { "--list-presets", "List available package presets" } }; void cpackProgressCallback(const std::string& message, float /*unused*/) { - std::cout << "-- " << message << std::endl; + std::cout << "-- " << message << '\n'; } + +std::vector<cmDocumentationEntry> makeGeneratorDocs( + const cmCPackGeneratorFactory& gf) +{ + const auto& generators = gf.GetGeneratorsList(); + + std::vector<cmDocumentationEntry> docs; + docs.reserve(generators.size()); + + std::transform( + generators.cbegin(), generators.cend(), std::back_inserter(docs), + [](const std::decay<decltype(generators)>::type::value_type& gen) { + return cmDocumentationEntry{ gen.first, gen.second }; + }); + return docs; +} + } // namespace // this is CPack. @@ -101,8 +113,7 @@ int main(int argc, char const* const* argv) if (cmSystemTools::GetCurrentWorkingDirectory().empty()) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Current working directory cannot be established." - << std::endl); + "Current working directory cannot be established.\n"); return 1; } @@ -129,14 +140,14 @@ int main(int argc, char const* const* argv) auto const verboseLambda = [&log](const std::string&, cmake*, cmMakefile*) -> bool { log.SetVerbose(true); - cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Verbose" << std::endl); + cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Verbose\n"); return true; }; auto const debugLambda = [&log](const std::string&, cmake*, cmMakefile*) -> bool { log.SetDebug(true); - cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Debug" << std::endl); + cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Debug\n"); return true; }; @@ -194,26 +205,25 @@ int main(int argc, char const* const* argv) CommandArgument::setToValue(preset) }, CommandArgument{ "--list-presets", CommandArgument::Values::Zero, CommandArgument::setToTrue(listPresets) }, - CommandArgument{ - "-D", CommandArgument::Values::One, - [&log, &definitions](const std::string& arg, cmake*, - cmMakefile*) -> bool { - std::string value = arg; - size_t pos = value.find_first_of('='); - if (pos == std::string::npos) { - cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Please specify CPack definitions as: KEY=VALUE" - << std::endl); - return false; - } - std::string key = value.substr(0, pos); - value.erase(0, pos + 1); - definitions[key] = value; - cmCPack_Log(&log, cmCPackLog::LOG_DEBUG, - "Set CPack variable: " << key << " to \"" << value << "\"" - << std::endl); - return true; - } }, + CommandArgument{ "-D", CommandArgument::Values::One, + [&log, &definitions](const std::string& arg, cmake*, + cmMakefile*) -> bool { + std::string value = arg; + size_t pos = value.find_first_of('='); + if (pos == std::string::npos) { + cmCPack_Log( + &log, cmCPackLog::LOG_ERROR, + "Please specify CPack definitions as: KEY=VALUE\n"); + return false; + } + std::string key = value.substr(0, pos); + value.erase(0, pos + 1); + definitions[key] = value; + cmCPack_Log(&log, cmCPackLog::LOG_DEBUG, + "Set CPack variable: " << key << " to \"" + << value << "\"\n"); + return true; + } }, }; cmake cminst(cmake::RoleScript, cmState::CPack); @@ -262,8 +272,7 @@ int main(int argc, char const* const* argv) cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Could not read presets from " << workingDirectory << ": " - << cmCMakePresetsGraph::ResultToString(result) - << std::endl); + << cmCMakePresetsGraph::ResultToString(result) << '\n'); return 1; } @@ -276,7 +285,7 @@ int main(int argc, char const* const* argv) if (presetPair == presetsGraph.PackagePresets.end()) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "No such package preset in " << workingDirectory << ": \"" - << preset << '"' << std::endl); + << preset << "\"\n"); presetsGraph.PrintPackagePresetList(presetGeneratorsPresent); return 1; } @@ -284,8 +293,7 @@ int main(int argc, char const* const* argv) if (presetPair->second.Unexpanded.Hidden) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Cannot use hidden package preset in " - << workingDirectory << ": \"" << preset << '"' - << std::endl); + << workingDirectory << ": \"" << preset << "\"\n"); presetsGraph.PrintPackagePresetList(presetGeneratorsPresent); return 1; } @@ -294,7 +302,7 @@ int main(int argc, char const* const* argv) if (!expandedPreset) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Could not evaluate package preset \"" - << preset << "\": Invalid macro expansion" << std::endl); + << preset << "\": Invalid macro expansion\n"); presetsGraph.PrintPackagePresetList(presetGeneratorsPresent); return 1; } @@ -302,8 +310,7 @@ int main(int argc, char const* const* argv) if (!expandedPreset->ConditionResult) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Cannot use disabled package preset in " - << workingDirectory << ": \"" << preset << '"' - << std::endl); + << workingDirectory << ": \"" << preset << "\"\n"); presetsGraph.PrintPackagePresetList(presetGeneratorsPresent); return 1; } @@ -320,7 +327,7 @@ int main(int argc, char const* const* argv) cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "No such configure preset in " << workingDirectory << ": \"" - << expandedPreset->ConfigurePreset << '"' << std::endl); + << expandedPreset->ConfigurePreset << "\"\n"); presetsGraph.PrintConfigurePresetList(); return 1; } @@ -329,7 +336,7 @@ int main(int argc, char const* const* argv) cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Cannot use hidden configure preset in " << workingDirectory << ": \"" - << expandedPreset->ConfigurePreset << '"' << std::endl); + << expandedPreset->ConfigurePreset << "\"\n"); presetsGraph.PrintConfigurePresetList(); return 1; } @@ -339,7 +346,7 @@ int main(int argc, char const* const* argv) cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Could not evaluate configure preset \"" << expandedPreset->ConfigurePreset - << "\": Invalid macro expansion" << std::endl); + << "\": Invalid macro expansion\n"); return 1; } @@ -395,7 +402,7 @@ int main(int argc, char const* const* argv) } cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, - "Read CPack config file: " << cpackConfigFile << std::endl); + "Read CPack config file: " << cpackConfigFile << '\n'); bool cpackConfigFileSpecified = true; if (cpackConfigFile.empty()) { @@ -423,7 +430,7 @@ int main(int argc, char const* const* argv) globalMF.GetModulesFile("CMakeDetermineSystem.cmake"); if (!globalMF.ReadListFile(systemFile)) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Error reading CMakeDetermineSystem.cmake" << std::endl); + "Error reading CMakeDetermineSystem.cmake\n"); return 1; } @@ -431,8 +438,7 @@ int main(int argc, char const* const* argv) globalMF.GetModulesFile("CMakeSystemSpecificInformation.cmake"); if (!globalMF.ReadListFile(systemFile)) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Error reading CMakeSystemSpecificInformation.cmake" - << std::endl); + "Error reading CMakeSystemSpecificInformation.cmake\n"); return 1; } @@ -444,17 +450,17 @@ int main(int argc, char const* const* argv) cpackConfigFile = cmSystemTools::CollapseFullPath(cpackConfigFile); cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, "Read CPack configuration file: " << cpackConfigFile - << std::endl); + << '\n'); if (!globalMF.ReadListFile(cpackConfigFile)) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Problem reading CPack config file: \"" - << cpackConfigFile << "\"" << std::endl); + "Problem reading CPack config file: \"" << cpackConfigFile + << "\"\n"); return 1; } } else if (cpackConfigFileSpecified) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Cannot find CPack config file: \"" << cpackConfigFile - << "\"" << std::endl); + << "\"\n"); return 1; } @@ -503,17 +509,17 @@ int main(int argc, char const* const* argv) cmValue genList = globalMF.GetDefinition("CPACK_GENERATOR"); if (!genList) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "CPack generator not specified" << std::endl); + "CPack generator not specified\n"); } else { std::vector<std::string> generatorsVector = cmExpandedList(*genList); for (std::string const& gen : generatorsVector) { cmMakefile::ScopePushPop raii(&globalMF); cmMakefile* mf = &globalMF; cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, - "Specified generator: " << gen << std::endl); + "Specified generator: " << gen << '\n'); if (!mf->GetDefinition("CPACK_PACKAGE_NAME")) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "CPack project name not specified" << std::endl); + "CPack project name not specified" << '\n'); parsed = false; } if (parsed && @@ -522,13 +528,11 @@ int main(int argc, char const* const* argv) mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR") && mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH")))) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "CPack project version not specified" - << std::endl - << "Specify CPACK_PACKAGE_VERSION, or " - "CPACK_PACKAGE_VERSION_MAJOR, " - "CPACK_PACKAGE_VERSION_MINOR, and " - "CPACK_PACKAGE_VERSION_PATCH." - << std::endl); + "CPack project version not specified\n" + "Specify CPACK_PACKAGE_VERSION, or " + "CPACK_PACKAGE_VERSION_MAJOR, " + "CPACK_PACKAGE_VERSION_MINOR, and " + "CPACK_PACKAGE_VERSION_PATCH.\n"); parsed = false; } if (parsed) { @@ -539,19 +543,12 @@ int main(int argc, char const* const* argv) cpackGenerator->SetTraceExpand(cminst.GetTraceExpand()); } else { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Could not create CPack generator: " << gen - << std::endl); + "Could not create CPack generator: " << gen << '\n'); // Print out all the valid generators cmDocumentation generatorDocs; - std::vector<cmDocumentationEntry> v; - for (auto const& g : generators.GetGeneratorsList()) { - cmDocumentationEntry e; - e.Name = g.first; - e.Brief = g.second; - v.push_back(std::move(e)); - } - generatorDocs.SetSection("Generators", v); - std::cerr << "\n"; + generatorDocs.SetSection("Generators", + makeGeneratorDocs(generators)); + std::cerr << '\n'; generatorDocs.PrintDocumentation(cmDocumentation::ListGenerators, std::cerr); parsed = false; @@ -559,8 +556,7 @@ int main(int argc, char const* const* argv) if (parsed && !cpackGenerator->Initialize(gen, mf)) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, - "Cannot initialize the generator " << gen - << std::endl); + "Cannot initialize the generator " << gen << '\n'); parsed = false; } @@ -573,17 +569,16 @@ int main(int argc, char const* const* argv) "Please specify build tree of the project that uses CMake " "using CPACK_INSTALL_CMAKE_PROJECTS, specify " "CPACK_INSTALL_COMMANDS, CPACK_INSTALL_SCRIPT, or " - "CPACK_INSTALLED_DIRECTORIES." - << std::endl); + "CPACK_INSTALLED_DIRECTORIES.\n"); parsed = false; } if (parsed) { cmValue projName = mf->GetDefinition("CPACK_PACKAGE_NAME"); cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, "Use generator: " << cpackGenerator->GetNameOfClass() - << std::endl); + << '\n'); cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, - "For project: " << *projName << std::endl); + "For project: " << *projName << '\n'); cmValue projVersion = mf->GetDefinition("CPACK_PACKAGE_VERSION"); if (!projVersion) { @@ -594,7 +589,7 @@ int main(int argc, char const* const* argv) cmValue projVersionPatch = mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH"); std::ostringstream ostr; - ostr << *projVersionMajor << "." << *projVersionMinor << "." + ostr << *projVersionMajor << "." << *projVersionMinor << '.' << *projVersionPatch; mf->AddDefinition("CPACK_PACKAGE_VERSION", ostr.str()); } @@ -603,7 +598,7 @@ int main(int argc, char const* const* argv) if (!res) { cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "Error when generating package: " << *projName - << std::endl); + << '\n'); return 1; } } @@ -618,27 +613,13 @@ int main(int argc, char const* const* argv) */ if (help) { // Construct and print requested documentation. - doc.SetName("cpack"); doc.SetSection("Name", cmDocumentationName); doc.SetSection("Usage", cmDocumentationUsage); doc.PrependSection("Options", cmDocumentationOptions); - - std::vector<cmDocumentationEntry> v; - for (auto const& g : generators.GetGeneratorsList()) { - cmDocumentationEntry e; - e.Name = g.first; - e.Brief = g.second; - v.push_back(std::move(e)); - } - doc.SetSection("Generators", v); - - return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1; - } - - if (cmSystemTools::GetErrorOccurredFlag()) { - return 1; + doc.SetSection("Generators", makeGeneratorDocs(generators)); + return !doc.PrintRequestedDocumentation(std::cout); } - return 0; + return int(cmSystemTools::GetErrorOccurredFlag()); } diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index a39c52f..643bc6f 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -165,7 +165,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) if (outstring) { *outstring = "--build-and-test requires that the generator " "be provided using the --build-generator " - "command line option. "; + "command line option.\n"; } return 1; } diff --git a/Source/CTest/cmCTestConfigureCommand.cxx b/Source/CTest/cmCTestConfigureCommand.cxx index fd20398..1f3633d 100644 --- a/Source/CTest/cmCTestConfigureCommand.cxx +++ b/Source/CTest/cmCTestConfigureCommand.cxx @@ -122,10 +122,15 @@ cmCTestGenericHandler* cmCTestConfigureCommand::InitializeHandler() cmakeConfigureCommand += "\""; } - cmakeConfigureCommand += " \""; + cmakeConfigureCommand += " \"-S"; cmakeConfigureCommand += source_dir; cmakeConfigureCommand += "\""; + cmakeConfigureCommand += " \"-B"; + cmakeConfigureCommand += + this->CTest->GetCTestConfiguration("BuildDirectory"); + cmakeConfigureCommand += "\""; + this->CTest->SetCTestConfiguration("ConfigureCommand", cmakeConfigureCommand, this->Quiet); } else { diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index f7c6a9c..5c48cbf 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -73,6 +73,7 @@ public: bool StartProcess() { std::vector<const char*> args; + args.reserve(this->CommandLineStrings.size()); for (std::string const& cl : this->CommandLineStrings) { args.push_back(cl.c_str()); } diff --git a/Source/CTest/cmCTestCurl.cxx b/Source/CTest/cmCTestCurl.cxx index 69c5793..84161f9 100644 --- a/Source/CTest/cmCTestCurl.cxx +++ b/Source/CTest/cmCTestCurl.cxx @@ -112,7 +112,7 @@ bool cmCTestCurl::UploadFile(std::string const& local_file, { response.clear(); if (!this->InitCurl()) { - cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed"); + cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed\n"); return false; } /* enable uploading */ @@ -176,7 +176,7 @@ bool cmCTestCurl::UploadFile(std::string const& local_file, if (response.empty()) { cmCTestLog(this->CTest, ERROR_MESSAGE, "No response from server.\n" - << curlDebug); + << curlDebug << std::endl); return false; } return true; @@ -192,7 +192,7 @@ bool cmCTestCurl::HttpRequest(std::string const& url, << "fields " << fields << "\n", this->Quiet); if (!this->InitCurl()) { - cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed"); + cmCTestLog(this->CTest, ERROR_MESSAGE, "Initialization of curl failed\n"); return false; } curl_easy_setopt(this->Curl, CURLOPT_POST, 1); diff --git a/Source/CTest/cmCTestGenericHandler.cxx b/Source/CTest/cmCTestGenericHandler.cxx index 1c292c7..dd69968 100644 --- a/Source/CTest/cmCTestGenericHandler.cxx +++ b/Source/CTest/cmCTestGenericHandler.cxx @@ -26,13 +26,8 @@ namespace { * is non-null, otherwise removing key `op` (if it exists). */ void SetMapValue(cmCTestGenericHandler::t_StringToString& map, - const std::string& op, const char* value) + const std::string& op, const std::string& value) { - if (!value) { - map.erase(op); - return; - } - map[op] = value; } void SetMapValue(cmCTestGenericHandler::t_StringToString& map, @@ -47,7 +42,8 @@ void SetMapValue(cmCTestGenericHandler::t_StringToString& map, } } -void cmCTestGenericHandler::SetOption(const std::string& op, const char* value) +void cmCTestGenericHandler::SetOption(const std::string& op, + const std::string& value) { SetMapValue(this->Options, op, value); } @@ -57,7 +53,7 @@ void cmCTestGenericHandler::SetOption(const std::string& op, cmValue value) } void cmCTestGenericHandler::SetPersistentOption(const std::string& op, - const char* value) + const std::string& value) { this->SetOption(op, value); SetMapValue(this->PersistentOptions, op, value); @@ -121,7 +117,7 @@ bool cmCTestGenericHandler::StartResultingXML(cmCTest::Part part, if (!name) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create resulting XML file without providing the name" - << std::endl;); + << std::endl); return false; } std::ostringstream ostr; @@ -157,7 +153,7 @@ bool cmCTestGenericHandler::StartLogFile(const char* name, if (!name) { cmCTestLog(this->CTest, ERROR_MESSAGE, "Cannot create log file without providing the name" - << std::endl;); + << std::endl); return false; } std::ostringstream ostr; diff --git a/Source/CTest/cmCTestGenericHandler.h b/Source/CTest/cmCTestGenericHandler.h index 4bdb9c2..a0197d6 100644 --- a/Source/CTest/cmCTestGenericHandler.h +++ b/Source/CTest/cmCTestGenericHandler.h @@ -85,17 +85,9 @@ public: * so calling a single-getter for a key that has only been set * as a multi-value will return nullptr. */ - void SetPersistentOption(const std::string& op, const char* value); - void SetPersistentOption(const std::string& op, const std::string& value) - { - this->SetPersistentOption(op, cmValue(value)); - } + void SetPersistentOption(const std::string& op, const std::string& value); void SetPersistentOption(const std::string& op, cmValue value); - void SetOption(const std::string& op, const char* value); - void SetOption(const std::string& op, const std::string& value) - { - this->SetOption(op, cmValue(value)); - } + void SetOption(const std::string& op, const std::string& value); void SetOption(const std::string& op, cmValue value); cmValue GetOption(const std::string& op); diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index be952cd..c377d68 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -143,7 +143,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, "BuildDirectory", cmSystemTools::CollapseFullPath(bdir), this->Quiet); } else { cmCTestLog(this->CTest, ERROR_MESSAGE, - "CTEST_BINARY_DIRECTORY not set" << std::endl;); + "CTEST_BINARY_DIRECTORY not set" << std::endl); } } if (!this->Source.empty()) { @@ -164,7 +164,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, this->CTest->SetCTestConfiguration("ChangeId", *changeId, this->Quiet); } - cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl;); + cmCTestLog(this->CTest, DEBUG, "Initialize handler" << std::endl); cmCTestGenericHandler* handler = this->InitializeHandler(); if (!handler) { cmCTestLog(this->CTest, ERROR_MESSAGE, diff --git a/Source/CursesDialog/ccmake.cxx b/Source/CursesDialog/ccmake.cxx index 1f7776c..18c1a80 100644 --- a/Source/CursesDialog/ccmake.cxx +++ b/Source/CursesDialog/ccmake.cxx @@ -16,45 +16,38 @@ #include "cmCursesMainForm.h" #include "cmCursesStandardIncludes.h" #include "cmDocumentation.h" -#include "cmDocumentationEntry.h" // IWYU pragma: keep +#include "cmDocumentationEntry.h" #include "cmMessageMetadata.h" #include "cmState.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmake.h" -static const char* cmDocumentationName[][2] = { - { nullptr, " ccmake - Curses Interface for CMake." }, - { nullptr, nullptr } +namespace { +const cmDocumentationEntry cmDocumentationName = { + {}, + " ccmake - Curses Interface for CMake." }; -static const char* cmDocumentationUsage[][2] = { - { nullptr, +const cmDocumentationEntry cmDocumentationUsage[2] = { + { {}, " ccmake <path-to-source>\n" " ccmake <path-to-existing-build>" }, - { nullptr, + { {}, "Specify a source directory to (re-)generate a build system for " "it in the current working directory. Specify an existing build " "directory to re-generate its build system." }, - { nullptr, nullptr } }; -static const char* cmDocumentationUsageNote[][2] = { - { nullptr, "Run 'ccmake --help' for more information." }, - { nullptr, nullptr } +const cmDocumentationEntry cmDocumentationUsageNote = { + {}, + "Run 'ccmake --help' for more information." }; -static const char* cmDocumentationOptions[][2] = { - CMAKE_STANDARD_OPTIONS_TABLE, - { nullptr, nullptr } -}; - -cmCursesForm* cmCursesForm::CurrentForm = nullptr; - #ifndef _WIN32 extern "C" { -static void onsig(int /*unused*/) +void onsig(int /*unused*/) { if (cmCursesForm::CurrentForm) { cmCursesForm::CurrentForm->HandleResize(); @@ -63,6 +56,9 @@ static void onsig(int /*unused*/) } } #endif // _WIN32 +} // anonymous namespace + +cmCursesForm* cmCursesForm::CurrentForm = nullptr; int main(int argc, char const* const* argv) { @@ -77,7 +73,7 @@ int main(int argc, char const* const* argv) cmDocumentation doc; doc.addCMakeStandardDocSections(); if (doc.CheckOptions(argc, argv)) { - cmake hcm(cmake::RoleInternal, cmState::Unknown); + cmake hcm(cmake::RoleInternal, cmState::Help); hcm.SetHomeDirectory(""); hcm.SetHomeOutputDirectory(""); hcm.AddCMakePaths(); @@ -89,8 +85,8 @@ int main(int argc, char const* const* argv) doc.AppendSection("Usage", cmDocumentationUsageNote); } doc.AppendSection("Generators", generators); - doc.PrependSection("Options", cmDocumentationOptions); - return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1; + doc.PrependSection("Options", cmake::CMAKE_STANDARD_OPTIONS_TABLE); + return !doc.PrintRequestedDocumentation(std::cout); } bool debug = false; diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx index fb12b7d..50e8e3a 100644 --- a/Source/QtDialog/CMakeSetup.cxx +++ b/Source/QtDialog/CMakeSetup.cxx @@ -22,26 +22,27 @@ #include "cmSystemTools.h" // IWYU pragma: keep #include "cmake.h" -static const char* cmDocumentationName[][2] = { { nullptr, - " cmake-gui - CMake GUI." }, - { nullptr, nullptr } }; - -static const char* cmDocumentationUsage[][2] = { - { nullptr, - " cmake-gui [options]\n" - " cmake-gui [options] <path-to-source>\n" - " cmake-gui [options] <path-to-existing-build>\n" - " cmake-gui [options] -S <path-to-source> -B <path-to-build>\n" - " cmake-gui [options] --browse-manual\n" }, - { nullptr, nullptr } +namespace { +const cmDocumentationEntry cmDocumentationName = { + {}, + " cmake-gui - CMake GUI." }; -static const char* cmDocumentationOptions[][2] = { +const cmDocumentationEntry cmDocumentationUsage = { + {}, + " cmake-gui [options]\n" + " cmake-gui [options] <path-to-source>\n" + " cmake-gui [options] <path-to-existing-build>\n" + " cmake-gui [options] -S <path-to-source> -B <path-to-build>\n" + " cmake-gui [options] --browse-manual" +}; + +const cmDocumentationEntry cmDocumentationOptions[3] = { { "-S <path-to-source>", "Explicitly specify a source directory." }, { "-B <path-to-build>", "Explicitly specify a build directory." }, - { "--preset=<preset>", "Specify a configure preset." }, - { nullptr, nullptr } + { "--preset=<preset>", "Specify a configure preset." } }; +} // anonymous namespace #if defined(Q_OS_MAC) static int cmOSXInstall(std::string dir); @@ -79,7 +80,7 @@ int main(int argc, char** argv) doc.addCMakeStandardDocSections(); if (argc2 > 1 && doc.CheckOptions(argc2, argv2)) { // Construct and print requested documentation. - cmake hcm(cmake::RoleInternal, cmState::Unknown); + cmake hcm(cmake::RoleInternal, cmState::Help); hcm.SetHomeDirectory(""); hcm.SetHomeOutputDirectory(""); hcm.AddCMakePaths(); @@ -91,7 +92,7 @@ int main(int argc, char** argv) doc.AppendSection("Generators", generators); doc.PrependSection("Options", cmDocumentationOptions); - return (doc.PrintRequestedDocumentation(std::cout) ? 0 : 1); + return !doc.PrintRequestedDocumentation(std::cout); } #if defined(Q_OS_MAC) @@ -252,6 +253,7 @@ int main(int argc, char** argv) # include <unistd.h> # include "cm_sys_stat.h" + static bool cmOSXInstall(std::string const& dir, std::string const& tool) { if (tool.empty()) { @@ -277,6 +279,7 @@ static bool cmOSXInstall(std::string const& dir, std::string const& tool) << "': " << strerror(err) << "\n"; return false; } + static int cmOSXInstall(std::string dir) { if (!cmHasLiteralSuffix(dir, "/")) { diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index 01fa7bb..3d4d726 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -1344,7 +1344,8 @@ void CMakeSetupDialog::showUserChanges() void CMakeSetupDialog::setSearchFilter(const QString& str) { this->CacheValues->selectionModel()->clear(); - this->CacheValues->setSearchFilter(str); + const bool valid = this->CacheValues->setSearchFilter(str); + QtCMake::setSearchFilterColor(this->Search, valid); } void CMakeSetupDialog::doOutputContextMenu(QPoint pt) diff --git a/Source/QtDialog/EnvironmentDialog.cxx b/Source/QtDialog/EnvironmentDialog.cxx index bf89816..2752c0f 100644 --- a/Source/QtDialog/EnvironmentDialog.cxx +++ b/Source/QtDialog/EnvironmentDialog.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "EnvironmentDialog.h" +#include "QCMakeWidgets.h" #include <QDialogButtonBox> #include <QGridLayout> #include <QItemSelectionModel> @@ -110,14 +111,11 @@ EnvironmentDialog::EnvironmentDialog(const QProcessEnvironment& environment, &EnvironmentDialog::addEntry); QObject::connect(this->RemoveEntry, &QAbstractButton::clicked, this, &EnvironmentDialog::removeSelectedEntries); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) - QObject::connect(this->Search, &QLineEdit::textChanged, this->m_filter, - QOverload<const QString&>::of( - &EnvironmentSearchFilter::setFilterRegularExpression)); -#else - QObject::connect(this->Search, &QLineEdit::textChanged, this->m_filter, - &EnvironmentSearchFilter::setFilterFixedString); -#endif + QObject::connect( + this->Search, &QLineEdit::textChanged, [this](const QString& text) { + const bool valid = QtCMake::setSearchFilter(this->m_filter, text); + QtCMake::setSearchFilterColor(this->Search, valid); + }); QObject::connect(this->Environment->selectionModel(), &QItemSelectionModel::selectionChanged, this, &EnvironmentDialog::selectionChanged); diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx index f79d6fc..6f19b67 100644 --- a/Source/QtDialog/QCMakeCacheView.cxx +++ b/Source/QtDialog/QCMakeCacheView.cxx @@ -167,13 +167,9 @@ bool QCMakeCacheView::showAdvanced() const return this->AdvancedFilter->showAdvanced(); } -void QCMakeCacheView::setSearchFilter(const QString& s) +bool QCMakeCacheView::setSearchFilter(const QString& s) { -#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) - this->SearchFilter->setFilterRegularExpression(s); -#else - this->SearchFilter->setFilterFixedString(s); -#endif + return QtCMake::setSearchFilter(this->SearchFilter, s); } QCMakeCacheModel::QCMakeCacheModel(QObject* p) diff --git a/Source/QtDialog/QCMakeCacheView.h b/Source/QtDialog/QCMakeCacheView.h index c5e6dd4..89068ab 100644 --- a/Source/QtDialog/QCMakeCacheView.h +++ b/Source/QtDialog/QCMakeCacheView.h @@ -28,12 +28,13 @@ public: QSize sizeHint() const { return QSize(200, 200); } + // set the search filter string. any property key or value not matching will + // be filtered out + bool setSearchFilter(const QString&); + public slots: // set whether to show advanced entries void setShowAdvanced(bool); - // set the search filter string. any property key or value not matching will - // be filtered out - void setSearchFilter(const QString&); protected: QModelIndex moveCursor(CursorAction, Qt::KeyboardModifiers); diff --git a/Source/QtDialog/QCMakeWidgets.cxx b/Source/QtDialog/QCMakeWidgets.cxx index 03d6ed1..f1bb2f1 100644 --- a/Source/QtDialog/QCMakeWidgets.cxx +++ b/Source/QtDialog/QCMakeWidgets.cxx @@ -10,8 +10,13 @@ #include <QFileDialog> #include <QFileInfo> #include <QResizeEvent> +#include <QSortFilterProxyModel> #include <QToolButton> +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) +# include <QRegularExpression> +#endif + #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) # include <QFileSystemModel> #else @@ -155,3 +160,32 @@ QString QCMakeFileCompleter::pathFromIndex(const QModelIndex& idx) const { return QDir::fromNativeSeparators(QCompleter::pathFromIndex(idx)); } + +namespace QtCMake { +bool setSearchFilter(QSortFilterProxyModel* model, const QString& searchString) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + QRegularExpression const regex(searchString, + QRegularExpression::CaseInsensitiveOption | + QRegularExpression::DontCaptureOption); + if (regex.isValid()) { + model->setFilterRegularExpression(regex); + return true; + } + model->setFilterFixedString(QString{}); + return false; +#else + model->setFilterFixedString(searchString); + return true; +#endif +} + +void setSearchFilterColor(QLineEdit* edit, bool valid) +{ + QPalette palette; + if (!valid) { + palette.setColor(QPalette::Base, Qt::red); + } + edit->setPalette(palette); +} +} diff --git a/Source/QtDialog/QCMakeWidgets.h b/Source/QtDialog/QCMakeWidgets.h index 9a2a27e..858a913 100644 --- a/Source/QtDialog/QCMakeWidgets.h +++ b/Source/QtDialog/QCMakeWidgets.h @@ -9,6 +9,7 @@ #include <QLineEdit> class QToolButton; +class QSortFilterProxyModel; // common widgets for Qt based CMake @@ -76,3 +77,10 @@ public: } } }; + +namespace QtCMake { +bool setSearchFilter(QSortFilterProxyModel* model, + const QString& searchString); + +void setSearchFilterColor(QLineEdit* edit, bool valid); +} diff --git a/Source/cmBinUtilsLinuxELFLinker.cxx b/Source/cmBinUtilsLinuxELFLinker.cxx index a69c00d..5972202 100644 --- a/Source/cmBinUtilsLinuxELFLinker.cxx +++ b/Source/cmBinUtilsLinuxELFLinker.cxx @@ -154,8 +154,13 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies( if (!this->Archive->IsPostExcluded(path)) { bool unique; this->Archive->AddResolvedPath(dep, path, unique); - if (unique && !this->ScanDependencies(path, rpaths)) { - return false; + if (unique) { + std::vector<std::string> combinedParentRpaths = parentRpaths; + combinedParentRpaths.insert(combinedParentRpaths.end(), + rpaths.begin(), rpaths.end()); + if (!this->ScanDependencies(path, combinedParentRpaths)) { + return false; + } } } } else { diff --git a/Source/cmCMakePresetsGraphInternal.h b/Source/cmCMakePresetsGraphInternal.h index 9e47a69..2726e92 100644 --- a/Source/cmCMakePresetsGraphInternal.h +++ b/Source/cmCMakePresetsGraphInternal.h @@ -1,5 +1,7 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + #include <memory> #include <string> #include <vector> diff --git a/Source/cmCMakePresetsGraphReadJSON.cxx b/Source/cmCMakePresetsGraphReadJSON.cxx index eec53c1..a96ab58 100644 --- a/Source/cmCMakePresetsGraphReadJSON.cxx +++ b/Source/cmCMakePresetsGraphReadJSON.cxx @@ -518,9 +518,7 @@ cmCMakePresetsGraph::ReadFileResult cmCMakePresetsGraph::ReadJSONFile( PresetPair<ConfigurePreset> presetPair; presetPair.Unexpanded = preset; presetPair.Expanded = cm::nullopt; - if (!this->ConfigurePresets - .emplace(std::make_pair(preset.Name, presetPair)) - .second) { + if (!this->ConfigurePresets.emplace(preset.Name, presetPair).second) { return ReadFileResult::DUPLICATE_PRESETS; } diff --git a/Source/cmCPluginAPI.h b/Source/cmCPluginAPI.h index 19626f0..0d8a366 100644 --- a/Source/cmCPluginAPI.h +++ b/Source/cmCPluginAPI.h @@ -8,7 +8,7 @@ loosely into four groups 1) Utility 2) cmMakefile 3) cmSourceFile 4) cmSystemTools. Within each grouping functions are listed alphabetically */ /*=========================================================================*/ -#ifndef cmCPluginAPI_h +#ifndef cmCPluginAPI_h /* NOLINT(cmake-use-pragma-once) */ #define cmCPluginAPI_h #define CMAKE_VERSION_MAJOR 2 diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index f60a1e9..b00fa73 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -410,7 +410,8 @@ cmCTest::Part cmCTest::GetPartFromName(const std::string& name) return PartCount; } -int cmCTest::Initialize(const char* binary_dir, cmCTestStartCommand* command) +int cmCTest::Initialize(const std::string& binary_dir, + cmCTestStartCommand* command) { bool quiet = false; if (command && command->ShouldBeQuiet()) { @@ -683,7 +684,7 @@ bool cmCTest::InitializeFromCommand(cmCTestStartCommand* command) this->SetCTestConfigurationFromCMakeVariable( mf, "BuildName", "CTEST_BUILD_NAME", command->ShouldBeQuiet()); - if (!this->Initialize(bld_dir.c_str(), command)) { + if (!this->Initialize(bld_dir, command)) { return false; } cmCTestOptionalLog(this, OUTPUT, @@ -943,8 +944,7 @@ int cmCTest::ProcessSteps() (this->GetRemainingTimeAllowed() > std::chrono::minutes(2))) { cmCTestUpdateHandler* uphandler = this->GetUpdateHandler(); uphandler->SetPersistentOption( - "SourceDirectory", - this->GetCTestConfiguration("SourceDirectory").c_str()); + "SourceDirectory", this->GetCTestConfiguration("SourceDirectory")); update_count = uphandler->ProcessHandler(); if (update_count < 0) { res |= cmCTest::UPDATE_ERRORS; @@ -1691,7 +1691,7 @@ bool cmCTest::SubmitExtraFiles(std::vector<std::string> const& files) if (!cmSystemTools::FileExists(file)) { cmCTestLog(this, ERROR_MESSAGE, "Cannot find extra file: " << file << " to submit." - << std::endl;); + << std::endl); return false; } this->AddSubmitFile(PartExtraFiles, file); @@ -2139,9 +2139,9 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption("TestsToRunInformation", - args[i].c_str()); + args[i]); this->GetMemCheckHandler()->SetPersistentOption("TestsToRunInformation", - args[i].c_str()); + args[i]); } else if (this->CheckArgument(arg, "-U"_s, "--union")) { this->GetTestHandler()->SetPersistentOption("UseUnion", "true"); this->GetMemCheckHandler()->SetPersistentOption("UseUnion", "true"); @@ -2149,9 +2149,9 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption("IncludeRegularExpression", - args[i].c_str()); + args[i]); this->GetMemCheckHandler()->SetPersistentOption("IncludeRegularExpression", - args[i].c_str()); + args[i]); } else if (this->CheckArgument(arg, "-L"_s, "--label-regex") && i < args.size() - 1) { i++; @@ -2172,41 +2172,40 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption("ExcludeRegularExpression", - args[i].c_str()); + args[i]); this->GetMemCheckHandler()->SetPersistentOption("ExcludeRegularExpression", - args[i].c_str()); + args[i]); } else if (this->CheckArgument(arg, "-FA"_s, "--fixture-exclude-any") && i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption( - "ExcludeFixtureRegularExpression", args[i].c_str()); + "ExcludeFixtureRegularExpression", args[i]); this->GetMemCheckHandler()->SetPersistentOption( - "ExcludeFixtureRegularExpression", args[i].c_str()); + "ExcludeFixtureRegularExpression", args[i]); } else if (this->CheckArgument(arg, "-FS"_s, "--fixture-exclude-setup") && i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption( - "ExcludeFixtureSetupRegularExpression", args[i].c_str()); + "ExcludeFixtureSetupRegularExpression", args[i]); this->GetMemCheckHandler()->SetPersistentOption( - "ExcludeFixtureSetupRegularExpression", args[i].c_str()); + "ExcludeFixtureSetupRegularExpression", args[i]); } else if (this->CheckArgument(arg, "-FC"_s, "--fixture-exclude-cleanup") && i < args.size() - 1) { i++; this->GetTestHandler()->SetPersistentOption( - "ExcludeFixtureCleanupRegularExpression", args[i].c_str()); + "ExcludeFixtureCleanupRegularExpression", args[i]); this->GetMemCheckHandler()->SetPersistentOption( - "ExcludeFixtureCleanupRegularExpression", args[i].c_str()); + "ExcludeFixtureCleanupRegularExpression", args[i]); } else if (this->CheckArgument(arg, "--resource-spec-file"_s) && i < args.size() - 1) { i++; - this->GetTestHandler()->SetPersistentOption("ResourceSpecFile", - args[i].c_str()); + this->GetTestHandler()->SetPersistentOption("ResourceSpecFile", args[i]); this->GetMemCheckHandler()->SetPersistentOption("ResourceSpecFile", - args[i].c_str()); + args[i]); } else if (this->CheckArgument(arg, "--rerun-failed"_s)) { @@ -2314,8 +2313,8 @@ void cmCTest::SetPersistentOptionIfNotEmpty(const std::string& value, const std::string& optionName) { if (!value.empty()) { - this->GetTestHandler()->SetPersistentOption(optionName, value.c_str()); - this->GetMemCheckHandler()->SetPersistentOption(optionName, value.c_str()); + this->GetTestHandler()->SetPersistentOption(optionName, value); + this->GetMemCheckHandler()->SetPersistentOption(optionName, value); } } @@ -2758,8 +2757,9 @@ int cmCTest::Run(std::vector<std::string>& args, std::string* output) // intended for (auto& handler : this->Impl->GetTestingHandlers()) { if (!handler->ProcessCommandLineArguments(arg, i, args)) { - cmCTestLog(this, ERROR_MESSAGE, - "Problem parsing command line arguments within a handler"); + cmCTestLog( + this, ERROR_MESSAGE, + "Problem parsing command line arguments within a handler\n"); return 0; } } @@ -2903,7 +2903,7 @@ int cmCTest::ExecuteTests() } } - if (!this->Initialize(workDir.c_str(), nullptr)) { + if (!this->Initialize(workDir, nullptr)) { res = 12; cmCTestLog(this, ERROR_MESSAGE, "Problem initializing the dashboard." << std::endl); diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 0017b3e..9a8d5a6 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -481,7 +481,7 @@ private: * call this method because it sets CTEST_COMMAND to drive a build * through the ctest command line. */ - int Initialize(const char* binary_dir, cmCTestStartCommand* command); + int Initialize(const std::string& binary_dir, cmCTestStartCommand* command); /** parse the option after -D and convert it into the appropriate steps */ bool AddTestsForDashboardType(std::string& targ); diff --git a/Source/cmCallVisualStudioMacro.h b/Source/cmCallVisualStudioMacro.h index 795b863..78f22ae 100644 --- a/Source/cmCallVisualStudioMacro.h +++ b/Source/cmCallVisualStudioMacro.h @@ -19,8 +19,7 @@ public: //! given solution file open. Pass "ALL" for slnFile to call the //! macro in each Visual Studio instance. static int CallMacro(const std::string& slnFile, const std::string& macro, - const std::string& args, - const bool logErrorsAsMessages); + const std::string& args, bool logErrorsAsMessages); //! Count the number of running instances of Visual Studio with the //! given solution file open. Pass "ALL" for slnFile to count all diff --git a/Source/cmCommandLineArgument.h b/Source/cmCommandLineArgument.h index 33c91bc..003e972 100644 --- a/Source/cmCommandLineArgument.h +++ b/Source/cmCommandLineArgument.h @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once +#include <cm/optional> + #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -250,6 +252,15 @@ private: return true; }; } + + static std::function<bool(const std::string&, CallState...)> + generateSetToValue(cm::optional<std::string>& value1) + { + return [&value1](const std::string& arg, CallState&&...) -> bool { + value1 = arg; + return true; + }; + } }; std::string extract_single_value(std::string const& input, diff --git a/Source/cmConfigureLog.cxx b/Source/cmConfigureLog.cxx new file mode 100644 index 0000000..c2a5b5e --- /dev/null +++ b/Source/cmConfigureLog.cxx @@ -0,0 +1,261 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmConfigureLog.h" + +#include <cassert> +#include <cstdio> +#include <iterator> +#include <sstream> +#include <utility> + +#include <cmext/algorithm> +#include <cmext/string_view> + +#include <cm3p/json/writer.h> + +#include "cm_utf8.h" + +#include "cmListFileCache.h" +#include "cmMakefile.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmake.h" + +cmConfigureLog::cmConfigureLog(std::string logDir, + std::vector<unsigned long> logVersions) + : LogDir(std::move(logDir)) + , LogVersions(std::move(logVersions)) +{ + // Always emit events for the latest log version. + static const unsigned long LatestLogVersion = 1; + if (!cm::contains(this->LogVersions, LatestLogVersion)) { + this->LogVersions.emplace_back(LatestLogVersion); + } + + Json::StreamWriterBuilder builder; + this->Encoder.reset(builder.newStreamWriter()); +} + +cmConfigureLog::~cmConfigureLog() +{ + if (this->Opened) { + this->EndObject(); + this->Stream << "...\n"; + } +} + +bool cmConfigureLog::IsAnyLogVersionEnabled( + std::vector<unsigned long> const& v) const +{ + // Both input lists are sorted. Look for a matching element. + auto i1 = v.cbegin(); + auto i2 = this->LogVersions.cbegin(); + while (i1 != v.cend() && i2 != this->LogVersions.cend()) { + if (*i1 < *i2) { + ++i1; + } else if (*i2 < *i1) { + ++i2; + } else { + return true; + } + } + return false; +} + +void cmConfigureLog::WriteBacktrace(cmMakefile const& mf) +{ + std::vector<std::string> backtrace; + auto root = mf.GetCMakeInstance()->GetHomeDirectory(); + for (auto bt = mf.GetBacktrace(); !bt.Empty(); bt = bt.Pop()) { + auto t = bt.Top(); + if (!t.Name.empty() || t.Line == cmListFileContext::DeferPlaceholderLine) { + t.FilePath = cmSystemTools::RelativeIfUnder(root, t.FilePath); + std::ostringstream s; + s << t; + backtrace.emplace_back(s.str()); + } + } + this->WriteValue("backtrace"_s, backtrace); +} + +void cmConfigureLog::EnsureInit() +{ + if (this->Opened) { + return; + } + assert(!this->Stream.is_open()); + + std::string name = cmStrCat(this->LogDir, "/CMakeConfigureLog.yaml"); + this->Stream.open(name.c_str(), std::ios::out | std::ios::app); + + this->Opened = true; + + this->Stream << "\n---\n"; + this->BeginObject("events"_s); +} + +cmsys::ofstream& cmConfigureLog::BeginLine() +{ + for (unsigned i = 0; i < this->Indent; ++i) { + this->Stream << " "; + } + return this->Stream; +} + +void cmConfigureLog::EndLine() +{ + this->Stream << std::endl; +} + +void cmConfigureLog::BeginObject(cm::string_view key) +{ + this->BeginLine() << key << ':'; + this->EndLine(); + ++this->Indent; +} + +void cmConfigureLog::EndObject() +{ + assert(this->Indent); + --this->Indent; +} + +void cmConfigureLog::BeginEvent(std::string const& kind) +{ + this->EnsureInit(); + + this->BeginLine() << '-'; + this->EndLine(); + + ++this->Indent; + + this->WriteValue("kind"_s, kind); +} + +void cmConfigureLog::EndEvent() +{ + assert(this->Indent); + --this->Indent; +} + +void cmConfigureLog::WriteValue(cm::string_view key, std::nullptr_t) +{ + this->BeginLine() << key << ": null"; + this->EndLine(); +} + +void cmConfigureLog::WriteValue(cm::string_view key, bool value) +{ + this->BeginLine() << key << ": " << (value ? "true" : "false"); + this->EndLine(); +} + +void cmConfigureLog::WriteValue(cm::string_view key, int value) +{ + this->BeginLine() << key << ": " << value; + this->EndLine(); +} + +void cmConfigureLog::WriteValue(cm::string_view key, std::string const& value) +{ + this->BeginLine() << key << ": "; + this->Encoder->write(value, &this->Stream); + this->EndLine(); +} + +void cmConfigureLog::WriteValue(cm::string_view key, + std::vector<std::string> const& list) +{ + this->BeginObject(key); + for (auto const& value : list) { + this->BeginLine() << "- "; + this->Encoder->write(value, &this->Stream); + this->EndLine(); + } + this->EndObject(); +} + +void cmConfigureLog::WriteLiteralTextBlock(cm::string_view key, + cm::string_view text) +{ + this->BeginLine() << key << ": |"; + this->EndLine(); + + auto const l = text.length(); + if (l) { + ++this->Indent; + this->BeginLine(); + + auto i = decltype(l){ 0 }; + while (i < l) { + // YAML allows ' ', '\t' and "printable characters", but NOT other + // ASCII whitespace; those must be escaped, as must the upper UNICODE + // control characters (U+0080 - U+009F) + static constexpr unsigned int C1_LAST = 0x9F; + auto const c = static_cast<unsigned char>(text[i]); + switch (c) { + case '\r': + // Print a carriage return only if it is not followed by a line feed. + ++i; + if (i == l || text[i] != '\n') { + this->WriteEscape(c); + } + break; + case '\n': + // Print any line feeds except the very last one + if (i + 1 < l) { + this->EndLine(); + this->BeginLine(); + } + ++i; + break; + case '\t': + // Print horizontal tab verbatim + this->Stream.put('\t'); + ++i; + break; + case '\\': + // Escape backslash for disambiguation + this->Stream << "\\\\"; + ++i; + break; + default: + if (c >= 32 && c < 127) { + // Print ascii byte. + this->Stream.put(text[i]); + ++i; + break; + } else if (c > 127) { + // Decode a UTF-8 sequence. + unsigned int c32; + auto const* const s = text.data() + i; + auto const* const e = text.data() + l; + auto const* const n = cm_utf8_decode_character(s, e, &c32); + if (n > s && c32 > C1_LAST) { + auto const k = std::distance(s, n); + this->Stream.write(s, static_cast<std::streamsize>(k)); + i += static_cast<unsigned>(k); + break; + } + } + + // Escape non-printable byte. + this->WriteEscape(c); + ++i; + break; + } + } + + this->EndLine(); + --this->Indent; + } +} + +void cmConfigureLog::WriteEscape(unsigned char c) +{ + char buffer[6]; + int n = snprintf(buffer, sizeof(buffer), "\\x%02x", c); + if (n > 0) { + this->Stream.write(buffer, n); + } +} diff --git a/Source/cmConfigureLog.h b/Source/cmConfigureLog.h new file mode 100644 index 0000000..9caac66 --- /dev/null +++ b/Source/cmConfigureLog.h @@ -0,0 +1,68 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <memory> +#include <string> +#include <vector> + +#include <cm/string_view> + +#include "cmsys/FStream.hxx" + +namespace Json { +class StreamWriter; +} + +class cmMakefile; + +class cmConfigureLog +{ +public: + /** Construct with the log directory and a sorted list of enabled log + versions. The latest log version will be enabled regardless. */ + cmConfigureLog(std::string logDir, std::vector<unsigned long> logVersions); + ~cmConfigureLog(); + + /** Return true if at least one of the log versions in the given sorted + list is enabled. */ + bool IsAnyLogVersionEnabled(std::vector<unsigned long> const& v) const; + + void WriteBacktrace(cmMakefile const& mf); + + void EnsureInit(); + + void BeginEvent(std::string const& kind); + void EndEvent(); + + void BeginObject(cm::string_view key); + void EndObject(); + + // TODO other value types + void WriteValue(cm::string_view key, std::nullptr_t); + void WriteValue(cm::string_view key, bool value); + void WriteValue(cm::string_view key, int value); + void WriteValue(cm::string_view key, std::string const& value); + void WriteValue(cm::string_view key, std::vector<std::string> const& list); + + void WriteTextBlock(cm::string_view key, cm::string_view text); + void WriteLiteralTextBlock(cm::string_view key, cm::string_view text); + + void WriteLiteralTextBlock(cm::string_view key, std::string const& text) + { + this->WriteLiteralTextBlock(key, cm::string_view{ text }); + } + +private: + std::string LogDir; + std::vector<unsigned long> LogVersions; + cmsys::ofstream Stream; + unsigned Indent = 0; + bool Opened = false; + + std::unique_ptr<Json::StreamWriter> Encoder; + + cmsys::ofstream& BeginLine(); + void EndLine(); + void WriteEscape(unsigned char c); +}; diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index b44111d..2a4ea80 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -7,6 +7,7 @@ #include <cstring> #include <set> #include <sstream> +#include <type_traits> #include <utility> #include <cm/string_view> @@ -16,6 +17,7 @@ #include "cmsys/FStream.hxx" #include "cmArgumentParser.h" +#include "cmConfigureLog.h" #include "cmExportTryCompileFileGenerator.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" @@ -285,8 +287,8 @@ Arguments cmCoreTryCompile::ParseArgs( return arguments; } -bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, - cmStateEnums::TargetType targetType) +cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( + Arguments& arguments, cmStateEnums::TargetType targetType) { this->OutputFile.clear(); // which signature were we called with ? @@ -302,7 +304,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, arguments.SourceDirectoryOrFile->empty()) { this->Makefile->IssueMessage(MessageType::FATAL_ERROR, "No <srcdir> specified."); - return false; + return cm::nullopt; } sourceDirectory = *arguments.SourceDirectoryOrFile; projectName = *arguments.ProjectName; @@ -322,7 +324,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, if (!arguments.BinaryDirectory || arguments.BinaryDirectory->empty()) { this->Makefile->IssueMessage(MessageType::FATAL_ERROR, "No <bindir> specified."); - return false; + return cm::nullopt; } if (*arguments.BinaryDirectory == unique_binary_directory) { // leave empty until we're ready to create it, so we don't try to remove @@ -335,7 +337,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, MessageType::FATAL_ERROR, cmStrCat("<bindir> is not an absolute path:\n '", *arguments.BinaryDirectory, "'")); - return false; + return cm::nullopt; } this->BinaryDirectory = *arguments.BinaryDirectory; // compute the binary dir when TRY_COMPILE is called with a src file @@ -367,7 +369,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, "IMPORTED LINK_LIBRARIES. Got ", tgt->GetName(), " of type ", cmState::GetTargetTypeName(tgt->GetType()), ".")); - return false; + return cm::nullopt; } if (tgt->IsImported()) { targets.emplace_back(i); @@ -379,28 +381,28 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, if (arguments.CopyFileTo && arguments.CopyFileTo->empty()) { this->Makefile->IssueMessage(MessageType::FATAL_ERROR, "COPY_FILE must be followed by a file path"); - return false; + return cm::nullopt; } if (arguments.CopyFileError && arguments.CopyFileError->empty()) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, "COPY_FILE_ERROR must be followed by a variable name"); - return false; + return cm::nullopt; } if (arguments.CopyFileError && !arguments.CopyFileTo) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, "COPY_FILE_ERROR may be used only with COPY_FILE"); - return false; + return cm::nullopt; } if (arguments.Sources && arguments.Sources->empty()) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, "SOURCES must be followed by at least one source file"); - return false; + return cm::nullopt; } if (this->SrcFileSignature) { @@ -409,19 +411,19 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, this->Makefile->IssueMessage( MessageType::FATAL_ERROR, "SOURCE_FROM_CONTENT requires exactly two arguments"); - return false; + return cm::nullopt; } if (arguments.SourceFromVar && arguments.SourceFromVar->size() % 2) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, "SOURCE_FROM_VAR requires exactly two arguments"); - return false; + return cm::nullopt; } if (arguments.SourceFromFile && arguments.SourceFromFile->size() % 2) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, "SOURCE_FROM_FILE requires exactly two arguments"); - return false; + return cm::nullopt; } } else { // only valid for srcfile signatures @@ -430,19 +432,19 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, MessageType::FATAL_ERROR, cmStrCat(arguments.LangProps.begin()->first, " allowed only in source file signature")); - return false; + return cm::nullopt; } if (!arguments.CompileDefs.empty()) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, "COMPILE_DEFINITIONS allowed only in source file signature"); - return false; + return cm::nullopt; } if (arguments.CopyFileTo) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, "COPY_FILE allowed only in source file signature"); - return false; + return cm::nullopt; } } @@ -462,7 +464,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, e << "Attempt at a recursive or nested TRY_COMPILE in directory\n" << " " << this->BinaryDirectory << "\n"; this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return false; + return cm::nullopt; } std::string outFileName = this->BinaryDirectory + "/CMakeLists.txt"; @@ -486,7 +488,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, const auto& content = (*arguments.SourceFromContent)[i + 1]; auto out = this->WriteSource(name, content, "SOURCE_FROM_CONTENT"); if (out.empty()) { - return false; + return cm::nullopt; } sources.emplace_back(std::move(out)); } @@ -499,7 +501,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, const auto& content = this->Makefile->GetDefinition(var); auto out = this->WriteSource(name, content, "SOURCE_FROM_VAR"); if (out.empty()) { - return false; + return cm::nullopt; } sources.emplace_back(std::move(out)); } @@ -514,7 +516,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, const auto& msg = cmStrCat("SOURCE_FROM_FILE given invalid filename \"", dst, "\""); this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg); - return false; + return cm::nullopt; } auto dstPath = cmStrCat(this->BinaryDirectory, "/", dst); @@ -523,7 +525,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, const auto& msg = cmStrCat("SOURCE_FROM_FILE failed to copy \"", src, "\": ", result.GetString()); this->Makefile->IssueMessage(MessageType::FATAL_ERROR, msg); - return false; + return cm::nullopt; } sources.emplace_back(std::move(dstPath)); @@ -550,7 +552,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, err << cmJoin(langs, " "); err << "\nSee project() command to enable other languages."; this->Makefile->IssueMessage(MessageType::FATAL_ERROR, err.str()); - return false; + return cm::nullopt; } } @@ -577,7 +579,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, << cmSystemTools::GetLastSystemError(); /* clang-format on */ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return false; + return cm::nullopt; } cmValue def = this->Makefile->GetDefinition("CMAKE_MODULE_PATH"); @@ -778,7 +780,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, this->Makefile->IssueMessage(MessageType::FATAL_ERROR, "could not write export file."); fclose(fout); - return false; + return cm::nullopt; } fprintf(fout, "\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/%s\")\n\n", fname.c_str()); @@ -1111,7 +1113,7 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, } if (!arguments.CopyFileError) { this->Makefile->IssueMessage(MessageType::FATAL_ERROR, emsg.str()); - return false; + return cm::nullopt; } copyFileErrorMessage = emsg.str(); } @@ -1122,7 +1124,15 @@ bool cmCoreTryCompile::TryCompileCode(Arguments& arguments, this->Makefile->AddDefinition(copyFileError, copyFileErrorMessage); } } - return res == 0; + + cmTryCompileResult result; + result.SourceDirectory = sourceDirectory; + result.BinaryDirectory = this->BinaryDirectory; + result.Variable = *arguments.CompileResultVariable; + result.VariableCached = !arguments.NoCache; + result.Output = std::move(output); + result.ExitCode = res; + return cm::optional<cmTryCompileResult>(std::move(result)); } bool cmCoreTryCompile::IsTemporary(std::string const& path) @@ -1263,3 +1273,20 @@ std::string cmCoreTryCompile::WriteSource(std::string const& filename, file.close(); return filepath; } + +void cmCoreTryCompile::WriteTryCompileEventFields( + cmConfigureLog& log, cmTryCompileResult const& compileResult) +{ +#ifndef CMAKE_BOOTSTRAP + log.BeginObject("directories"_s); + log.WriteValue("source"_s, compileResult.SourceDirectory); + log.WriteValue("binary"_s, compileResult.BinaryDirectory); + log.EndObject(); + log.BeginObject("buildResult"_s); + log.WriteValue("variable"_s, compileResult.Variable); + log.WriteValue("cached"_s, compileResult.VariableCached); + log.WriteLiteralTextBlock("stdout"_s, compileResult.Output); + log.WriteValue("exitCode"_s, compileResult.ExitCode); + log.EndObject(); +#endif +} diff --git a/Source/cmCoreTryCompile.h b/Source/cmCoreTryCompile.h index 3e1e12c..6d29586 100644 --- a/Source/cmCoreTryCompile.h +++ b/Source/cmCoreTryCompile.h @@ -14,10 +14,23 @@ #include "cmArgumentParserTypes.h" #include "cmStateTypes.h" +class cmConfigureLog; class cmMakefile; template <typename Iter> class cmRange; +struct cmTryCompileResult +{ + std::string SourceDirectory; + std::string BinaryDirectory; + + bool VariableCached = true; + std::string Variable; + + std::string Output; + int ExitCode = 1; +}; + /** \class cmCoreTryCompile * \brief Base class for cmTryCompileCommand and cmTryRunCommand * @@ -80,8 +93,8 @@ public: * This function requires at least two \p arguments and will crash if given * fewer. */ - bool TryCompileCode(Arguments& arguments, - cmStateEnums::TargetType targetType); + cm::optional<cmTryCompileResult> TryCompileCode( + Arguments& arguments, cmStateEnums::TargetType targetType); /** * Returns \c true if \p path resides within a CMake temporary directory, @@ -103,6 +116,9 @@ public: */ void FindOutputFile(const std::string& targetName); + static void WriteTryCompileEventFields( + cmConfigureLog& log, cmTryCompileResult const& compileResult); + std::string BinaryDirectory; std::string OutputFile; std::string FindErrorMessage; diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index 41d4442..14c22e3 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -148,6 +148,14 @@ std::string EvaluateDepfile(std::string const& path, std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(path); return cge->Evaluate(lg, config); } + +std::string EvaluateComment(const char* comment, + cmGeneratorExpression const& ge, + cmLocalGenerator* lg, std::string const& config) +{ + std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(comment); + return cge->Evaluate(lg, config); +} } cmCustomCommandGenerator::cmCustomCommandGenerator( @@ -172,7 +180,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator( }; } - cmGeneratorExpression ge(cc.GetBacktrace()); + cmGeneratorExpression ge(*lg->GetCMakeInstance(), cc.GetBacktrace()); cmGeneratorTarget const* target{ lg->FindGeneratorTargetToUse( this->Target) }; @@ -417,7 +425,8 @@ std::string cmCustomCommandGenerator::GetDepfile() const return ""; } - cmGeneratorExpression ge(this->CC->GetBacktrace()); + cmGeneratorExpression ge(*this->LG->GetCMakeInstance(), + this->CC->GetBacktrace()); return EvaluateDepfile(depfile, ge, this->LG, this->OutputConfig); } @@ -462,9 +471,19 @@ std::string cmCustomCommandGenerator::GetInternalDepfile() const return this->ComputeInternalDepfile(this->OutputConfig, depfile); } -const char* cmCustomCommandGenerator::GetComment() const +cm::optional<std::string> cmCustomCommandGenerator::GetComment() const { - return this->CC->GetComment(); + const char* comment = this->CC->GetComment(); + if (!comment) { + return cm::nullopt; + } + if (!*comment) { + return std::string(); + } + + cmGeneratorExpression ge(*this->LG->GetCMakeInstance(), + this->CC->GetBacktrace()); + return EvaluateComment(comment, ge, this->LG, this->OutputConfig); } std::string cmCustomCommandGenerator::GetWorkingDirectory() const diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h index 73a8d38..4453654 100644 --- a/Source/cmCustomCommandGenerator.h +++ b/Source/cmCustomCommandGenerator.h @@ -58,7 +58,7 @@ public: unsigned int GetNumberOfCommands() const; std::string GetCommand(unsigned int c) const; void AppendArguments(unsigned int c, std::string& cmd) const; - const char* GetComment() const; + cm::optional<std::string> GetComment() const; std::string GetWorkingDirectory() const; std::vector<std::string> const& GetOutputs() const; std::vector<std::string> const& GetByproducts() const; diff --git a/Source/cmCxxModuleMapper.cxx b/Source/cmCxxModuleMapper.cxx index 84691c9..cb37f2b 100644 --- a/Source/cmCxxModuleMapper.cxx +++ b/Source/cmCxxModuleMapper.cxx @@ -28,6 +28,38 @@ cm::optional<std::string> CxxModuleLocations::BmiGeneratorPathForModule( namespace { +std::string CxxModuleMapContentClang(CxxModuleLocations const& loc, + cmScanDepInfo const& obj) +{ + std::stringstream mm; + + // Clang's command line only supports a single output. If more than one is + // expected, we cannot make a useful module map file. + if (obj.Provides.size() > 1) { + return {}; + } + + // A series of flags which tell the compiler where to look for modules. + + for (auto const& p : obj.Provides) { + if (auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName)) { + // Force the TU to be considered a C++ module source file regardless of + // extension. + mm << "-x c++-module\n"; + + mm << "-fmodule-output=" << *bmi_loc << '\n'; + break; + } + } + for (auto const& r : obj.Requires) { + if (auto bmi_loc = loc.BmiGeneratorPathForModule(r.LogicalName)) { + mm << "-fmodule-file=" << *bmi_loc << '\n'; + } + } + + return mm.str(); +} + std::string CxxModuleMapContentGcc(CxxModuleLocations const& loc, cmScanDepInfo const& obj) { @@ -179,6 +211,8 @@ cm::static_string_view CxxModuleMapExtension( { if (format) { switch (*format) { + case CxxModuleMapFormat::Clang: + return ".pcm"_s; case CxxModuleMapFormat::Gcc: return ".gcm"_s; case CxxModuleMapFormat::Msvc: @@ -297,6 +331,8 @@ std::string CxxModuleMapContent(CxxModuleMapFormat format, CxxModuleUsage const& usages) { switch (format) { + case CxxModuleMapFormat::Clang: + return CxxModuleMapContentClang(loc, obj); case CxxModuleMapFormat::Gcc: return CxxModuleMapContentGcc(loc, obj); case CxxModuleMapFormat::Msvc: diff --git a/Source/cmCxxModuleMapper.h b/Source/cmCxxModuleMapper.h index 8526a07..9271978 100644 --- a/Source/cmCxxModuleMapper.h +++ b/Source/cmCxxModuleMapper.h @@ -17,6 +17,7 @@ enum class CxxModuleMapFormat { + Clang, Gcc, Msvc, }; diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx index d466a12..77c5295 100644 --- a/Source/cmDocumentation.cxx +++ b/Source/cmDocumentation.cxx @@ -16,7 +16,8 @@ #include "cmSystemTools.h" #include "cmVersion.h" -static const char* cmDocumentationStandardOptions[][2] = { +namespace { +const cmDocumentationEntry cmDocumentationStandardOptions[20] = { { "-h,-H,--help,-help,-usage,/?", "Print usage information and exit." }, { "--version,-version,/V [<file>]", "Print version number and exit." }, { "--help-full [<file>]", "Print all help manuals and exit." }, @@ -42,22 +43,27 @@ static const char* cmDocumentationStandardOptions[][2] = { { "--help-variable var [<file>]", "Print help for one variable and exit." }, { "--help-variable-list [<file>]", "List variables with help available and exit." }, - { "--help-variables [<file>]", "Print cmake-variables manual and exit." }, - { nullptr, nullptr } + { "--help-variables [<file>]", "Print cmake-variables manual and exit." } }; -static const char* cmDocumentationCPackGeneratorsHeader[][2] = { - { nullptr, "The following generators are available on this platform:" }, - { nullptr, nullptr } +const cmDocumentationEntry cmDocumentationCPackGeneratorsHeader = { + {}, + "The following generators are available on this platform:" }; -static const char* cmDocumentationCMakeGeneratorsHeader[][2] = { - { nullptr, - "The following generators are available on this platform (* marks " - "default):" }, - { nullptr, nullptr } +const cmDocumentationEntry cmDocumentationCMakeGeneratorsHeader = { + {}, + "The following generators are available on this platform (* marks " + "default):" }; +bool isOption(const char* arg) +{ + return ((arg[0] == '-') || (strcmp(arg, "/V") == 0) || + (strcmp(arg, "/?") == 0)); +} +} // anonymous namespace + cmDocumentation::cmDocumentation() { this->addCommonStandardDocSections(); @@ -148,14 +154,6 @@ bool cmDocumentation::PrintRequestedDocumentation(std::ostream& os) return result; } -#define GET_OPT_ARGUMENT(target) \ - do { \ - if ((i + 1 < argc) && !this->IsOption(argv[i + 1])) { \ - (target) = argv[i + 1]; \ - i = i + 1; \ - }; \ - } while (false) - void cmDocumentation::WarnFormFromFilename( cmDocumentation::RequestedHelpItem& request, bool& result) { @@ -217,6 +215,14 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv, return true; } + auto get_opt_argument = [=](const int nextIdx, std::string& target) -> bool { + if ((nextIdx < argc) && !isOption(argv[nextIdx])) { + target = argv[nextIdx]; + return true; + } + return false; + }; + // Search for supported help options. bool result = false; @@ -230,7 +236,7 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv, (strcmp(argv[i], "/?") == 0) || (strcmp(argv[i], "-usage") == 0) || (strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-H") == 0)) { help.HelpType = cmDocumentation::Help; - GET_OPT_ARGUMENT(help.Argument); + i += int(get_opt_argument(i + 1, help.Argument)); help.Argument = cmSystemTools::LowerCase(help.Argument); // special case for single command if (!help.Argument.empty()) { @@ -239,25 +245,25 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv, } else if (strcmp(argv[i], "--help-properties") == 0) { help.HelpType = cmDocumentation::OneManual; help.Argument = "cmake-properties.7"; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-policies") == 0) { help.HelpType = cmDocumentation::OneManual; help.Argument = "cmake-policies.7"; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-variables") == 0) { help.HelpType = cmDocumentation::OneManual; help.Argument = "cmake-variables.7"; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-modules") == 0) { help.HelpType = cmDocumentation::OneManual; help.Argument = "cmake-modules.7"; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-custom-modules") == 0) { - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); cmSystemTools::Message( "Warning: --help-custom-modules no longer supported"); if (help.Filename.empty()) { @@ -271,83 +277,79 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv, } else if (strcmp(argv[i], "--help-commands") == 0) { help.HelpType = cmDocumentation::OneManual; help.Argument = "cmake-commands.7"; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-compatcommands") == 0) { - GET_OPT_ARGUMENT(help.Filename); cmSystemTools::Message( "Warning: --help-compatcommands no longer supported"); return true; } else if (strcmp(argv[i], "--help-full") == 0) { help.HelpType = cmDocumentation::Full; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-html") == 0) { - GET_OPT_ARGUMENT(help.Filename); cmSystemTools::Message("Warning: --help-html no longer supported"); return true; } else if (strcmp(argv[i], "--help-man") == 0) { - GET_OPT_ARGUMENT(help.Filename); cmSystemTools::Message("Warning: --help-man no longer supported"); return true; } else if (strcmp(argv[i], "--help-command") == 0) { help.HelpType = cmDocumentation::OneCommand; - GET_OPT_ARGUMENT(help.Argument); - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); help.Argument = cmSystemTools::LowerCase(help.Argument); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-module") == 0) { help.HelpType = cmDocumentation::OneModule; - GET_OPT_ARGUMENT(help.Argument); - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-property") == 0) { help.HelpType = cmDocumentation::OneProperty; - GET_OPT_ARGUMENT(help.Argument); - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-policy") == 0) { help.HelpType = cmDocumentation::OnePolicy; - GET_OPT_ARGUMENT(help.Argument); - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-variable") == 0) { help.HelpType = cmDocumentation::OneVariable; - GET_OPT_ARGUMENT(help.Argument); - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-manual") == 0) { help.HelpType = cmDocumentation::OneManual; - GET_OPT_ARGUMENT(help.Argument); - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Argument)); + i += int(get_opt_argument(i + 1, help.Filename)); this->WarnFormFromFilename(help, result); } else if (strcmp(argv[i], "--help-command-list") == 0) { help.HelpType = cmDocumentation::ListCommands; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--help-module-list") == 0) { help.HelpType = cmDocumentation::ListModules; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--help-property-list") == 0) { help.HelpType = cmDocumentation::ListProperties; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--help-variable-list") == 0) { help.HelpType = cmDocumentation::ListVariables; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--help-policy-list") == 0) { help.HelpType = cmDocumentation::ListPolicies; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--help-manual-list") == 0) { help.HelpType = cmDocumentation::ListManuals; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } else if (strcmp(argv[i], "--copyright") == 0) { - GET_OPT_ARGUMENT(help.Filename); cmSystemTools::Message("Warning: --copyright no longer supported"); return true; } else if ((strcmp(argv[i], "--version") == 0) || (strcmp(argv[i], "-version") == 0) || (strcmp(argv[i], "/V") == 0)) { help.HelpType = cmDocumentation::Version; - GET_OPT_ARGUMENT(help.Filename); + i += int(get_opt_argument(i + 1, help.Filename)); } if (help.HelpType != None) { // This is a help option. See if there is a file name given. @@ -369,56 +371,12 @@ void cmDocumentation::SetSection(const char* name, this->SectionAtName(name) = std::move(section); } -void cmDocumentation::SetSection(const char* name, - std::vector<cmDocumentationEntry>& docs) -{ - cmDocumentationSection sec{ name }; - sec.Append(docs); - this->SetSection(name, std::move(sec)); -} - -void cmDocumentation::SetSection(const char* name, const char* docs[][2]) -{ - cmDocumentationSection sec{ name }; - sec.Append(docs); - this->SetSection(name, std::move(sec)); -} - -void cmDocumentation::SetSections( - std::map<std::string, cmDocumentationSection> sections) -{ - for (auto& s : sections) { - this->SetSection(s.first.c_str(), std::move(s.second)); - } -} cmDocumentationSection& cmDocumentation::SectionAtName(const char* name) { return this->AllSections.emplace(name, cmDocumentationSection{ name }) .first->second; } -void cmDocumentation::PrependSection(const char* name, const char* docs[][2]) -{ - this->SectionAtName(name).Prepend(docs); -} - -void cmDocumentation::PrependSection(const char* name, - std::vector<cmDocumentationEntry>& docs) -{ - this->SectionAtName(name).Prepend(docs); -} - -void cmDocumentation::AppendSection(const char* name, const char* docs[][2]) -{ - this->SectionAtName(name).Append(docs); -} - -void cmDocumentation::AppendSection(const char* name, - std::vector<cmDocumentationEntry>& docs) -{ - this->SectionAtName(name).Append(docs); -} - void cmDocumentation::AppendSection(const char* name, cmDocumentationEntry& docs) { @@ -465,7 +423,7 @@ void cmDocumentation::PrintNames(std::ostream& os, std::string const& pattern) } std::sort(names.begin(), names.end()); for (std::string const& n : names) { - os << n << "\n"; + os << n << '\n'; } } @@ -501,7 +459,7 @@ bool cmDocumentation::PrintHelpOneManual(std::ostream& os) // Argument was not a manual. Complain. os << "Argument \"" << this->CurrentArgument << "\" to --help-manual is not an available manual. " - << "Use --help-manual-list to see all available manuals.\n"; + "Use --help-manual-list to see all available manuals.\n"; return false; } @@ -520,7 +478,7 @@ bool cmDocumentation::PrintHelpOneCommand(std::ostream& os) // Argument was not a command. Complain. os << "Argument \"" << this->CurrentArgument << "\" to --help-command is not a CMake command. " - << "Use --help-command-list to see all commands.\n"; + "Use --help-command-list to see all commands.\n"; return false; } @@ -553,7 +511,7 @@ bool cmDocumentation::PrintHelpListModules(std::ostream& os) } std::sort(modules.begin(), modules.end()); for (std::string const& m : modules) { - os << m << "\n"; + os << m << '\n'; } return true; } @@ -567,7 +525,7 @@ bool cmDocumentation::PrintHelpOneProperty(std::ostream& os) // Argument was not a property. Complain. os << "Argument \"" << this->CurrentArgument << "\" to --help-property is not a CMake property. " - << "Use --help-property-list to see all properties.\n"; + "Use --help-property-list to see all properties.\n"; return false; } @@ -601,7 +559,6 @@ bool cmDocumentation::PrintHelpListGenerators(std::ostream& os) { const auto si = this->AllSections.find("Generators"); if (si != this->AllSections.end()) { - this->Formatter.SetIndent(" "); this->Formatter.PrintSection(os, si->second); } return true; @@ -616,7 +573,7 @@ bool cmDocumentation::PrintHelpOneVariable(std::ostream& os) // Argument was not a variable. Complain. os << "Argument \"" << this->CurrentArgument << "\" to --help-variable is not a defined variable. " - << "Use --help-variable-list to see all defined variables.\n"; + "Use --help-variable-list to see all defined variables.\n"; return false; } @@ -662,12 +619,6 @@ const char* cmDocumentation::GetNameString() const return "CMake"; } -bool cmDocumentation::IsOption(const char* arg) const -{ - return ((arg[0] == '-') || (strcmp(arg, "/V") == 0) || - (strcmp(arg, "/?") == 0)); -} - bool cmDocumentation::PrintOldCustomModules(std::ostream& os) { // CheckOptions abuses the Argument field to give us the file name. @@ -691,7 +642,7 @@ bool cmDocumentation::PrintOldCustomModules(std::ostream& os) } else if ((ext.length() == 2) && (ext[1] >= '1') && (ext[1] <= '9')) { /* clang-format off */ os << - ".TH " << name << " " << ext[1] << " \"" << + ".TH " << name << ' ' << ext[1] << " \"" << cmSystemTools::GetCurrentDateTime("%B %d, %Y") << "\" \"cmake " << cmVersion::GetCMakeVersion() << "\"\n" ".SH NAME\n" @@ -704,7 +655,7 @@ bool cmDocumentation::PrintOldCustomModules(std::ostream& os) ; /* clang-format on */ } else { - os << name << "\n\n" << summary << "\n" << detail; + os << name << "\n\n" << summary << '\n' << detail; } return true; } diff --git a/Source/cmDocumentation.h b/Source/cmDocumentation.h index 313be32..6930986 100644 --- a/Source/cmDocumentation.h +++ b/Source/cmDocumentation.h @@ -7,6 +7,7 @@ #include <iosfwd> #include <map> #include <string> +#include <utility> #include <vector> #include "cmDocumentationFormatter.h" @@ -15,9 +16,33 @@ struct cmDocumentationEntry; /** Class to generate documentation. */ -class cmDocumentation : public cmDocumentationEnums +class cmDocumentation { public: + /** Types of help provided. */ + enum Type + { + None, + Version, + Usage, + Help, + Full, + ListManuals, + ListCommands, + ListModules, + ListProperties, + ListVariables, + ListPolicies, + ListGenerators, + OneManual, + OneCommand, + OneModule, + OneProperty, + OneVariable, + OnePolicy, + OldCustomModules + }; + cmDocumentation(); /** @@ -50,19 +75,26 @@ public: /** Set a section of the documentation. Typical sections include Name, Usage, Description, Options */ void SetSection(const char* sectionName, cmDocumentationSection section); - void SetSection(const char* sectionName, - std::vector<cmDocumentationEntry>& docs); - void SetSection(const char* sectionName, const char* docs[][2]); - void SetSections(std::map<std::string, cmDocumentationSection> sections); + template <typename Iterable> + void SetSection(const char* sectionName, const Iterable& docs) + { + cmDocumentationSection sec{ sectionName }; + sec.Append(docs); + this->SetSection(sectionName, std::move(sec)); + } /** Add the documentation to the beginning/end of the section */ - void PrependSection(const char* sectionName, const char* docs[][2]); - void PrependSection(const char* sectionName, - std::vector<cmDocumentationEntry>& docs); + template <typename Iterable> + void PrependSection(const char* sectionName, const Iterable& docs) + { + this->SectionAtName(sectionName).Prepend(docs); + } void PrependSection(const char* sectionName, cmDocumentationEntry& docs); - void AppendSection(const char* sectionName, const char* docs[][2]); - void AppendSection(const char* sectionName, - std::vector<cmDocumentationEntry>& docs); + template <typename Iterable> + void AppendSection(const char* sectionName, const Iterable& docs) + { + this->SectionAtName(sectionName).Append(docs); + } void AppendSection(const char* sectionName, cmDocumentationEntry& docs); /** Add common (to all tools) documentation section(s) */ @@ -102,7 +134,6 @@ private: bool PrintOldCustomModules(std::ostream& os); const char* GetNameString() const; - bool IsOption(const char* arg) const; bool ShowGenerators; @@ -114,7 +145,7 @@ private: struct RequestedHelpItem { - cmDocumentationEnums::Type HelpType = None; + Type HelpType = None; std::string Filename; std::string Argument; }; diff --git a/Source/cmDocumentationEntry.h b/Source/cmDocumentationEntry.h index 89a2899..d971836 100644 --- a/Source/cmDocumentationEntry.h +++ b/Source/cmDocumentationEntry.h @@ -9,26 +9,15 @@ /** Standard documentation entry for cmDocumentation's formatting. */ struct cmDocumentationEntry { - std::string Name; - std::string Brief; - char CustomNamePrefix = ' '; - cmDocumentationEntry() = default; - cmDocumentationEntry(const char* doc[2]) - { - if (doc[0]) { - this->Name = doc[0]; - } - if (doc[1]) { - this->Brief = doc[1]; - } - } - cmDocumentationEntry(const char* n, const char* b) +#if __cplusplus <= 201103L + cmDocumentationEntry(const std::string& name, const std::string& brief) + : Name{ name } + , Brief{ brief } { - if (n) { - this->Name = n; - } - if (b) { - this->Brief = b; - } } +#endif + + std::string Name = {}; + std::string Brief = {}; + char CustomNamePrefix = ' '; }; diff --git a/Source/cmDocumentationFormatter.cxx b/Source/cmDocumentationFormatter.cxx index 732637e..70ba1fc 100644 --- a/Source/cmDocumentationFormatter.cxx +++ b/Source/cmDocumentationFormatter.cxx @@ -2,7 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmDocumentationFormatter.h" -#include <cstring> +#include <algorithm> +#include <cassert> #include <iomanip> #include <ostream> #include <string> @@ -11,178 +12,207 @@ #include "cmDocumentationEntry.h" #include "cmDocumentationSection.h" -cmDocumentationFormatter::cmDocumentationFormatter() = default; - -cmDocumentationFormatter::~cmDocumentationFormatter() = default; +namespace { +const char* skipSpaces(const char* ptr) +{ + assert(ptr); + for (; *ptr == ' '; ++ptr) { + ; + } + return ptr; +} +const char* skipToSpace(const char* ptr) +{ + assert(ptr); + for (; *ptr && (*ptr != '\n') && (*ptr != ' '); ++ptr) { + ; + } + return ptr; +} +} void cmDocumentationFormatter::PrintFormatted(std::ostream& os, - const char* text) + std::string const& text) const { - if (!text) { + if (text.empty()) { return; } - const char* ptr = text; - while (*ptr) { - // Any ptrs starting in a space are treated as preformatted text. - std::string preformatted; - while (*ptr == ' ') { - for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) { - preformatted.append(1, ch); - } - if (*ptr) { - ++ptr; - preformatted.append(1, '\n'); - } - } - if (!preformatted.empty()) { - this->PrintPreformatted(os, preformatted.c_str()); + + struct Buffer + { + // clang-format off + using PrinterFn = void (cmDocumentationFormatter::*)( + std::ostream&, std::string const& + ) const; + // clang-format on + std::string collected; + const PrinterFn printer; + }; + // const auto NORMAL_IDX = 0u; + const auto PREFORMATTED_IDX = 1u; + const auto HANDLERS_SIZE = 2u; + Buffer buffers[HANDLERS_SIZE] = { + { {}, &cmDocumentationFormatter::PrintParagraph }, + { {}, &cmDocumentationFormatter::PrintPreformatted } + }; + + const auto padding = std::string(this->TextIndent, ' '); + + for (std::size_t pos = 0u, eol = 0u; pos < text.size(); pos = eol) { + const auto current_idx = std::size_t(text[pos] == ' '); + // size_t(!bool(current_idx)) + const auto other_idx = current_idx ^ 1u; + + // Flush the other buffer if anything has been collected + if (!buffers[other_idx].collected.empty()) { + // NOTE Whatever the other index is, the current buffered + // string expected to be empty. + assert(buffers[current_idx].collected.empty()); + + (this->*buffers[other_idx].printer)(os, buffers[other_idx].collected); + buffers[other_idx].collected.clear(); } - // Other ptrs are treated as paragraphs. - std::string paragraph; - for (char ch = *ptr; ch && ch != '\n'; ++ptr, ch = *ptr) { - paragraph.append(1, ch); + // ATTENTION The previous implementation had called `PrintParagraph()` + // **for every processed (char by char) input line**. + // The method unconditionally append the `\n' character after the + // printed text. To keep the backward-compatible behavior it's needed to + // add the '\n' character to the previously collected line... + if (!buffers[current_idx].collected.empty() && + current_idx != PREFORMATTED_IDX) { + buffers[current_idx].collected += '\n'; } - if (*ptr) { - ++ptr; - paragraph.append(1, '\n'); + + // Lookup EOL + eol = text.find('\n', pos); + if (current_idx == PREFORMATTED_IDX) { + buffers[current_idx].collected.append(padding); } - if (!paragraph.empty()) { - this->PrintParagraph(os, paragraph.c_str()); + buffers[current_idx].collected.append( + text, pos, eol == std::string::npos ? eol : ++eol - pos); + } + + for (auto& buf : buffers) { + if (!buf.collected.empty()) { + (this->*buf.printer)(os, buf.collected); } } } void cmDocumentationFormatter::PrintPreformatted(std::ostream& os, - const char* text) + std::string const& text) const { - bool newline = true; - for (const char* ptr = text; *ptr; ++ptr) { - if (newline && *ptr != '\n') { - os << this->TextIndent; - newline = false; - } - os << *ptr; - if (*ptr == '\n') { - newline = true; - } - } - os << "\n"; + os << text << '\n'; } void cmDocumentationFormatter::PrintParagraph(std::ostream& os, - const char* text) + std::string const& text) const { - os << this->TextIndent; + if (this->TextIndent) { + os << std::string(this->TextIndent, ' '); + } this->PrintColumn(os, text); - os << "\n"; -} - -void cmDocumentationFormatter::SetIndent(const char* indent) -{ - this->TextIndent = indent; + os << '\n'; } -void cmDocumentationFormatter::PrintColumn(std::ostream& os, const char* text) +void cmDocumentationFormatter::PrintColumn(std::ostream& os, + std::string const& text) const { // Print text arranged in an indented column of fixed width. - const char* l = text; - long column = 0; bool newSentence = false; bool firstLine = true; - int width = this->TextWidth - static_cast<int>(strlen(this->TextIndent)); - // Loop until the end of the text. - while (*l) { - // Parse the next word. - const char* r = l; - while (*r && (*r != '\n') && (*r != ' ')) { - ++r; - } + assert(this->TextIndent < this->TextWidth); + const std::ptrdiff_t width = this->TextWidth - this->TextIndent; + std::ptrdiff_t column = 0; + // Loop until the end of the text. + for (const char *l = text.c_str(), *r = skipToSpace(text.c_str()); *l; + l = skipSpaces(r), r = skipToSpace(l)) { // Does it fit on this line? - if (r - l < (width - column - (newSentence ? 1 : 0))) { + if (r - l < width - column - std::ptrdiff_t(newSentence)) { // Word fits on this line. if (r > l) { if (column) { // Not first word on line. Separate from the previous word // by a space, or two if this is a new sentence. - if (newSentence) { - os << " "; - column += 2; - } else { - os << " "; - column += 1; - } - } else { + os << &(" "[std::size_t(!newSentence)]); + column += 1u + std::ptrdiff_t(newSentence); + } else if (!firstLine && this->TextIndent) { // First word on line. Print indentation unless this is the // first line. - os << (firstLine ? "" : this->TextIndent); + os << std::string(this->TextIndent, ' '); } // Print the word. - os.write(l, static_cast<long>(r - l)); + os.write(l, r - l); newSentence = (*(r - 1) == '.'); } if (*r == '\n') { // Text provided a newline. Start a new line. - os << "\n"; + os << '\n'; ++r; column = 0; firstLine = false; } else { // No provided newline. Continue this line. - column += static_cast<long>(r - l); + column += r - l; } } else { // Word does not fit on this line. Start a new line. - os << "\n"; + os << '\n'; firstLine = false; if (r > l) { - os << this->TextIndent; - os.write(l, static_cast<long>(r - l)); - column = static_cast<long>(r - l); + os << std::string(this->TextIndent, ' '); + os.write(l, r - l); + column = r - l; newSentence = (*(r - 1) == '.'); } else { column = 0; } } - // Move to beginning of next word. Skip over whitespace. - l = r; - while (*l == ' ') { - ++l; - } } } void cmDocumentationFormatter::PrintSection( std::ostream& os, cmDocumentationSection const& section) { - os << section.GetName() << "\n"; + const std::size_t PREFIX_SIZE = + sizeof(cmDocumentationEntry::CustomNamePrefix) + 1u; + // length of the "= " literal (see below) + const std::size_t SUFFIX_SIZE = 2u; + // legacy magic number ;-) + const std::size_t NAME_SIZE = 29u; + + const std::size_t PADDING_SIZE = PREFIX_SIZE + SUFFIX_SIZE; + const std::size_t TITLE_SIZE = NAME_SIZE + PADDING_SIZE; + + const auto savedIndent = this->TextIndent; - const std::vector<cmDocumentationEntry>& entries = section.GetEntries(); - for (cmDocumentationEntry const& entry : entries) { + os << section.GetName() << '\n'; + + for (cmDocumentationEntry const& entry : section.GetEntries()) { if (!entry.Name.empty()) { - os << std::setw(2) << std::left << entry.CustomNamePrefix << entry.Name; - this->TextIndent = " "; - int align = static_cast<int>(strlen(this->TextIndent)) - 4; - for (int i = static_cast<int>(entry.Name.size()); i < align; ++i) { - os << " "; - } - if (entry.Name.size() > strlen(this->TextIndent) - 4) { - os << "\n"; - os.write(this->TextIndent, strlen(this->TextIndent) - 2); + this->TextIndent = TITLE_SIZE; + os << std::setw(PREFIX_SIZE) << std::left << entry.CustomNamePrefix + << std::setw(int(std::max(NAME_SIZE, entry.Name.size()))) + << entry.Name; + if (entry.Name.size() > NAME_SIZE) { + os << '\n' << std::setw(int(this->TextIndent - PREFIX_SIZE)) << ' '; } os << "= "; - this->PrintColumn(os, entry.Brief.c_str()); - os << "\n"; + this->PrintColumn(os, entry.Brief); + os << '\n'; } else { - os << "\n"; - this->TextIndent = ""; - this->PrintFormatted(os, entry.Brief.c_str()); + os << '\n'; + this->TextIndent = 0u; + this->PrintFormatted(os, entry.Brief); } } - os << "\n"; + + os << '\n'; + + this->TextIndent = savedIndent; } diff --git a/Source/cmDocumentationFormatter.h b/Source/cmDocumentationFormatter.h index cb3038a..e269f6a 100644 --- a/Source/cmDocumentationFormatter.h +++ b/Source/cmDocumentationFormatter.h @@ -5,40 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> - -/** This is just a helper class to make it build with MSVC 6.0. -Actually the enums and internal classes could directly go into -cmDocumentation, but then MSVC6 complains in RequestedHelpItem that -cmDocumentation is an undefined type and so it doesn't know the enums. -Moving the enums to a class which is then already completely parsed helps -against this. */ -class cmDocumentationEnums -{ -public: - /** Types of help provided. */ - enum Type - { - None, - Version, - Usage, - Help, - Full, - ListManuals, - ListCommands, - ListModules, - ListProperties, - ListVariables, - ListPolicies, - ListGenerators, - OneManual, - OneCommand, - OneModule, - OneProperty, - OneVariable, - OnePolicy, - OldCustomModules - }; -}; +#include <string> class cmDocumentationSection; @@ -46,18 +13,15 @@ class cmDocumentationSection; class cmDocumentationFormatter { public: - cmDocumentationFormatter(); - virtual ~cmDocumentationFormatter(); - void PrintFormatted(std::ostream& os, const char* text); - - virtual void PrintSection(std::ostream& os, - cmDocumentationSection const& section); - virtual void PrintPreformatted(std::ostream& os, const char* text); - virtual void PrintParagraph(std::ostream& os, const char* text); - void PrintColumn(std::ostream& os, const char* text); - void SetIndent(const char* indent); + void SetIndent(std::size_t indent) { this->TextIndent = indent; } + void PrintFormatted(std::ostream& os, std::string const& text) const; + void PrintSection(std::ostream& os, cmDocumentationSection const& section); private: - int TextWidth = 77; - const char* TextIndent = ""; + void PrintPreformatted(std::ostream& os, std::string const&) const; + void PrintParagraph(std::ostream& os, std::string const&) const; + void PrintColumn(std::ostream& os, std::string const&) const; + + std::size_t TextWidth = 77u; + std::size_t TextIndent = 0u; }; diff --git a/Source/cmDocumentationSection.cxx b/Source/cmDocumentationSection.cxx deleted file mode 100644 index 439da1b..0000000 --- a/Source/cmDocumentationSection.cxx +++ /dev/null @@ -1,28 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmDocumentationSection.h" - -void cmDocumentationSection::Append(const char* data[][2]) -{ - int i = 0; - while (data[i][1]) { - this->Entries.emplace_back(data[i][0], data[i][1]); - data += 1; - } -} - -void cmDocumentationSection::Prepend(const char* data[][2]) -{ - std::vector<cmDocumentationEntry> tmp; - int i = 0; - while (data[i][1]) { - tmp.emplace_back(data[i][0], data[i][1]); - data += 1; - } - this->Entries.insert(this->Entries.begin(), tmp.begin(), tmp.end()); -} - -void cmDocumentationSection::Append(const char* n, const char* b) -{ - this->Entries.emplace_back(n, b); -} diff --git a/Source/cmDocumentationSection.h b/Source/cmDocumentationSection.h index 276e520..b5e24fe 100644 --- a/Source/cmDocumentationSection.h +++ b/Source/cmDocumentationSection.h @@ -4,11 +4,10 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <iterator> #include <string> #include <vector> -#include <cmext/algorithm> - #include "cmDocumentationEntry.h" // Low-level interface for custom documents: @@ -45,21 +44,20 @@ public: { this->Entries.push_back(entry); } - void Append(const std::vector<cmDocumentationEntry>& entries) + + template <typename Iterable> + void Append(const Iterable& entries) { - cm::append(this->Entries, entries); + this->Entries.insert(std::end(this->Entries), std::begin(entries), + std::end(entries)); } - /** Append an entry to this section using NULL terminated chars */ - void Append(const char* [][2]); - void Append(const char* n, const char* b); - /** prepend some documentation to this section */ - void Prepend(const char* [][2]); - void Prepend(const std::vector<cmDocumentationEntry>& entries) + template <typename Iterable> + void Prepend(const Iterable& entries) { - this->Entries.insert(this->Entries.begin(), entries.begin(), - entries.end()); + this->Entries.insert(std::begin(this->Entries), std::begin(entries), + std::end(entries)); } private: diff --git a/Source/cmDyndepCollation.cxx b/Source/cmDyndepCollation.cxx new file mode 100644 index 0000000..2827659 --- /dev/null +++ b/Source/cmDyndepCollation.cxx @@ -0,0 +1,652 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ + +#include "cmDyndepCollation.h" + +#include <algorithm> +#include <map> +#include <ostream> +#include <set> +#include <utility> +#include <vector> + +#include <cm/memory> +#include <cm/string_view> +#include <cmext/string_view> + +#include <cm3p/json/value.h> + +#include "cmExportBuildFileGenerator.h" +#include "cmExportSet.h" +#include "cmFileSet.h" +#include "cmGeneratedFileStream.h" +#include "cmGeneratorExpression.h" // IWYU pragma: keep +#include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" +#include "cmInstallCxxModuleBmiGenerator.h" +#include "cmInstallExportGenerator.h" +#include "cmInstallFileSetGenerator.h" +#include "cmInstallGenerator.h" +#include "cmMakefile.h" +#include "cmMessageType.h" +#include "cmOutputConverter.h" +#include "cmScanDepFormat.h" +#include "cmSourceFile.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" +#include "cmTarget.h" +#include "cmTargetExport.h" + +namespace { + +Json::Value CollationInformationCxxModules( + cmGeneratorTarget const* gt, std::string const& config, + cmDyndepGeneratorCallbacks const& cb) +{ + cmTarget const* tgt = gt->Target; + auto all_file_sets = tgt->GetAllFileSetNames(); + Json::Value tdi_cxx_module_info = Json::objectValue; + for (auto const& file_set_name : all_file_sets) { + auto const* file_set = tgt->GetFileSet(file_set_name); + if (!file_set) { + gt->Makefile->IssueMessage(MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), + "\" is tracked to have file set \"", + file_set_name, + "\", but it was not found.")); + continue; + } + auto fs_type = file_set->GetType(); + // We only care about C++ module sources here. + if (fs_type != "CXX_MODULES"_s) { + continue; + } + + auto fileEntries = file_set->CompileFileEntries(); + auto directoryEntries = file_set->CompileDirectoryEntries(); + + auto directories = file_set->EvaluateDirectoryEntries( + directoryEntries, gt->LocalGenerator, config, gt); + std::map<std::string, std::vector<std::string>> files_per_dirs; + for (auto const& entry : fileEntries) { + file_set->EvaluateFileEntry(directories, files_per_dirs, entry, + gt->LocalGenerator, config, gt); + } + + std::map<std::string, cmSourceFile const*> sf_map; + { + std::vector<cmSourceFile const*> objectSources; + gt->GetObjectSources(objectSources, config); + for (auto const* sf : objectSources) { + auto full_path = sf->GetFullPath(); + if (full_path.empty()) { + gt->Makefile->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), + "\" has a full path-less source file.")); + continue; + } + sf_map[full_path] = sf; + } + } + + Json::Value fs_dest = Json::nullValue; + for (auto const& ig : gt->Makefile->GetInstallGenerators()) { + if (auto const* fsg = + dynamic_cast<cmInstallFileSetGenerator const*>(ig.get())) { + if (fsg->GetTarget() == gt && fsg->GetFileSet() == file_set) { + fs_dest = fsg->GetDestination(config); + continue; + } + } + } + + for (auto const& files_per_dir : files_per_dirs) { + for (auto const& file : files_per_dir.second) { + auto lookup = sf_map.find(file); + if (lookup == sf_map.end()) { + gt->Makefile->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), "\" has source file \"", + file, + R"(" which is not in any of its "FILE_SET BASE_DIRS".)")); + continue; + } + + auto const* sf = lookup->second; + + if (!sf) { + gt->Makefile->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), "\" has source file \"", + file, "\" which has not been tracked properly.")); + continue; + } + + auto obj_path = cb.ObjectFilePath(sf, config); + Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] = + Json::objectValue; + + tdi_module_info["source"] = file; + tdi_module_info["relative-directory"] = files_per_dir.first; + tdi_module_info["name"] = file_set->GetName(); + tdi_module_info["type"] = file_set->GetType(); + tdi_module_info["visibility"] = + std::string(cmFileSetVisibilityToName(file_set->GetVisibility())); + tdi_module_info["destination"] = fs_dest; + } + } + } + + return tdi_cxx_module_info; +} + +Json::Value CollationInformationBmiInstallation(cmGeneratorTarget const* gt, + std::string const& config) +{ + cmInstallCxxModuleBmiGenerator const* bmi_gen = nullptr; + for (auto const& ig : gt->Makefile->GetInstallGenerators()) { + if (auto const* bmig = + dynamic_cast<cmInstallCxxModuleBmiGenerator const*>(ig.get())) { + if (bmig->GetTarget() == gt) { + bmi_gen = bmig; + continue; + } + } + } + if (bmi_gen) { + Json::Value tdi_bmi_info = Json::objectValue; + + tdi_bmi_info["permissions"] = bmi_gen->GetFilePermissions(); + tdi_bmi_info["destination"] = bmi_gen->GetDestination(config); + const char* msg_level = ""; + switch (bmi_gen->GetMessageLevel()) { + case cmInstallGenerator::MessageDefault: + break; + case cmInstallGenerator::MessageAlways: + msg_level = "MESSAGE_ALWAYS"; + break; + case cmInstallGenerator::MessageLazy: + msg_level = "MESSAGE_LAZY"; + break; + case cmInstallGenerator::MessageNever: + msg_level = "MESSAGE_NEVER"; + break; + } + tdi_bmi_info["message-level"] = msg_level; + tdi_bmi_info["script-location"] = bmi_gen->GetScriptLocation(config); + + return tdi_bmi_info; + } + return Json::nullValue; +} + +Json::Value CollationInformationExports(cmGeneratorTarget const* gt) +{ + Json::Value tdi_exports = Json::arrayValue; + std::string export_name = gt->GetExportName(); + + auto const& all_install_exports = gt->GetGlobalGenerator()->GetExportSets(); + for (auto const& exp : all_install_exports) { + // Ignore exports sets which are not for this target. + auto const& targets = exp.second.GetTargetExports(); + auto tgt_export = + std::find_if(targets.begin(), targets.end(), + [gt](std::unique_ptr<cmTargetExport> const& te) { + return te->Target == gt; + }); + if (tgt_export == targets.end()) { + continue; + } + + auto const* installs = exp.second.GetInstallations(); + for (auto const* install : *installs) { + Json::Value tdi_export_info = Json::objectValue; + + auto const& ns = install->GetNamespace(); + auto const& dest = install->GetDestination(); + auto const& cxxm_dir = install->GetCxxModuleDirectory(); + auto const& export_prefix = install->GetTempDir(); + + tdi_export_info["namespace"] = ns; + tdi_export_info["export-name"] = export_name; + tdi_export_info["destination"] = dest; + tdi_export_info["cxx-module-info-dir"] = cxxm_dir; + tdi_export_info["export-prefix"] = export_prefix; + tdi_export_info["install"] = true; + + tdi_exports.append(tdi_export_info); + } + } + + auto const& all_build_exports = gt->Makefile->GetExportBuildFileGenerators(); + for (auto const& exp : all_build_exports) { + std::vector<std::string> targets; + exp->GetTargets(targets); + + // Ignore exports sets which are not for this target. + auto const& name = gt->GetName(); + bool has_current_target = + std::any_of(targets.begin(), targets.end(), + [name](std::string const& tname) { return tname == name; }); + if (!has_current_target) { + continue; + } + + Json::Value tdi_export_info = Json::objectValue; + + auto const& ns = exp->GetNamespace(); + auto const& main_fn = exp->GetMainExportFileName(); + auto const& cxxm_dir = exp->GetCxxModuleDirectory(); + auto dest = cmsys::SystemTools::GetParentDirectory(main_fn); + auto const& export_prefix = + cmSystemTools::GetFilenamePath(exp->GetMainExportFileName()); + + tdi_export_info["namespace"] = ns; + tdi_export_info["export-name"] = export_name; + tdi_export_info["destination"] = dest; + tdi_export_info["cxx-module-info-dir"] = cxxm_dir; + tdi_export_info["export-prefix"] = export_prefix; + tdi_export_info["install"] = false; + + tdi_exports.append(tdi_export_info); + } + + return tdi_exports; +} +} + +void cmDyndepCollation::AddCollationInformation( + Json::Value& tdi, cmGeneratorTarget const* gt, std::string const& config, + cmDyndepGeneratorCallbacks const& cb) +{ + tdi["cxx-modules"] = CollationInformationCxxModules(gt, config, cb); + tdi["bmi-installation"] = CollationInformationBmiInstallation(gt, config); + tdi["exports"] = CollationInformationExports(gt); + tdi["config"] = config; +} + +struct CxxModuleFileSet +{ + std::string Name; + std::string RelativeDirectory; + std::string SourcePath; + std::string Type; + cmFileSetVisibility Visibility; + cm::optional<std::string> Destination; +}; + +struct CxxModuleBmiInstall +{ + std::string Component; + std::string Destination; + bool ExcludeFromAll; + bool Optional; + std::string Permissions; + std::string MessageLevel; + std::string ScriptLocation; +}; + +struct CxxModuleExport +{ + std::string Name; + std::string Destination; + std::string Prefix; + std::string CxxModuleInfoDir; + std::string Namespace; + bool Install; +}; + +struct cmCxxModuleExportInfo +{ + std::map<std::string, CxxModuleFileSet> ObjectToFileSet; + cm::optional<CxxModuleBmiInstall> BmiInstallation; + std::vector<CxxModuleExport> Exports; + std::string Config; +}; + +void cmCxxModuleExportInfoDeleter::operator()(cmCxxModuleExportInfo* ei) const +{ + delete ei; +} + +std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter> +cmDyndepCollation::ParseExportInfo(Json::Value const& tdi) +{ + auto export_info = + std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter>( + new cmCxxModuleExportInfo); + + export_info->Config = tdi["config"].asString(); + if (export_info->Config.empty()) { + export_info->Config = "noconfig"; + } + Json::Value const& tdi_exports = tdi["exports"]; + if (tdi_exports.isArray()) { + for (auto const& tdi_export : tdi_exports) { + CxxModuleExport exp; + exp.Install = tdi_export["install"].asBool(); + exp.Name = tdi_export["export-name"].asString(); + exp.Destination = tdi_export["destination"].asString(); + exp.Prefix = tdi_export["export-prefix"].asString(); + exp.CxxModuleInfoDir = tdi_export["cxx-module-info-dir"].asString(); + exp.Namespace = tdi_export["namespace"].asString(); + + export_info->Exports.push_back(exp); + } + } + auto const& bmi_installation = tdi["bmi-installation"]; + if (bmi_installation.isObject()) { + CxxModuleBmiInstall bmi_install; + + bmi_install.Component = bmi_installation["component"].asString(); + bmi_install.Destination = bmi_installation["destination"].asString(); + bmi_install.ExcludeFromAll = bmi_installation["exclude-from-all"].asBool(); + bmi_install.Optional = bmi_installation["optional"].asBool(); + bmi_install.Permissions = bmi_installation["permissions"].asString(); + bmi_install.MessageLevel = bmi_installation["message-level"].asString(); + bmi_install.ScriptLocation = + bmi_installation["script-location"].asString(); + + export_info->BmiInstallation = bmi_install; + } + Json::Value const& tdi_cxx_modules = tdi["cxx-modules"]; + if (tdi_cxx_modules.isObject()) { + for (auto i = tdi_cxx_modules.begin(); i != tdi_cxx_modules.end(); ++i) { + CxxModuleFileSet& fsi = export_info->ObjectToFileSet[i.key().asString()]; + auto const& tdi_cxx_module_info = *i; + fsi.Name = tdi_cxx_module_info["name"].asString(); + fsi.RelativeDirectory = + tdi_cxx_module_info["relative-directory"].asString(); + fsi.SourcePath = tdi_cxx_module_info["source"].asString(); + fsi.Type = tdi_cxx_module_info["type"].asString(); + fsi.Visibility = cmFileSetVisibilityFromName( + tdi_cxx_module_info["visibility"].asString(), nullptr); + auto const& tdi_fs_dest = tdi_cxx_module_info["destination"]; + if (tdi_fs_dest.isString()) { + fsi.Destination = tdi_fs_dest.asString(); + } + } + } + + return export_info; +} + +bool cmDyndepCollation::WriteDyndepMetadata( + std::string const& lang, std::vector<cmScanDepInfo> const& objects, + cmCxxModuleExportInfo const& export_info, + cmDyndepMetadataCallbacks const& cb) +{ + // Only C++ supports any of the file-set or BMI installation considered + // below. + if (lang != "CXX"_s) { + return true; + } + + bool result = true; + + // Prepare the export information blocks. + std::string const config_upper = + cmSystemTools::UpperCase(export_info.Config); + std::vector< + std::pair<std::unique_ptr<cmGeneratedFileStream>, CxxModuleExport const*>> + exports; + for (auto const& exp : export_info.Exports) { + std::unique_ptr<cmGeneratedFileStream> properties; + + std::string const export_dir = + cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/'); + std::string const property_file_path = cmStrCat( + export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake"); + properties = cm::make_unique<cmGeneratedFileStream>(property_file_path); + + // Set up the preamble. + *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name + << "\"\n" + << " PROPERTY IMPORTED_CXX_MODULES_" << config_upper << '\n'; + + exports.emplace_back(std::move(properties), &exp); + } + + std::unique_ptr<cmGeneratedFileStream> bmi_install_script; + if (export_info.BmiInstallation) { + bmi_install_script = cm::make_unique<cmGeneratedFileStream>( + export_info.BmiInstallation->ScriptLocation); + } + + auto cmEscape = [](cm::string_view str) { + return cmOutputConverter::EscapeForCMake( + str, cmOutputConverter::WrapQuotes::NoWrap); + }; + auto install_destination = + [&cmEscape](std::string const& dest) -> std::pair<bool, std::string> { + if (cmSystemTools::FileIsFullPath(dest)) { + return std::make_pair(true, cmEscape(dest)); + } + return std::make_pair(false, + cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest))); + }; + + // public/private requirement tracking. + std::set<std::string> private_modules; + std::map<std::string, std::set<std::string>> public_source_requires; + + for (cmScanDepInfo const& object : objects) { + // Convert to forward slashes. + auto output_path = object.PrimaryOutput; +#ifdef _WIN32 + cmSystemTools::ConvertToUnixSlashes(output_path); +#endif + // Find the fileset for this object. + auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path); + bool const has_provides = !object.Provides.empty(); + if (fileset_info_itr == export_info.ObjectToFileSet.end()) { + // If it provides anything, it should have a `CXX_MODULES` or + // `CXX_MODULE_INTERNAL_PARTITIONS` type and be present. + if (has_provides) { + // Take the first module provided to provide context. + auto const& provides = object.Provides[0]; + char const* ok_types = "`CXX_MODULES`"; + if (provides.LogicalName.find(':') != std::string::npos) { + ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if " + "it is not `export`ed)"; + } + cmSystemTools::Error(cmStrCat( + "Output ", object.PrimaryOutput, " provides the `", + provides.LogicalName, + "` module but it is not found in a `FILE_SET` of type ", ok_types)); + result = false; + } + + // This object file does not provide anything, so nothing more needs to + // be done. + continue; + } + + auto const& file_set = fileset_info_itr->second; + + // Verify the fileset type for the object. + if (file_set.Type == "CXX_MODULES"_s) { + if (!has_provides) { + cmSystemTools::Error( + cmStrCat("Output ", object.PrimaryOutput, + " is of type `CXX_MODULES` but does not provide a module")); + result = false; + continue; + } + } else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) { + if (!has_provides) { + cmSystemTools::Error( + cmStrCat("Source ", file_set.SourcePath, + " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not " + "provide a module")); + result = false; + continue; + } + auto const& provides = object.Provides[0]; + if (provides.LogicalName.find(':') == std::string::npos) { + cmSystemTools::Error( + cmStrCat("Source ", file_set.SourcePath, + " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not " + "provide a module partition")); + result = false; + continue; + } + } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) { + // TODO. + } else { + if (has_provides) { + auto const& provides = object.Provides[0]; + char const* ok_types = "`CXX_MODULES`"; + if (provides.LogicalName.find(':') != std::string::npos) { + ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if " + "it is not `export`ed)"; + } + cmSystemTools::Error( + cmStrCat("Source ", file_set.SourcePath, " provides the `", + provides.LogicalName, "` C++ module but is of type `", + file_set.Type, "` module but must be of type ", ok_types)); + result = false; + } + + // Not a C++ module; ignore. + continue; + } + + if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) { + // Nothing needs to be conveyed about non-`PUBLIC` modules. + for (auto const& p : object.Provides) { + private_modules.insert(p.LogicalName); + } + continue; + } + + // The module is public. Record what it directly requires. + { + auto& reqs = public_source_requires[file_set.SourcePath]; + for (auto const& r : object.Requires) { + reqs.insert(r.LogicalName); + } + } + + // Write out properties and install rules for any exports. + for (auto const& p : object.Provides) { + bool bmi_dest_is_abs = false; + std::string bmi_destination; + if (export_info.BmiInstallation) { + auto dest = + install_destination(export_info.BmiInstallation->Destination); + bmi_dest_is_abs = dest.first; + bmi_destination = cmStrCat(dest.second, '/'); + } + + std::string install_bmi_path; + std::string build_bmi_path; + auto m = cb.ModuleFile(p.LogicalName); + if (m) { + install_bmi_path = cmStrCat( + bmi_destination, cmEscape(cmSystemTools::GetFilenameName(*m))); + build_bmi_path = cmEscape(*m); + } + + for (auto const& exp : exports) { + std::string iface_source; + if (exp.second->Install && file_set.Destination) { + auto dest = install_destination(*file_set.Destination); + iface_source = cmStrCat( + dest.second, '/', cmEscape(file_set.RelativeDirectory), + cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath))); + } else { + iface_source = cmEscape(file_set.SourcePath); + } + + std::string bmi_path; + if (exp.second->Install && export_info.BmiInstallation) { + bmi_path = install_bmi_path; + } else if (!exp.second->Install) { + bmi_path = build_bmi_path; + } + + if (iface_source.empty()) { + // No destination for the C++ module source; ignore this property + // value. + continue; + } + + *exp.first << " \"" << cmEscape(p.LogicalName) << '=' + << iface_source; + if (!bmi_path.empty()) { + *exp.first << ',' << bmi_path; + } + *exp.first << "\"\n"; + } + + if (bmi_install_script) { + auto const& bmi_install = *export_info.BmiInstallation; + + *bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \"" + << cmEscape(bmi_install.Component) << '\"'; + if (!bmi_install.ExcludeFromAll) { + *bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT"; + } + *bmi_install_script << ")\n"; + *bmi_install_script << " file(INSTALL\n" + " DESTINATION \""; + if (!bmi_dest_is_abs) { + *bmi_install_script << "${CMAKE_INSTALL_PREFIX}/"; + } + *bmi_install_script << cmEscape(bmi_install.Destination) + << "\"\n" + " TYPE FILE\n"; + if (bmi_install.Optional) { + *bmi_install_script << " OPTIONAL\n"; + } + if (!bmi_install.MessageLevel.empty()) { + *bmi_install_script << " " << bmi_install.MessageLevel << "\n"; + } + if (!bmi_install.Permissions.empty()) { + *bmi_install_script << " PERMISSIONS" << bmi_install.Permissions + << "\n"; + } + *bmi_install_script << " FILES \"" << *m << "\")\n"; + if (bmi_dest_is_abs) { + *bmi_install_script + << " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n" + " \"" + << cmEscape(cmSystemTools::GetFilenameName(*m)) + << "\")\n" + " if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n" + " message(WARNING\n" + " \"ABSOLUTE path INSTALL DESTINATION : " + "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n" + " endif ()\n" + " if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n" + " message(FATAL_ERROR\n" + " \"ABSOLUTE path INSTALL DESTINATION forbidden (by " + "caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n" + " endif ()\n"; + } + *bmi_install_script << "endif ()\n"; + } + } + } + + // Add trailing parenthesis for the `set_property` call. + for (auto const& exp : exports) { + *exp.first << ")\n"; + } + + // Check that public sources only require public modules. + for (auto const& pub_reqs : public_source_requires) { + for (auto const& req : pub_reqs.second) { + if (private_modules.count(req)) { + cmSystemTools::Error(cmStrCat( + "Public C++ module source `", pub_reqs.first, "` requires the `", + req, "` C++ module which is provided by a private source")); + result = false; + } + } + } + + return result; +} diff --git a/Source/cmDyndepCollation.h b/Source/cmDyndepCollation.h new file mode 100644 index 0000000..e70ac09 --- /dev/null +++ b/Source/cmDyndepCollation.h @@ -0,0 +1,52 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <functional> +#include <memory> +#include <string> +#include <vector> + +#include <cm/optional> + +class cmGeneratorTarget; +struct cmScanDepInfo; +class cmSourceFile; + +namespace Json { +class Value; +} + +struct cmDyndepGeneratorCallbacks +{ + std::function<std::string(cmSourceFile const* sf, std::string const& config)> + ObjectFilePath; +}; + +struct cmDyndepMetadataCallbacks +{ + std::function<cm::optional<std::string>(std::string const& name)> ModuleFile; +}; + +struct cmCxxModuleExportInfo; +struct cmCxxModuleExportInfoDeleter +{ + void operator()(cmCxxModuleExportInfo* ei) const; +}; + +struct cmDyndepCollation +{ + static void AddCollationInformation(Json::Value& tdi, + cmGeneratorTarget const* gt, + std::string const& config, + cmDyndepGeneratorCallbacks const& cb); + + static std::unique_ptr<cmCxxModuleExportInfo, cmCxxModuleExportInfoDeleter> + ParseExportInfo(Json::Value const& tdi); + static bool WriteDyndepMetadata(std::string const& lang, + std::vector<cmScanDepInfo> const& objects, + cmCxxModuleExportInfo const& export_info, + cmDyndepMetadataCallbacks const& cb); +}; diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx index 922b53f..c890e4b 100644 --- a/Source/cmExperimental.cxx +++ b/Source/cmExperimental.cxx @@ -27,7 +27,7 @@ struct FeatureData bool Warned; } LookupTable[] = { // CxxModuleCMakeApi - { "3c375311-a3c9-4396-a187-3227ef642046", + { "2182bf5c-ef0d-489a-91da-49dbc3090d2a", "CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API", "CMake's C++ module support is experimental. It is meant only for " "experimentation and feedback to CMake developers.", diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 50bc78c..c8e2cb8 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -379,7 +379,7 @@ void cmExportFileGenerator::PopulateIncludeDirectoriesInterface( const char* propName = "INTERFACE_INCLUDE_DIRECTORIES"; cmValue input = target->GetProperty(propName); - cmGeneratorExpression ge; + cmGeneratorExpression ge(*target->Makefile->GetCMakeInstance()); std::string dirs = cmGeneratorExpression::Preprocess( cmJoin(target->Target->GetInstallIncludeDirectoriesEntries(te), ";"), @@ -669,8 +669,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( while ((pos = input.find("$<TARGET_PROPERTY:", lastPos)) != std::string::npos) { - std::string::size_type nameStartPos = - pos + sizeof("$<TARGET_PROPERTY:") - 1; + std::string::size_type nameStartPos = pos + cmStrLen("$<TARGET_PROPERTY:"); std::string::size_type closePos = input.find('>', nameStartPos); std::string::size_type commaPos = input.find(',', nameStartPos); std::string::size_type nextOpenPos = input.find("$<", nameStartPos); @@ -696,7 +695,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( pos = 0; lastPos = pos; while ((pos = input.find("$<TARGET_NAME:", lastPos)) != std::string::npos) { - std::string::size_type nameStartPos = pos + sizeof("$<TARGET_NAME:") - 1; + std::string::size_type nameStartPos = pos + cmStrLen("$<TARGET_NAME:"); std::string::size_type endPos = input.find('>', nameStartPos); if (endPos == std::string::npos) { errorString = "$<TARGET_NAME:...> expression incomplete"; @@ -721,7 +720,7 @@ void cmExportFileGenerator::ResolveTargetsInGeneratorExpression( lastPos = pos; while (errorString.empty() && (pos = input.find("$<LINK_ONLY:", lastPos)) != std::string::npos) { - std::string::size_type nameStartPos = pos + sizeof("$<LINK_ONLY:") - 1; + std::string::size_type nameStartPos = pos + cmStrLen("$<LINK_ONLY:"); std::string::size_type endPos = input.find('>', nameStartPos); if (endPos == std::string::npos) { errorString = "$<LINK_ONLY:...> expression incomplete"; @@ -939,13 +938,13 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os) // Isolate the file policy level. // Support CMake versions as far back as 2.6 but also support using NEW - // policy settings for up to CMake 3.23 (this upper limit may be reviewed + // policy settings for up to CMake 3.24 (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.8.3...3.23)\n"; + << "cmake_policy(VERSION 2.8.3...3.24)\n"; /* clang-format on */ } diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 195737b..5e190f4 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -570,7 +570,7 @@ std::string cmExportInstallFileGenerator::GetFileSetDirectories( auto configs = gte->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); - cmGeneratorExpression ge; + cmGeneratorExpression ge(*gte->Makefile->GetCMakeInstance()); auto cge = ge.Parse(te->FileSetGenerators.at(fileSet)->GetDestination()); for (auto const& config : configs) { @@ -617,7 +617,7 @@ std::string cmExportInstallFileGenerator::GetFileSetFiles( auto fileEntries = fileSet->CompileFileEntries(); auto directoryEntries = fileSet->CompileDirectoryEntries(); - cmGeneratorExpression destGe; + cmGeneratorExpression destGe(*gte->Makefile->GetCMakeInstance()); auto destCge = destGe.Parse(te->FileSetGenerators.at(fileSet)->GetDestination()); diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index e98aa05..33c057d 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -70,7 +70,7 @@ std::string cmExportTryCompileFileGenerator::FindTargets( return std::string(); } - cmGeneratorExpression ge; + cmGeneratorExpression ge(*tgt->Makefile->GetCMakeInstance()); std::unique_ptr<cmGeneratorExpressionDAGChecker> parentDagChecker; if (propName == "INTERFACE_LINK_OPTIONS") { diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx index 7f8374d..d1d3d25 100644 --- a/Source/cmFileAPI.cxx +++ b/Source/cmFileAPI.cxx @@ -18,6 +18,7 @@ #include "cmFileAPICMakeFiles.h" #include "cmFileAPICache.h" #include "cmFileAPICodemodel.h" +#include "cmFileAPIConfigureLog.h" #include "cmFileAPIToolchains.h" #include "cmGlobalGenerator.h" #include "cmStringAlgorithms.h" @@ -66,6 +67,26 @@ void cmFileAPI::ReadQueries() } } +std::vector<unsigned long> cmFileAPI::GetConfigureLogVersions() +{ + std::vector<unsigned long> versions; + auto getConfigureLogVersions = [&versions](Query const& q) { + for (Object const& o : q.Known) { + if (o.Kind == ObjectKind::ConfigureLog) { + versions.emplace_back(o.Version); + } + } + }; + getConfigureLogVersions(this->TopQuery); + for (auto const& client : this->ClientQueries) { + getConfigureLogVersions(client.second.DirQuery); + } + std::sort(versions.begin(), versions.end()); + versions.erase(std::unique(versions.begin(), versions.end()), + versions.end()); + return versions; +} + void cmFileAPI::WriteReplies() { if (this->QueryExists) { @@ -241,6 +262,17 @@ bool cmFileAPI::ReadQuery(std::string const& query, objects.push_back(o); return true; } + if (kindName == ObjectKindName(ObjectKind::ConfigureLog)) { + Object o; + o.Kind = ObjectKind::ConfigureLog; + if (verStr == "v1") { + o.Version = 1; + } else { + return false; + } + objects.push_back(o); + return true; + } if (kindName == ObjectKindName(ObjectKind::Cache)) { Object o; o.Kind = ObjectKind::Cache; @@ -411,11 +443,12 @@ const char* cmFileAPI::ObjectKindName(ObjectKind kind) { // Keep in sync with ObjectKind enum. static const char* objectKindNames[] = { - "codemodel", // - "cache", // - "cmakeFiles", // - "toolchains", // - "__test" // + "codemodel", // + "configureLog", // + "cache", // + "cmakeFiles", // + "toolchains", // + "__test" // }; return objectKindNames[static_cast<size_t>(kind)]; } @@ -442,6 +475,9 @@ Json::Value cmFileAPI::BuildObject(Object const& object) case ObjectKind::CodeModel: value = this->BuildCodeModel(object); break; + case ObjectKind::ConfigureLog: + value = this->BuildConfigureLog(object); + break; case ObjectKind::Cache: value = this->BuildCache(object); break; @@ -503,6 +539,8 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest( if (kindName == this->ObjectKindName(ObjectKind::CodeModel)) { r.Kind = ObjectKind::CodeModel; + } else if (kindName == this->ObjectKindName(ObjectKind::ConfigureLog)) { + r.Kind = ObjectKind::ConfigureLog; } else if (kindName == this->ObjectKindName(ObjectKind::Cache)) { r.Kind = ObjectKind::Cache; } else if (kindName == this->ObjectKindName(ObjectKind::CMakeFiles)) { @@ -530,6 +568,9 @@ cmFileAPI::ClientRequest cmFileAPI::BuildClientRequest( case ObjectKind::CodeModel: this->BuildClientRequestCodeModel(r, versions); break; + case ObjectKind::ConfigureLog: + this->BuildClientRequestConfigureLog(r, versions); + break; case ObjectKind::Cache: this->BuildClientRequestCache(r, versions); break; @@ -687,7 +728,7 @@ std::string cmFileAPI::NoSupportedVersion( // The "codemodel" object kind. // Update Help/manual/cmake-file-api.7.rst when updating this constant. -static unsigned int const CodeModelV2Minor = 4; +static unsigned int const CodeModelV2Minor = 5; void cmFileAPI::BuildClientRequestCodeModel( ClientRequest& r, std::vector<RequestVersion> const& versions) @@ -719,6 +760,41 @@ Json::Value cmFileAPI::BuildCodeModel(Object const& object) return codemodel; } +// The "configureLog" object kind. + +// Update Help/manual/cmake-file-api.7.rst when updating this constant. +static unsigned int const ConfigureLogV1Minor = 0; + +void cmFileAPI::BuildClientRequestConfigureLog( + ClientRequest& r, std::vector<RequestVersion> const& versions) +{ + // Select a known version from those requested. + for (RequestVersion const& v : versions) { + if ((v.Major == 1 && v.Minor <= ConfigureLogV1Minor)) { + r.Version = v.Major; + break; + } + } + if (!r.Version) { + r.Error = NoSupportedVersion(versions); + } +} + +Json::Value cmFileAPI::BuildConfigureLog(Object const& object) +{ + Json::Value configureLog = cmFileAPIConfigureLogDump(*this, object.Version); + configureLog["kind"] = this->ObjectKindName(object.Kind); + + Json::Value& version = configureLog["version"]; + if (object.Version == 1) { + version = BuildVersion(1, ConfigureLogV1Minor); + } else { + return configureLog; // should be unreachable + } + + return configureLog; +} + // The "cache" object kind. static unsigned int const CacheV2Minor = 0; @@ -870,6 +946,14 @@ Json::Value cmFileAPI::ReportCapabilities() { Json::Value request = Json::objectValue; + request["kind"] = ObjectKindName(ObjectKind::ConfigureLog); + Json::Value& versions = request["version"] = Json::arrayValue; + versions.append(BuildVersion(1, ConfigureLogV1Minor)); + requests.append(std::move(request)); // NOLINT(*) + } + + { + Json::Value request = Json::objectValue; request["kind"] = ObjectKindName(ObjectKind::Cache); Json::Value& versions = request["version"] = Json::arrayValue; versions.append(BuildVersion(2, CacheV2Minor)); diff --git a/Source/cmFileAPI.h b/Source/cmFileAPI.h index 22302b4..6d7678f 100644 --- a/Source/cmFileAPI.h +++ b/Source/cmFileAPI.h @@ -24,6 +24,9 @@ public: /** Read fileapi queries from disk. */ void ReadQueries(); + /** Get the list of configureLog object kind versions requested. */ + std::vector<unsigned long> GetConfigureLogVersions(); + /** Write fileapi replies to disk. */ void WriteReplies(); @@ -54,6 +57,7 @@ private: enum class ObjectKind { CodeModel, + ConfigureLog, Cache, CMakeFiles, Toolchains, @@ -193,6 +197,10 @@ private: ClientRequest& r, std::vector<RequestVersion> const& versions); Json::Value BuildCodeModel(Object const& object); + void BuildClientRequestConfigureLog( + ClientRequest& r, std::vector<RequestVersion> const& versions); + Json::Value BuildConfigureLog(Object const& object); + void BuildClientRequestCache(ClientRequest& r, std::vector<RequestVersion> const& versions); Json::Value BuildCache(Object const& object); diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index 0581802..d3683d4 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -17,6 +17,7 @@ #include <cm/string_view> #include <cmext/algorithm> +#include <cmext/string_view> #include <cm3p/json/value.h> @@ -44,6 +45,7 @@ #include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmSourceFile.h" #include "cmSourceGroup.h" #include "cmState.h" @@ -434,6 +436,8 @@ class Target std::unordered_map<CompileData, Json::ArrayIndex> CompileGroupMap; std::vector<CompileGroup> CompileGroups; + using FileSetDatabase = std::map<std::string, Json::ArrayIndex>; + template <typename T> JBT<T> ToJBT(BT<T> const& bt) { @@ -444,6 +448,7 @@ class Target JBTs<T> ToJBTs(BTs<T> const& bts) { std::vector<JBTIndex> ids; + ids.reserve(bts.Backtraces.size()); for (cmListFileBacktrace const& backtrace : bts.Backtraces) { ids.emplace_back(this->Backtraces.Add(backtrace)); } @@ -466,9 +471,12 @@ class Target Json::Value DumpPrecompileHeader(JBT<std::string> const& header); Json::Value DumpLanguageStandard(JBTs<std::string> const& standard); Json::Value DumpDefine(JBT<std::string> const& def); - Json::Value DumpSources(); + std::pair<Json::Value, FileSetDatabase> DumpFileSets(); + Json::Value DumpFileSet(cmFileSet const* fs, + std::vector<std::string> const& directories); + Json::Value DumpSources(FileSetDatabase const& fsdb); Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk, - Json::ArrayIndex si); + Json::ArrayIndex si, FileSetDatabase const& fsdb); Json::Value DumpSourceGroups(); Json::Value DumpSourceGroup(SourceGroup& sg); Json::Value DumpCompileGroups(); @@ -1216,7 +1224,13 @@ Json::Value Target::Dump() { this->ProcessLanguages(); - target["sources"] = this->DumpSources(); + auto fileSetInfo = this->DumpFileSets(); + + if (!fileSetInfo.first.isNull()) { + target["fileSets"] = fileSetInfo.first; + } + + target["sources"] = this->DumpSources(fileSetInfo.second); Json::Value folder = this->DumpFolder(); if (!folder.isNull()) { @@ -1527,29 +1541,113 @@ Json::Value Target::DumpPaths() return paths; } -Json::Value Target::DumpSources() +std::pair<Json::Value, Target::FileSetDatabase> Target::DumpFileSets() +{ + Json::Value fsJson = Json::nullValue; + FileSetDatabase fsdb; + + // Build the fileset database. + auto const* tgt = this->GT->Target; + auto const& fs_names = tgt->GetAllFileSetNames(); + + if (!fs_names.empty()) { + fsJson = Json::arrayValue; + size_t fsIndex = 0; + for (auto const& fs_name : fs_names) { + auto const* fs = tgt->GetFileSet(fs_name); + if (!fs) { + this->GT->Makefile->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), + "\" is tracked to have file set \"", fs_name, + "\", but it was not found.")); + continue; + } + + auto fileEntries = fs->CompileFileEntries(); + auto directoryEntries = fs->CompileDirectoryEntries(); + + auto directories = fs->EvaluateDirectoryEntries( + directoryEntries, this->GT->LocalGenerator, this->Config, this->GT); + + fsJson.append(this->DumpFileSet(fs, directories)); + + std::map<std::string, std::vector<std::string>> files_per_dirs; + for (auto const& entry : fileEntries) { + fs->EvaluateFileEntry(directories, files_per_dirs, entry, + this->GT->LocalGenerator, this->Config, + this->GT); + } + + for (auto const& files_per_dir : files_per_dirs) { + auto const& dir = files_per_dir.first; + for (auto const& file : files_per_dir.second) { + std::string sf_path; + if (dir.empty()) { + sf_path = file; + } else { + sf_path = cmStrCat(dir, '/', file); + } + fsdb[sf_path] = static_cast<Json::ArrayIndex>(fsIndex); + } + } + + ++fsIndex; + } + } + + return std::make_pair(fsJson, fsdb); +} + +Json::Value Target::DumpFileSet(cmFileSet const* fs, + std::vector<std::string> const& directories) +{ + Json::Value fileSet = Json::objectValue; + + fileSet["name"] = fs->GetName(); + fileSet["type"] = fs->GetType(); + fileSet["visibility"] = + std::string(cmFileSetVisibilityToName(fs->GetVisibility())); + + Json::Value baseDirs = Json::arrayValue; + for (auto const& directory : directories) { + baseDirs.append(directory); + } + fileSet["baseDirectories"] = baseDirs; + + return fileSet; +} + +Json::Value Target::DumpSources(FileSetDatabase const& fsdb) { Json::Value sources = Json::arrayValue; cmGeneratorTarget::KindedSources const& kinded = this->GT->GetKindedSources(this->Config); for (cmGeneratorTarget::SourceAndKind const& sk : kinded.Sources) { - sources.append(this->DumpSource(sk, sources.size())); + sources.append(this->DumpSource(sk, sources.size(), fsdb)); } return sources; } Json::Value Target::DumpSource(cmGeneratorTarget::SourceAndKind const& sk, - Json::ArrayIndex si) + Json::ArrayIndex si, + FileSetDatabase const& fsdb) { Json::Value source = Json::objectValue; - std::string const path = sk.Source.Value->ResolveFullPath(); + cmSourceFile* sf = sk.Source.Value; + std::string const path = sf->ResolveFullPath(); source["path"] = RelativeIfUnder(this->TopSource, path); if (sk.Source.Value->GetIsGenerated()) { source["isGenerated"] = true; } this->AddBacktrace(source, sk.Source.Backtrace); + auto fsit = fsdb.find(path); + if (fsit != fsdb.end()) { + source["fileSetIndex"] = fsit->second; + } + if (cmSourceGroup* sg = this->GT->Makefile->FindSourceGroup(path, this->SourceGroupsLocal)) { source["sourceGroupIndex"] = this->AddSourceGroup(sg, si); diff --git a/Source/cmFileAPIConfigureLog.cxx b/Source/cmFileAPIConfigureLog.cxx new file mode 100644 index 0000000..50189cb --- /dev/null +++ b/Source/cmFileAPIConfigureLog.cxx @@ -0,0 +1,67 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmFileAPIConfigureLog.h" + +#include <cm3p/json/value.h> + +#include "cmFileAPI.h" +#include "cmStringAlgorithms.h" +#include "cmake.h" + +namespace { + +class ConfigureLog +{ + cmFileAPI& FileAPI; + unsigned long Version; + + Json::Value DumpPath(); + Json::Value DumpEventKindNames(); + +public: + ConfigureLog(cmFileAPI& fileAPI, unsigned long version); + Json::Value Dump(); +}; + +ConfigureLog::ConfigureLog(cmFileAPI& fileAPI, unsigned long version) + : FileAPI(fileAPI) + , Version(version) +{ + static_cast<void>(this->Version); +} + +Json::Value ConfigureLog::Dump() +{ + Json::Value configureLog = Json::objectValue; + configureLog["path"] = this->DumpPath(); + configureLog["eventKindNames"] = this->DumpEventKindNames(); + return configureLog; +} + +Json::Value ConfigureLog::DumpPath() +{ + return cmStrCat(this->FileAPI.GetCMakeInstance()->GetHomeOutputDirectory(), + "/CMakeFiles/CMakeConfigureLog.yaml"); +} + +Json::Value ConfigureLog::DumpEventKindNames() +{ + // Report at most one version of each event kind. + // If a new event kind is added, increment ConfigureLogV1Minor. + // If a new version of an existing event kind is added, a new + // major version of the configureLog object kind is needed. + Json::Value eventKindNames = Json::arrayValue; + if (this->Version == 1) { + eventKindNames.append("try_compile-v1"); // WriteTryCompileEvent + eventKindNames.append("try_run-v1"); // WriteTryRunEvent + } + return eventKindNames; +} +} + +Json::Value cmFileAPIConfigureLogDump(cmFileAPI& fileAPI, + unsigned long version) +{ + ConfigureLog configureLog(fileAPI, version); + return configureLog.Dump(); +} diff --git a/Source/cmFileAPIConfigureLog.h b/Source/cmFileAPIConfigureLog.h new file mode 100644 index 0000000..deaa403 --- /dev/null +++ b/Source/cmFileAPIConfigureLog.h @@ -0,0 +1,12 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include "cmConfigure.h" // IWYU pragma: keep + +#include <cm3p/json/value.h> + +class cmFileAPI; + +extern Json::Value cmFileAPIConfigureLogDump(cmFileAPI& fileAPI, + unsigned long version); diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index fe38db5..dfce033 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -845,8 +845,10 @@ bool HandleMakeDirectoryCommand(std::vector<std::string> const& args, cmSystemTools::SetFatalErrorOccurred(); return false; } - if (!cmSystemTools::MakeDirectory(*cdir)) { - std::string error = "problem creating directory: " + *cdir; + cmsys::Status mkdirStatus = cmSystemTools::MakeDirectory(*cdir); + if (!mkdirStatus) { + std::string error = cmStrCat("failed to create directory:\n ", *cdir, + "\nbecause: ", mkdirStatus.GetString()); status.SetError(error); return false; } @@ -1408,12 +1410,14 @@ bool HandleCopyFile(std::vector<std::string> const& args, struct Arguments { + bool InputMayBeRecent = false; bool OnlyIfDifferent = false; std::string Result; }; static auto const parser = cmArgumentParser<Arguments>{} + .Bind("INPUT_MAY_BE_RECENT"_s, &Arguments::InputMayBeRecent) .Bind("ONLY_IF_DIFFERENT"_s, &Arguments::OnlyIfDifferent) .Bind("RESULT"_s, &Arguments::Result); @@ -1456,9 +1460,13 @@ bool HandleCopyFile(std::vector<std::string> const& args, } else { when = cmSystemTools::CopyWhen::Always; } + cmSystemTools::CopyInputRecent const inputRecent = arguments.InputMayBeRecent + ? cmSystemTools::CopyInputRecent::Yes + : cmSystemTools::CopyInputRecent::No; std::string err; - if (cmSystemTools::CopySingleFile(oldname, newname, when, &err) == + if (cmSystemTools::CopySingleFile(oldname, newname, when, inputRecent, + &err) == cmSystemTools::CopyResult::Success) { if (!arguments.Result.empty()) { status.GetMakefile().AddDefinition(arguments.Result, "0"); @@ -2107,6 +2115,14 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, // Verify MD5 sum if requested: // if (hash) { + if (res != CURLE_OK) { + status.SetError(cmStrCat( + "DOWNLOAD cannot compute hash on failed download\n" + " status: [", + static_cast<int>(res), ";\"", ::curl_easy_strerror(res), "\"]")); + return false; + } + std::string actualHash = hash->HashFile(file); if (actualHash.empty()) { status.SetError("DOWNLOAD cannot compute hash on downloaded file"); @@ -2130,11 +2146,7 @@ bool HandleDownloadCommand(std::vector<std::string> const& args, expectedHash, "]\n" " actual hash: [", - actualHash, - "]\n" - " status: [", - static_cast<int>(res), ";\"", - ::curl_easy_strerror(res), "\"]\n")); + actualHash, "]\n")); return false; } } @@ -2458,11 +2470,13 @@ void AddEvaluationFile(const std::string& inputName, { cmListFileBacktrace lfbt = status.GetMakefile().GetBacktrace(); - cmGeneratorExpression outputGe(lfbt); + cmGeneratorExpression outputGe(*status.GetMakefile().GetCMakeInstance(), + lfbt); std::unique_ptr<cmCompiledGeneratorExpression> outputCge = outputGe.Parse(outputExpr); - cmGeneratorExpression conditionGe(lfbt); + cmGeneratorExpression conditionGe(*status.GetMakefile().GetCMakeInstance(), + lfbt); std::unique_ptr<cmCompiledGeneratorExpression> conditionCge = conditionGe.Parse(condition); @@ -3398,20 +3412,29 @@ bool HandleArchiveCreateCommand(std::vector<std::string> const& args, } int compressionLevel = 0; + int minCompressionLevel = 0; + int maxCompressionLevel = 9; + if (compress == cmSystemTools::TarCompressZstd) { + maxCompressionLevel = 19; + } + if (!parsedArgs.CompressionLevel.empty()) { if (parsedArgs.CompressionLevel.size() != 1 && !std::isdigit(parsedArgs.CompressionLevel[0])) { - status.SetError(cmStrCat("compression level ", - parsedArgs.CompressionLevel, - " should be in range 0 to 9")); + status.SetError( + cmStrCat("compression level ", parsedArgs.CompressionLevel, " for ", + parsedArgs.Compression, " should be in range ", + minCompressionLevel, " to ", maxCompressionLevel)); cmSystemTools::SetFatalErrorOccurred(); return false; } compressionLevel = std::stoi(parsedArgs.CompressionLevel); - if (compressionLevel < 0 || compressionLevel > 9) { - status.SetError(cmStrCat("compression level ", - parsedArgs.CompressionLevel, - " should be in range 0 to 9")); + if (compressionLevel < minCompressionLevel || + compressionLevel > maxCompressionLevel) { + status.SetError( + cmStrCat("compression level ", parsedArgs.CompressionLevel, " for ", + parsedArgs.Compression, " should be in range ", + minCompressionLevel, " to ", maxCompressionLevel)); cmSystemTools::SetFatalErrorOccurred(); return false; } diff --git a/Source/cmFileLockPool.cxx b/Source/cmFileLockPool.cxx index 99f6885..c23a99c 100644 --- a/Source/cmFileLockPool.cxx +++ b/Source/cmFileLockPool.cxx @@ -15,7 +15,7 @@ cmFileLockPool::~cmFileLockPool() = default; void cmFileLockPool::PushFunctionScope() { - this->FunctionScopes.push_back(ScopePool()); + this->FunctionScopes.emplace_back(); } void cmFileLockPool::PopFunctionScope() @@ -26,7 +26,7 @@ void cmFileLockPool::PopFunctionScope() void cmFileLockPool::PushFileScope() { - this->FileScopes.push_back(ScopePool()); + this->FileScopes.emplace_back(); } void cmFileLockPool::PopFileScope() diff --git a/Source/cmFileSet.cxx b/Source/cmFileSet.cxx index d6665a2..b96ba6e 100644 --- a/Source/cmFileSet.cxx +++ b/Source/cmFileSet.cxx @@ -78,9 +78,10 @@ bool cmFileSetVisibilityIsForInterface(cmFileSetVisibility vis) return false; } -cmFileSet::cmFileSet(std::string name, std::string type, +cmFileSet::cmFileSet(cmake& cmakeInstance, std::string name, std::string type, cmFileSetVisibility visibility) - : Name(std::move(name)) + : CMakeInstance(cmakeInstance) + , Name(std::move(name)) , Type(std::move(type)) , Visibility(visibility) { @@ -113,7 +114,7 @@ cmFileSet::CompileFileEntries() const for (auto const& entry : this->FileEntries) { for (auto const& ex : cmExpandedList(entry.Value)) { - cmGeneratorExpression ge(entry.Backtrace); + cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace); auto cge = ge.Parse(ex); result.push_back(std::move(cge)); } @@ -129,7 +130,7 @@ cmFileSet::CompileDirectoryEntries() const for (auto const& entry : this->DirectoryEntries) { for (auto const& ex : cmExpandedList(entry.Value)) { - cmGeneratorExpression ge(entry.Backtrace); + cmGeneratorExpression ge(this->CMakeInstance, entry.Backtrace); auto cge = ge.Parse(ex); result.push_back(std::move(cge)); } diff --git a/Source/cmFileSet.h b/Source/cmFileSet.h index 5357e77..54d430c 100644 --- a/Source/cmFileSet.h +++ b/Source/cmFileSet.h @@ -17,6 +17,7 @@ struct cmGeneratorExpressionDAGChecker; class cmGeneratorTarget; class cmLocalGenerator; class cmMakefile; +class cmake; enum class cmFileSetVisibility { @@ -33,7 +34,7 @@ bool cmFileSetVisibilityIsForInterface(cmFileSetVisibility vis); class cmFileSet { public: - cmFileSet(std::string name, std::string type, + cmFileSet(cmake& cmakeInstance, std::string name, std::string type, cmFileSetVisibility visibility); const std::string& GetName() const { return this->Name; } @@ -77,6 +78,7 @@ public: static bool IsValidName(const std::string& name); private: + cmake& CMakeInstance; std::string Name; std::string Type; cmFileSetVisibility Visibility; diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 3f8378b..71c7e13 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -377,6 +377,10 @@ private: # pragma diag_suppress 1222 // invalid error number (3288, but works anyway) # define CM_LCC_DIAG_SUPPRESS_3288 # pragma diag_suppress 3288 // parameter was declared but never referenced +# define CM_LCC_DIAG_SUPPRESS_3301 +# pragma diag_suppress 3301 // parameter was declared but never referenced +# define CM_LCC_DIAG_SUPPRESS_3308 +# pragma diag_suppress 3308 // parameter was declared but never referenced #endif void ResetGenerator() @@ -421,6 +425,16 @@ bool TryGeneratedPaths(CallbackFn&& filesCollector, return false; } +#ifdef CM_LCC_DIAG_SUPPRESS_3308 +# undef CM_LCC_DIAG_SUPPRESS_3308 +# pragma diag_default 3308 +#endif + +#ifdef CM_LCC_DIAG_SUPPRESS_3301 +# undef CM_LCC_DIAG_SUPPRESS_3301 +# pragma diag_default 3301 +#endif + #ifdef CM_LCC_DIAG_SUPPRESS_3288 # undef CM_LCC_DIAG_SUPPRESS_3288 # pragma diag_default 3288 diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx index c72d6a7..133bf5f 100644 --- a/Source/cmGeneratedFileStream.cxx +++ b/Source/cmGeneratedFileStream.cxx @@ -27,7 +27,7 @@ cmGeneratedFileStream::cmGeneratedFileStream(Encoding encoding) cmGeneratedFileStream::cmGeneratedFileStream(std::string const& name, bool quiet, Encoding encoding) : cmGeneratedFileStreamBase(name) - , Stream(this->TempName.c_str()) + , Stream(this->TempName.c_str()) // NOLINT(cmake-use-cmsys-fstream) { // Check if the file opened. if (!*this && !quiet) { @@ -67,10 +67,11 @@ cmGeneratedFileStream& cmGeneratedFileStream::Open(std::string const& name, // Open the temporary output file. if (binaryFlag) { - this->Stream::open(this->TempName.c_str(), - std::ios::out | std::ios::binary); + this->Stream::open( // NOLINT(cmake-use-cmsys-fstream) + this->TempName.c_str(), std::ios::out | std::ios::binary); } else { - this->Stream::open(this->TempName.c_str()); + this->Stream::open( // NOLINT(cmake-use-cmsys-fstream) + this->TempName.c_str()); } // Check if the file opened. @@ -87,7 +88,7 @@ bool cmGeneratedFileStream::Close() this->Okay = !this->fail(); // Close the temporary output file. - this->Stream::close(); + this->Stream::close(); // NOLINT(cmake-use-cmsys-fstream) // Remove the temporary file (possibly by renaming to the real file). return this->cmGeneratedFileStreamBase::Close(); diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx index f988e54..c5ae31b 100644 --- a/Source/cmGeneratorExpression.cxx +++ b/Source/cmGeneratorExpression.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGeneratorExpression.h" +#include <algorithm> #include <cassert> #include <memory> #include <utility> @@ -13,11 +14,15 @@ #include "cmGeneratorExpressionEvaluator.h" #include "cmGeneratorExpressionLexer.h" #include "cmGeneratorExpressionParser.h" +#include "cmLocalGenerator.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmake.h" -cmGeneratorExpression::cmGeneratorExpression(cmListFileBacktrace backtrace) - : Backtrace(std::move(backtrace)) +cmGeneratorExpression::cmGeneratorExpression(cmake& cmakeInstance, + cmListFileBacktrace backtrace) + : CMakeInstance(cmakeInstance) + , Backtrace(std::move(backtrace)) { } @@ -29,7 +34,8 @@ std::unique_ptr<cmCompiledGeneratorExpression> cmGeneratorExpression::Parse( std::string input) const { return std::unique_ptr<cmCompiledGeneratorExpression>( - new cmCompiledGeneratorExpression(this->Backtrace, std::move(input))); + new cmCompiledGeneratorExpression(this->CMakeInstance, this->Backtrace, + std::move(input))); } std::string cmGeneratorExpression::Evaluate( @@ -39,7 +45,13 @@ std::string cmGeneratorExpression::Evaluate( cmGeneratorTarget const* currentTarget, std::string const& language) { if (Find(input) != std::string::npos) { - cmCompiledGeneratorExpression cge(cmListFileBacktrace(), std::move(input)); +#ifndef CMAKE_BOOTSTRAP + auto profilingRAII = lg->GetCMakeInstance()->CreateProfilingEntry( + "genex_compile_eval", input); +#endif + + cmCompiledGeneratorExpression cge(*lg->GetCMakeInstance(), + cmListFileBacktrace(), std::move(input)); return cge.Evaluate(lg, config, headTarget, dagChecker, currentTarget, language); } @@ -97,10 +109,15 @@ const std::string& cmCompiledGeneratorExpression::EvaluateWithContext( } cmCompiledGeneratorExpression::cmCompiledGeneratorExpression( - cmListFileBacktrace backtrace, std::string input) + cmake& cmakeInstance, cmListFileBacktrace backtrace, std::string input) : Backtrace(std::move(backtrace)) , Input(std::move(input)) { +#ifndef CMAKE_BOOTSTRAP + auto profilingRAII = + cmakeInstance.CreateProfilingEntry("genex_compile", this->Input); +#endif + cmGeneratorExpressionLexer l; std::vector<cmGeneratorExpressionToken> tokens = l.Tokenize(this->Input); this->NeedsEvaluation = l.GetSawGeneratorExpression(); @@ -210,23 +227,33 @@ static std::string stripExportInterface( while (true) { std::string::size_type bPos = input.find("$<BUILD_INTERFACE:", lastPos); std::string::size_type iPos = input.find("$<INSTALL_INTERFACE:", lastPos); + std::string::size_type lPos = + input.find("$<BUILD_LOCAL_INTERFACE:", lastPos); - if (bPos == std::string::npos && iPos == std::string::npos) { + pos = std::min({ bPos, iPos, lPos }); + if (pos == std::string::npos) { break; } - if (bPos == std::string::npos) { - pos = iPos; - } else if (iPos == std::string::npos) { - pos = bPos; + result += input.substr(lastPos, pos - lastPos); + enum class FoundGenex + { + BuildInterface, + InstallInterface, + BuildLocalInterface, + } foundGenex = FoundGenex::BuildInterface; + if (pos == bPos) { + foundGenex = FoundGenex::BuildInterface; + pos += cmStrLen("$<BUILD_INTERFACE:"); + } else if (pos == iPos) { + foundGenex = FoundGenex::InstallInterface; + pos += cmStrLen("$<INSTALL_INTERFACE:"); + } else if (pos == lPos) { + foundGenex = FoundGenex::BuildLocalInterface; + pos += cmStrLen("$<BUILD_LOCAL_INTERFACE:"); } else { - pos = (bPos < iPos) ? bPos : iPos; + assert(false && "Invalid position found"); } - - result += input.substr(lastPos, pos - lastPos); - const bool gotInstallInterface = input[pos + 2] == 'I'; - pos += gotInstallInterface ? sizeof("$<INSTALL_INTERFACE:") - 1 - : sizeof("$<BUILD_INTERFACE:") - 1; nestingLevel = 1; const char* c = input.c_str() + pos; const char* const cStart = c; @@ -242,10 +269,10 @@ static std::string stripExportInterface( continue; } if (context == cmGeneratorExpression::BuildInterface && - !gotInstallInterface) { + foundGenex == FoundGenex::BuildInterface) { result += input.substr(pos, c - cStart); } else if (context == cmGeneratorExpression::InstallInterface && - gotInstallInterface) { + foundGenex == FoundGenex::InstallInterface) { const std::string content = input.substr(pos, c - cStart); if (resolveRelative) { prefixItems(content, result, "${_IMPORT_PREFIX}/"); @@ -258,9 +285,18 @@ static std::string stripExportInterface( } const std::string::size_type traversed = (c - cStart) + 1; if (!*c) { - result += std::string(gotInstallInterface ? "$<INSTALL_INTERFACE:" - : "$<BUILD_INTERFACE:") + - input.substr(pos, traversed); + auto remaining = input.substr(pos, traversed); + switch (foundGenex) { + case FoundGenex::BuildInterface: + result = cmStrCat(result, "$<BUILD_INTERFACE:", remaining); + break; + case FoundGenex::InstallInterface: + result = cmStrCat(result, "$<INSTALL_INTERFACE:", remaining); + break; + case FoundGenex::BuildLocalInterface: + result = cmStrCat(result, "$<BUILD_LOCAL_INTERFACE:", remaining); + break; + } } pos += traversed; lastPos = pos; @@ -370,7 +406,7 @@ void cmGeneratorExpression::ReplaceInstallPrefix( while ((pos = input.find("$<INSTALL_PREFIX>", lastPos)) != std::string::npos) { - std::string::size_type endPos = pos + sizeof("$<INSTALL_PREFIX>") - 1; + std::string::size_type endPos = pos + cmStrLen("$<INSTALL_PREFIX>"); input.replace(pos, endPos - pos, replacement); lastPos = endPos; } diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index 188993f..e22b8ab 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -12,10 +12,11 @@ #include <vector> #include "cmListFileCache.h" +#include "cmLocalGenerator.h" +class cmake; class cmCompiledGeneratorExpression; class cmGeneratorTarget; -class cmLocalGenerator; struct cmGeneratorExpressionContext; struct cmGeneratorExpressionDAGChecker; struct cmGeneratorExpressionEvaluator; @@ -33,7 +34,8 @@ class cmGeneratorExpression { public: /** Construct. */ - cmGeneratorExpression(cmListFileBacktrace backtrace = cmListFileBacktrace()); + cmGeneratorExpression(cmake& cmakeInstance, + cmListFileBacktrace backtrace = cmListFileBacktrace()); ~cmGeneratorExpression(); cmGeneratorExpression(cmGeneratorExpression const&) = delete; @@ -82,6 +84,7 @@ public: const std::string& replacement); private: + cmake& CMakeInstance; cmListFileBacktrace Backtrace; }; @@ -152,7 +155,8 @@ private: cmGeneratorExpressionContext& context, cmGeneratorExpressionDAGChecker* dagChecker) const; - cmCompiledGeneratorExpression(cmListFileBacktrace backtrace, + cmCompiledGeneratorExpression(cmake& cmakeInstance, + cmListFileBacktrace backtrace, std::string input); friend class cmGeneratorExpression; @@ -184,7 +188,8 @@ public: std::string config, cmGeneratorTarget const* headTarget, std::string language = std::string()) - : LocalGenerator(localGenerator) + : GeneratorExpression(*localGenerator->GetCMakeInstance()) + , LocalGenerator(localGenerator) , Config(std::move(config)) , HeadTarget(headTarget) , Language(std::move(language)) diff --git a/Source/cmGeneratorExpressionEvaluationFile.cxx b/Source/cmGeneratorExpressionEvaluationFile.cxx index 8f3ed4d..817437e 100644 --- a/Source/cmGeneratorExpressionEvaluationFile.cxx +++ b/Source/cmGeneratorExpressionEvaluationFile.cxx @@ -165,7 +165,7 @@ void cmGeneratorExpressionEvaluationFile::Generate(cmLocalGenerator* lg) } cmListFileBacktrace lfbt = this->OutputFileExpr->GetBacktrace(); - cmGeneratorExpression contentGE(lfbt); + cmGeneratorExpression contentGE(*lg->GetCMakeInstance(), lfbt); std::unique_ptr<cmCompiledGeneratorExpression> inputExpression = contentGE.Parse(inputContent); diff --git a/Source/cmGeneratorExpressionEvaluator.cxx b/Source/cmGeneratorExpressionEvaluator.cxx index fec309c..b239408 100644 --- a/Source/cmGeneratorExpressionEvaluator.cxx +++ b/Source/cmGeneratorExpressionEvaluator.cxx @@ -4,8 +4,14 @@ #include <sstream> +#ifndef CMAKE_BOOTSTRAP +# include <cm3p/json/value.h> +#endif + #include "cmGeneratorExpressionContext.h" #include "cmGeneratorExpressionNode.h" +#include "cmLocalGenerator.h" +#include "cmake.h" GeneratorExpressionContent::GeneratorExpressionContent( const char* startContent, size_t length) @@ -61,6 +67,12 @@ std::string GeneratorExpressionContent::Evaluate( cmGeneratorExpressionContext* context, cmGeneratorExpressionDAGChecker* dagChecker) const { +#ifndef CMAKE_BOOTSTRAP + auto evalProfilingRAII = + context->LG->GetCMakeInstance()->CreateProfilingEntry( + "genex_eval", this->GetOriginalExpression()); +#endif + std::string identifier; { for (const auto& pExprEval : this->IdentifierChildren) { @@ -101,7 +113,24 @@ std::string GeneratorExpressionContent::Evaluate( return std::string(); } - return node->Evaluate(parameters, context, this, dagChecker); + { +#ifndef CMAKE_BOOTSTRAP + auto execProfilingRAII = + context->LG->GetCMakeInstance()->CreateProfilingEntry( + "genex_exec", identifier, [¶meters]() -> Json::Value { + Json::Value args = Json::objectValue; + if (!parameters.empty()) { + args["genexArgs"] = Json::arrayValue; + for (auto const& parameter : parameters) { + args["genexArgs"].append(parameter); + } + } + return args; + }); +#endif + + return node->Evaluate(parameters, context, this, dagChecker); + } } std::string GeneratorExpressionContent::EvaluateParameters( diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 45d5a83..e33ebd7 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -57,7 +57,7 @@ std::string cmGeneratorExpressionNode::EvaluateDependentExpression( cmGeneratorExpressionDAGChecker* dagChecker, cmGeneratorTarget const* currentTarget) { - cmGeneratorExpression ge(context->Backtrace); + cmGeneratorExpression ge(*lg->GetCMakeInstance(), context->Backtrace); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(prop); cge->SetEvaluateForBuildsystem(context->EvaluateForBuildsystem); cge->SetQuiet(context->Quiet); @@ -114,6 +114,8 @@ static const struct OneNode buildInterfaceNode; static const struct ZeroNode installInterfaceNode; +static const struct OneNode buildLocalInterfaceNode; + struct BooleanOpNode : public cmGeneratorExpressionNode { BooleanOpNode(const char* op_, const char* successVal_, @@ -1386,6 +1388,14 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode return "1"; } } + } else if (!suffix.empty()) { + // There is no explicit mapping for the tested config, so use + // the configuration of the imported location that was selected. + for (auto const& param : parameters) { + if (cmStrCat('_', cmSystemTools::UpperCase(param)) == suffix) { + return "1"; + } + } } } } @@ -1970,7 +1980,10 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode } return std::string(); } - target = context->LG->FindGeneratorTargetToUse(targetName); + cmLocalGenerator const* lg = context->CurrentTarget + ? context->CurrentTarget->GetLocalGenerator() + : context->LG; + target = lg->FindGeneratorTargetToUse(targetName); if (!target) { std::ostringstream e; @@ -3320,6 +3333,7 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "GENEX_EVAL", &genexEvalNode }, { "BUILD_INTERFACE", &buildInterfaceNode }, { "INSTALL_INTERFACE", &installInterfaceNode }, + { "BUILD_LOCAL_INTERFACE", &buildLocalInterfaceNode }, { "INSTALL_PREFIX", &installPrefixNode }, { "JOIN", &joinNode }, { "LINK_ONLY", &linkOnlyNode }, diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 7d43eb1..d0d339d 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -241,15 +241,16 @@ private: std::unique_ptr< cmGeneratorTarget:: - TargetPropertyEntry> static CreateTargetPropertyEntry(const BT<std:: - string>& + TargetPropertyEntry> static CreateTargetPropertyEntry(cmake& cmakeInstance, + const BT< + std::string>& propertyValue, bool evaluateForBuildsystem = false) { if (cmGeneratorExpression::Find(propertyValue.Value) != std::string::npos) { - cmGeneratorExpression ge(propertyValue.Backtrace); + cmGeneratorExpression ge(cmakeInstance, propertyValue.Backtrace); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(propertyValue.Value); cge->SetEvaluateForBuildsystem(evaluateForBuildsystem); @@ -262,12 +263,13 @@ std::unique_ptr< } static void CreatePropertyGeneratorExpressions( - cmBTStringRange entries, + cmake& cmakeInstance, cmBTStringRange entries, std::vector<std::unique_ptr<cmGeneratorTarget::TargetPropertyEntry>>& items, bool evaluateForBuildsystem = false) { for (auto const& entry : entries) { - items.push_back(CreateTargetPropertyEntry(entry, evaluateForBuildsystem)); + items.push_back( + CreateTargetPropertyEntry(cmakeInstance, entry, evaluateForBuildsystem)); } } @@ -343,29 +345,36 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) this->GlobalGenerator->ComputeTargetObjectDirectory(this); - CreatePropertyGeneratorExpressions(t->GetIncludeDirectoriesEntries(), + CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(), + t->GetIncludeDirectoriesEntries(), this->IncludeDirectoriesEntries); - CreatePropertyGeneratorExpressions(t->GetCompileOptionsEntries(), + CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(), + t->GetCompileOptionsEntries(), this->CompileOptionsEntries); - CreatePropertyGeneratorExpressions(t->GetCompileFeaturesEntries(), + CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(), + t->GetCompileFeaturesEntries(), this->CompileFeaturesEntries); - CreatePropertyGeneratorExpressions(t->GetCompileDefinitionsEntries(), + CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(), + t->GetCompileDefinitionsEntries(), this->CompileDefinitionsEntries); - CreatePropertyGeneratorExpressions(t->GetLinkOptionsEntries(), + CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(), + t->GetLinkOptionsEntries(), this->LinkOptionsEntries); - CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(), + CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(), + t->GetLinkDirectoriesEntries(), this->LinkDirectoriesEntries); - CreatePropertyGeneratorExpressions(t->GetPrecompileHeadersEntries(), + CreatePropertyGeneratorExpressions(*lg->GetCMakeInstance(), + t->GetPrecompileHeadersEntries(), this->PrecompileHeadersEntries); - CreatePropertyGeneratorExpressions(t->GetSourceEntries(), - this->SourceEntries, true); + CreatePropertyGeneratorExpressions( + *lg->GetCMakeInstance(), t->GetSourceEntries(), this->SourceEntries, true); this->PolicyMap = t->GetPolicyMap(); @@ -740,6 +749,12 @@ void cmGeneratorTarget::ClearSourcesCache() this->VisitedConfigsForObjects.clear(); this->LinkImplMap.clear(); this->LinkImplUsageRequirementsOnlyMap.clear(); + this->IncludeDirectoriesCache.clear(); + this->CompileOptionsCache.clear(); + this->CompileDefinitionsCache.clear(); + this->PrecompileHeadersCache.clear(); + this->LinkOptionsCache.clear(); + this->LinkDirectoriesCache.clear(); } void cmGeneratorTarget::ClearLinkInterfaceCache() @@ -753,6 +768,7 @@ void cmGeneratorTarget::AddSourceCommon(const std::string& src, bool before) this->SourceEntries.insert( before ? this->SourceEntries.begin() : this->SourceEntries.end(), CreateTargetPropertyEntry( + *this->LocalGenerator->GetCMakeInstance(), BT<std::string>(src, this->Makefile->GetBacktrace()), true)); this->ClearSourcesCache(); } @@ -780,6 +796,7 @@ void cmGeneratorTarget::AddIncludeDirectory(const std::string& src, before ? this->IncludeDirectoriesEntries.begin() : this->IncludeDirectoriesEntries.end(), CreateTargetPropertyEntry( + *this->Makefile->GetCMakeInstance(), BT<std::string>(src, this->Makefile->GetBacktrace()), true)); } @@ -1653,7 +1670,8 @@ void AddObjectEntries(cmGeneratorTarget const* headTarget, headTarget->GetGlobalGenerator()->IndexGeneratorTargetUniquely( lib.Target); std::string genex = "$<TARGET_OBJECTS:" + std::move(uniqueName) + ">"; - cmGeneratorExpression ge(lib.Backtrace); + cmGeneratorExpression ge(*headTarget->Makefile->GetCMakeInstance(), + lib.Backtrace); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(genex); cge->SetEvaluateForBuildsystem(true); @@ -3708,6 +3726,24 @@ std::string cmGeneratorTarget::GetCreateRuleVariable( return ""; } +//---------------------------------------------------------------------------- +std::string cmGeneratorTarget::GetClangTidyExportFixesDirectory( + const std::string& lang) const +{ + cmValue val = + this->GetProperty(cmStrCat(lang, "_CLANG_TIDY_EXPORT_FIXES_DIR")); + if (!cmNonempty(val)) { + return {}; + } + + std::string path = *val; + if (!cmSystemTools::FileIsFullPath(path)) { + path = + cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/', path); + } + return cmSystemTools::CollapseFullPath(path); +} + namespace { void processIncludeDirectories(cmGeneratorTarget const* tgt, EvaluatedTargetPropertyEntries& entries, @@ -3817,6 +3853,13 @@ void processIncludeDirectories(cmGeneratorTarget const* tgt, std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( const std::string& config, const std::string& lang) const { + ConfigAndLanguage cacheKey(config, lang); + { + auto it = this->IncludeDirectoriesCache.find(cacheKey); + if (it != this->IncludeDirectoriesCache.end()) { + return it->second; + } + } std::vector<BT<std::string>> includes; std::unordered_set<std::string> uniqueIncludes; @@ -3891,6 +3934,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetIncludeDirectories( processIncludeDirectories(this, entries, includes, uniqueIncludes, debugIncludes); + this->IncludeDirectoriesCache.emplace(cacheKey, includes); return includes; } @@ -4068,6 +4112,13 @@ void cmGeneratorTarget::GetCompileOptions(std::vector<std::string>& result, std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions( std::string const& config, std::string const& language) const { + ConfigAndLanguage cacheKey(config, language); + { + auto it = this->CompileOptionsCache.find(cacheKey); + if (it != this->CompileOptionsCache.end()) { + return it->second; + } + } std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueOptions; @@ -4094,6 +4145,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileOptions( processOptions(this, entries, result, uniqueOptions, debugOptions, "compile options", OptionsParse::Shell); + CompileOptionsCache.emplace(cacheKey, result); return result; } @@ -4155,6 +4207,13 @@ void cmGeneratorTarget::GetCompileDefinitions( std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( std::string const& config, std::string const& language) const { + ConfigAndLanguage cacheKey(config, language); + { + auto it = this->CompileDefinitionsCache.find(cacheKey); + if (it != this->CompileDefinitionsCache.end()) { + return it->second; + } + } std::vector<BT<std::string>> list; std::unordered_set<std::string> uniqueOptions; @@ -4192,7 +4251,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( } case cmPolicies::OLD: { std::unique_ptr<TargetPropertyEntry> entry = - CreateTargetPropertyEntry(*configProp); + CreateTargetPropertyEntry( + *this->LocalGenerator->GetCMakeInstance(), *configProp); entries.Entries.emplace_back(EvaluateTargetPropertyEntry( this, config, language, &dagChecker, *entry)); } break; @@ -4207,12 +4267,20 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetCompileDefinitions( processOptions(this, entries, list, uniqueOptions, debugDefines, "compile definitions", OptionsParse::None); + this->CompileDefinitionsCache.emplace(cacheKey, list); return list; } std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders( const std::string& config, const std::string& language) const { + ConfigAndLanguage cacheKey(config, language); + { + auto it = this->PrecompileHeadersCache.find(cacheKey); + if (it != this->PrecompileHeadersCache.end()) { + return it->second; + } + } std::unordered_set<std::string> uniqueOptions; cmGeneratorExpressionDAGChecker dagChecker(this, "PRECOMPILE_HEADERS", @@ -4240,6 +4308,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetPrecompileHeaders( processOptions(this, entries, list, uniqueOptions, debugDefines, "precompile headers", OptionsParse::None); + this->PrecompileHeadersCache.emplace(cacheKey, list); return list; } @@ -4600,6 +4669,14 @@ void cmGeneratorTarget::GetLinkOptions(std::vector<std::string>& result, std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( std::string const& config, std::string const& language) const { + ConfigAndLanguage cacheKey( + config, cmStrCat(language, this->IsDeviceLink() ? "-device" : "")); + { + auto it = this->LinkOptionsCache.find(cacheKey); + if (it != this->LinkOptionsCache.end()) { + return it->second; + } + } std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueOptions; @@ -4677,7 +4754,10 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkOptions( // Last step: replace "LINKER:" prefixed elements by // actual linker wrapper - return this->ResolveLinkerWrapper(result, language); + result = this->ResolveLinkerWrapper(result, language); + + this->LinkOptionsCache.emplace(cacheKey, result); + return result; } std::vector<BT<std::string>>& cmGeneratorTarget::ResolveLinkerWrapper( @@ -4776,13 +4856,10 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetStaticLibraryLinkOptions( EvaluatedTargetPropertyEntries entries; if (cmValue linkOptions = this->GetProperty("STATIC_LIBRARY_OPTIONS")) { - std::vector<std::string> options = cmExpandedList(*linkOptions); - for (const auto& option : options) { - std::unique_ptr<TargetPropertyEntry> entry = - CreateTargetPropertyEntry(option); - entries.Entries.emplace_back(EvaluateTargetPropertyEntry( - this, config, language, &dagChecker, *entry)); - } + std::unique_ptr<TargetPropertyEntry> entry = CreateTargetPropertyEntry( + *this->LocalGenerator->GetCMakeInstance(), *linkOptions); + entries.Entries.emplace_back(EvaluateTargetPropertyEntry( + this, config, language, &dagChecker, *entry)); } processOptions(this, entries, result, uniqueOptions, false, "static library link options", OptionsParse::Shell); @@ -4876,6 +4953,14 @@ void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result, std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( std::string const& config, std::string const& language) const { + ConfigAndLanguage cacheKey( + config, cmStrCat(language, this->IsDeviceLink() ? "-device" : "")); + { + auto it = this->LinkDirectoriesCache.find(cacheKey); + if (it != this->LinkDirectoriesCache.end()) { + return it->second; + } + } std::vector<BT<std::string>> result; std::unordered_set<std::string> uniqueDirectories; @@ -4905,6 +4990,7 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDirectories( processLinkDirectories(this, entries, result, uniqueDirectories, debugDirectories); + this->LinkDirectoriesCache.emplace(cacheKey, result); return result; } @@ -4931,8 +5017,8 @@ std::vector<BT<std::string>> cmGeneratorTarget::GetLinkDepends( if (cmValue linkDepends = this->GetProperty("LINK_DEPENDS")) { std::vector<std::string> depends = cmExpandedList(*linkDepends); for (const auto& depend : depends) { - std::unique_ptr<TargetPropertyEntry> entry = - CreateTargetPropertyEntry(depend); + std::unique_ptr<TargetPropertyEntry> entry = CreateTargetPropertyEntry( + *this->LocalGenerator->GetCMakeInstance(), depend); entries.Entries.emplace_back(EvaluateTargetPropertyEntry( this, config, language, &dagChecker, *entry)); } @@ -5532,7 +5618,7 @@ cmGeneratorTarget::GetTargetSourceFileFlags(const cmSourceFile* sf) const } else if (cmHasLiteralPrefix(*location, "Resources/")) { flags.Type = cmGeneratorTarget::SourceFileTypeDeepResource; if (stripResources) { - flags.MacFolder += strlen("Resources/"); + flags.MacFolder += cmStrLen("Resources/"); } } else { flags.Type = cmGeneratorTarget::SourceFileTypeMacContent; @@ -6705,7 +6791,7 @@ bool cmGeneratorTarget::IsLinkLookupScope(std::string const& n, cmLocalGenerator const*& lg) const { if (cmHasLiteralPrefix(n, CMAKE_DIRECTORY_ID_SEP)) { - cmDirectoryId const dirId = n.substr(sizeof(CMAKE_DIRECTORY_ID_SEP) - 1); + cmDirectoryId const dirId = n.substr(cmStrLen(CMAKE_DIRECTORY_ID_SEP)); if (dirId.String.empty()) { lg = this->LocalGenerator; return true; @@ -6756,7 +6842,8 @@ void cmGeneratorTarget::ExpandLinkItems( cmMakefile const* mf = this->LocalGenerator->GetMakefile(); LookupLinkItemScope scope{ this->LocalGenerator }; for (BT<std::string> const& entry : entries) { - cmGeneratorExpression ge(entry.Backtrace); + cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance(), + entry.Backtrace); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(entry.Value); cge->SetEvaluateForBuildsystem(true); std::vector<std::string> libs = cmExpandedList( @@ -8195,7 +8282,8 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( break; } } - cmGeneratorExpression ge(entry.Backtrace); + cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance(), + entry.Backtrace); std::unique_ptr<cmCompiledGeneratorExpression> const cge = ge.Parse(entry.Value); cge->SetEvaluateForBuildsystem(true); @@ -8515,9 +8603,14 @@ cmGeneratorTarget::ManagedType cmGeneratorTarget::CheckManagedType( // lib // 2. empty propval: add /clr as flag, mixed unmanaged/managed // target, has import lib - // 3. any value (safe,pure): add /clr:[propval] as flag, target with + // 3. netcore propval: add /clr:netcore as flag, mixed + // unmanaged/managed target, has import lib. + // 4. any value (safe,pure): add /clr:[propval] as flag, target with // managed code only, no import lib - return propval.empty() ? ManagedType::Mixed : ManagedType::Managed; + if (propval.empty() || propval == "netcore") { + return ManagedType::Mixed; + } + return ManagedType::Managed; } cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType( @@ -8849,3 +8942,101 @@ void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const } } } + +bool cmGeneratorTarget::NeedCxxModuleSupport(std::string const& lang, + std::string const& config) const +{ + if (lang != "CXX"_s) { + return false; + } + return this->HaveCxxModuleSupport(config) == Cxx20SupportLevel::Supported && + this->GetGlobalGenerator()->CheckCxxModuleSupport(); +} + +bool cmGeneratorTarget::NeedDyndep(std::string const& lang, + std::string const& config) const +{ + return lang == "Fortran"_s || this->NeedCxxModuleSupport(lang, config); +} + +cmFileSet const* cmGeneratorTarget::GetFileSetForSource( + std::string const& config, cmSourceFile const* sf) const +{ + this->BuildFileSetInfoCache(config); + + auto const& path = sf->GetFullPath(); + auto const& per_config = this->Configs[config]; + + auto const fsit = per_config.FileSetCache.find(path); + if (fsit == per_config.FileSetCache.end()) { + return nullptr; + } + return fsit->second; +} + +bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang, + std::string const& config, + cmSourceFile const* sf) const +{ + bool const needDyndep = this->NeedDyndep(lang, config); + if (!needDyndep) { + return false; + } + auto const* fs = this->GetFileSetForSource(config, sf); + if (fs && + (fs->GetType() == "CXX_MODULES"_s || + fs->GetType() == "CXX_MODULE_HEADER_UNITS"_s)) { + return true; + } + auto const sfProp = sf->GetProperty("CXX_SCAN_FOR_MODULES"); + if (sfProp.IsSet()) { + return sfProp.IsOn(); + } + auto const tgtProp = this->GetProperty("CXX_SCAN_FOR_MODULES"); + if (tgtProp.IsSet()) { + return tgtProp.IsOn(); + } + return true; +} + +void cmGeneratorTarget::BuildFileSetInfoCache(std::string const& config) const +{ + auto& per_config = this->Configs[config]; + + if (per_config.BuiltFileSetCache) { + return; + } + + auto const* tgt = this->Target; + + for (auto const& name : tgt->GetAllFileSetNames()) { + auto const* file_set = tgt->GetFileSet(name); + if (!file_set) { + tgt->GetMakefile()->IssueMessage( + MessageType::INTERNAL_ERROR, + cmStrCat("Target \"", tgt->GetName(), + "\" is tracked to have file set \"", name, + "\", but it was not found.")); + continue; + } + + auto fileEntries = file_set->CompileFileEntries(); + auto directoryEntries = file_set->CompileDirectoryEntries(); + auto directories = file_set->EvaluateDirectoryEntries( + directoryEntries, this->LocalGenerator, config, this); + + std::map<std::string, std::vector<std::string>> files; + for (auto const& entry : fileEntries) { + file_set->EvaluateFileEntry(directories, files, entry, + this->LocalGenerator, config, this); + } + + for (auto const& it : files) { + for (auto const& filename : it.second) { + per_config.FileSetCache[filename] = file_set; + } + } + } + + per_config.BuiltFileSetCache = true; +} diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 25e6a81..7fa662d 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -26,6 +26,7 @@ enum class cmBuildStep; class cmComputeLinkInformation; class cmCustomCommand; +class cmFileSet; class cmGlobalGenerator; class cmLocalGenerator; class cmMakefile; @@ -489,6 +490,20 @@ public: std::string GetCreateRuleVariable(std::string const& lang, std::string const& config) const; + std::string GetClangTidyExportFixesDirectory(const std::string& lang) const; + +private: + using ConfigAndLanguage = std::pair<std::string, std::string>; + using ConfigAndLanguageToBTStrings = + std::map<ConfigAndLanguage, std::vector<BT<std::string>>>; + mutable ConfigAndLanguageToBTStrings IncludeDirectoriesCache; + mutable ConfigAndLanguageToBTStrings CompileOptionsCache; + mutable ConfigAndLanguageToBTStrings CompileDefinitionsCache; + mutable ConfigAndLanguageToBTStrings PrecompileHeadersCache; + mutable ConfigAndLanguageToBTStrings LinkOptionsCache; + mutable ConfigAndLanguageToBTStrings LinkDirectoriesCache; + +public: /** Get the include directories for this target. */ std::vector<BT<std::string>> GetIncludeDirectories( const std::string& config, const std::string& lang) const; @@ -1229,4 +1244,21 @@ public: // Check C++ module status for the target. void CheckCxxModuleStatus(std::string const& config) const; + + bool NeedCxxModuleSupport(std::string const& lang, + std::string const& config) const; + bool NeedDyndep(std::string const& lang, std::string const& config) const; + cmFileSet const* GetFileSetForSource(std::string const& config, + cmSourceFile const* sf) const; + bool NeedDyndepForSource(std::string const& lang, std::string const& config, + cmSourceFile const* sf) const; + +private: + void BuildFileSetInfoCache(std::string const& config) const; + struct InfoByConfig + { + bool BuiltFileSetCache = false; + std::map<std::string, cmFileSet const*> FileSetCache; + }; + mutable std::map<std::string, InfoByConfig> Configs; }; diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index 138d3f1..8471dfe 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -9,6 +9,8 @@ #include <utility> #include <vector> +#include <cm/optional> + #include "cmCustomCommand.h" #include "cmCustomCommandGenerator.h" #include "cmGeneratedFileStream.h" @@ -411,9 +413,8 @@ void cmGhsMultiTargetGenerator::WriteCustomCommandsHelper( cmdLines.push_back("@echo off"); #endif // Echo the custom command's comment text. - const char* comment = ccg.GetComment(); - if (comment && *comment) { - std::string echocmd = cmStrCat("echo ", comment); + if (cm::optional<std::string> comment = ccg.GetComment()) { + std::string echocmd = cmStrCat("echo ", *comment); cmdLines.push_back(std::move(echocmd)); } diff --git a/Source/cmGlobalBorlandMakefileGenerator.cxx b/Source/cmGlobalBorlandMakefileGenerator.cxx index 776ee40..2fd7f8a 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.cxx +++ b/Source/cmGlobalBorlandMakefileGenerator.cxx @@ -60,11 +60,10 @@ cmGlobalBorlandMakefileGenerator::CreateLocalGenerator(cmMakefile* mf) return std::unique_ptr<cmLocalGenerator>(std::move(lg)); } -void cmGlobalBorlandMakefileGenerator::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalBorlandMakefileGenerator::GetDocumentation() { - entry.Name = cmGlobalBorlandMakefileGenerator::GetActualName(); - entry.Brief = "Generates Borland makefiles."; + return { cmGlobalBorlandMakefileGenerator::GetActualName(), + "Generates Borland makefiles." }; } std::vector<cmGlobalGenerator::GeneratedMakeCommand> diff --git a/Source/cmGlobalBorlandMakefileGenerator.h b/Source/cmGlobalBorlandMakefileGenerator.h index a280b81..049d6ba 100644 --- a/Source/cmGlobalBorlandMakefileGenerator.h +++ b/Source/cmGlobalBorlandMakefileGenerator.h @@ -13,7 +13,6 @@ class cmLocalGenerator; class cmMakefile; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalBorlandMakefileGenerator * \brief Write a Borland makefiles. @@ -38,7 +37,7 @@ public: static std::string GetActualName() { return "Borland Makefiles"; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); //! Create a local generator appropriate to this Global Generator std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( diff --git a/Source/cmGlobalCommonGenerator.cxx b/Source/cmGlobalCommonGenerator.cxx index 3ae66f0..7a44452 100644 --- a/Source/cmGlobalCommonGenerator.cxx +++ b/Source/cmGlobalCommonGenerator.cxx @@ -2,11 +2,14 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalCommonGenerator.h" +#include <algorithm> #include <memory> #include <utility> #include <cmext/algorithm> +#include <cmsys/Glob.hxx> + #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" #include "cmLocalGenerator.h" @@ -14,6 +17,7 @@ #include "cmStateDirectory.h" #include "cmStateSnapshot.h" #include "cmStateTypes.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmValue.h" #include "cmake.h" @@ -124,3 +128,23 @@ std::string cmGlobalCommonGenerator::GetEditCacheCommand() const cmValue edit_cmd = cm->GetCacheDefinition("CMAKE_EDIT_COMMAND"); return edit_cmd ? *edit_cmd : std::string(); } + +void cmGlobalCommonGenerator::RemoveUnknownClangTidyExportFixesFiles() const +{ + for (auto const& dir : this->ClangTidyExportFixesDirs) { + cmsys::Glob g; + g.SetRecurse(true); + g.SetListDirs(false); + g.FindFiles(cmStrCat(dir, "/*.yaml")); + for (auto const& file : g.GetFiles()) { + if (!this->ClangTidyExportFixesFiles.count(file) && + !std::any_of(this->ClangTidyExportFixesFiles.begin(), + this->ClangTidyExportFixesFiles.end(), + [&file](const std::string& knownFile) -> bool { + return cmSystemTools::SameFile(file, knownFile); + })) { + cmSystemTools::RemoveFile(file); + } + } + } +} diff --git a/Source/cmGlobalCommonGenerator.h b/Source/cmGlobalCommonGenerator.h index fed9ce8..fa42674 100644 --- a/Source/cmGlobalCommonGenerator.h +++ b/Source/cmGlobalCommonGenerator.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <map> +#include <set> #include <string> #include <vector> @@ -42,9 +43,21 @@ public: std::map<std::string, DirectoryTarget> ComputeDirectoryTargets() const; bool IsExcludedFromAllInConfig(const DirectoryTarget::Target& t, const std::string& config); + void AddClangTidyExportFixesDir(const std::string& dir) + { + this->ClangTidyExportFixesDirs.insert(dir); + } + void AddClangTidyExportFixesFile(const std::string& file) + { + this->ClangTidyExportFixesFiles.insert(file); + } protected: virtual bool SupportsDirectConsole() const { return true; } const char* GetEditCacheTargetName() const override { return "edit_cache"; } std::string GetEditCacheCommand() const override; + + std::set<std::string> ClangTidyExportFixesDirs; + std::set<std::string> ClangTidyExportFixesFiles; + void RemoveUnknownClangTidyExportFixesFiles() const; }; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index c2bf888..8ca6ee6 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -827,7 +827,8 @@ void cmGlobalGenerator::EnableLanguage( "No " << compilerName << " could be found.\n" ; /* clang-format on */ - } else if ((lang != "RC") && (lang != "ASM_MASM")) { + } else if ((lang != "RC") && (lang != "ASM_MARMASM") && + (lang != "ASM_MASM")) { if (!cmSystemTools::FileIsFullPath(*compilerFile)) { /* clang-format off */ noCompiler << @@ -1438,6 +1439,19 @@ bool cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const return false; } +void cmGlobalGenerator::CxxModuleSupportCheck() const +{ + bool const diagnose = !this->DiagnosedCxxModuleSupport && + !this->CMakeInstance->GetIsInTryCompile(); + if (diagnose) { + this->DiagnosedCxxModuleSupport = true; + this->GetCMakeInstance()->IssueMessage( + MessageType::AUTHOR_WARNING, + "C++20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP " + "is experimental. It is meant only for compiler developers to try."); + } +} + void cmGlobalGenerator::ComputeBuildFileGenerators() { for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) { @@ -1596,6 +1610,8 @@ void cmGlobalGenerator::Generate() // it builds by default. this->InitializeProgressMarks(); + this->DiagnosedCxxModuleSupport = false; + this->ProcessEvaluationFiles(); this->CMakeInstance->UpdateProgress("Generating", 0.1f); @@ -2943,19 +2959,18 @@ std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const bool cmGlobalGenerator::UseFolderProperty() const { - cmValue prop = + const cmValue prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty("USE_FOLDERS"); - // If this property is defined, let the setter turn this on or off... - // + // If this property is defined, let the setter turn this on or off. if (prop) { return cmIsOn(*prop); } - // By default, this feature is OFF, since it is not supported in the - // Visual Studio Express editions until VS11: - // - return false; + // If CMP0143 is NEW `treat` "USE_FOLDERS" as ON. Otherwise `treat` it as OFF + assert(!this->Makefiles.empty()); + return (this->Makefiles[0]->GetPolicyStatus(cmPolicies::CMP0143) == + cmPolicies::NEW); } void cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti, diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 076b041..66ab752 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -157,6 +157,8 @@ public: virtual bool InspectConfigTypeVariables() { return true; } + virtual bool CheckCxxModuleSupport() { return false; } + bool Compute(); virtual void AddExtraIDETargets() {} @@ -621,6 +623,8 @@ protected: virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() const; + void CxxModuleSupportCheck() const; + /// @brief Qt AUTOMOC/UIC/RCC target generation /// @return true on success bool QtAutoGen(); @@ -728,6 +732,8 @@ private: std::map<std::string, int> LanguageToLinkerPreference; std::map<std::string, std::string> LanguageToOriginalSharedLibFlags; + mutable bool DiagnosedCxxModuleSupport = false; + // Deferral id generation. size_t NextDeferId = 0; diff --git a/Source/cmGlobalGeneratorFactory.h b/Source/cmGlobalGeneratorFactory.h index d6ababb..a935079 100644 --- a/Source/cmGlobalGeneratorFactory.h +++ b/Source/cmGlobalGeneratorFactory.h @@ -4,6 +4,10 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cmDocumentationEntry.h" // IWYU pragma: export + +// TODO The following headers are parts of the `cmGlobalGeneratorFactory` +// public API, so could be defined as export to IWYU #include <string> #include <vector> @@ -11,7 +15,6 @@ class cmGlobalGenerator; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalGeneratorFactory * \brief Responable for creating cmGlobalGenerator instances @@ -28,7 +31,7 @@ public: const std::string& n, bool allowArch, cmake* cm) const = 0; /** Get the documentation entry for this factory */ - virtual void GetDocumentation(cmDocumentationEntry& entry) const = 0; + virtual cmDocumentationEntry GetDocumentation() const = 0; /** Get the names of the current registered generators */ virtual std::vector<std::string> GetGeneratorNames() const = 0; @@ -47,7 +50,7 @@ public: virtual std::string GetDefaultPlatformName() const = 0; }; -template <class T> +template <typename T> class cmGlobalGeneratorSimpleFactory : public cmGlobalGeneratorFactory { public: @@ -62,21 +65,19 @@ public: } /** Get the documentation entry for this factory */ - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - T::GetDocumentation(entry); + return T::GetDocumentation(); } /** Get the names of the current registered generators */ std::vector<std::string> GetGeneratorNames() const override { - std::vector<std::string> names; - names.push_back(T::GetActualName()); - return names; + return { T::GetActualName() }; } std::vector<std::string> GetGeneratorNamesWithPlatform() const override { - return std::vector<std::string>(); + return {}; } /** Determine whether or not this generator supports toolsets */ @@ -89,8 +90,8 @@ public: std::vector<std::string> GetKnownPlatforms() const override { // default is no platform supported - return std::vector<std::string>(); + return {}; } - std::string GetDefaultPlatformName() const override { return std::string(); } + std::string GetDefaultPlatformName() const override { return {}; } }; diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index 9c334a5..18c48d7 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -15,7 +15,6 @@ #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" -#include "cmDocumentationEntry.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGhsMultiGpj.h" @@ -58,11 +57,12 @@ cmGlobalGhsMultiGenerator::CreateLocalGenerator(cmMakefile* mf) cm::make_unique<cmLocalGhsMultiGenerator>(this, mf)); } -void cmGlobalGhsMultiGenerator::GetDocumentation(cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalGhsMultiGenerator::GetDocumentation() { - entry.Name = GetActualName(); - entry.Brief = - "Generates Green Hills MULTI files (experimental, work-in-progress)."; + return { + GetActualName(), + "Generates Green Hills MULTI files (experimental, work-in-progress)." + }; } void cmGlobalGhsMultiGenerator::ComputeTargetObjectDirectory( diff --git a/Source/cmGlobalGhsMultiGenerator.h b/Source/cmGlobalGhsMultiGenerator.h index aa68d3b..4a79610 100644 --- a/Source/cmGlobalGhsMultiGenerator.h +++ b/Source/cmGlobalGhsMultiGenerator.h @@ -18,7 +18,6 @@ class cmGeneratorTarget; class cmLocalGenerator; class cmMakefile; class cmake; -struct cmDocumentationEntry; class cmGlobalGhsMultiGenerator : public cmGlobalGenerator { @@ -46,7 +45,7 @@ public: std::string GetName() const override { return GetActualName(); } /// Overloaded methods. @see cmGlobalGenerator::GetDocumentation() - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); /** * Utilized by the generator factory to determine if this generator diff --git a/Source/cmGlobalJOMMakefileGenerator.cxx b/Source/cmGlobalJOMMakefileGenerator.cxx index 1a625cc..f1d4d09 100644 --- a/Source/cmGlobalJOMMakefileGenerator.cxx +++ b/Source/cmGlobalJOMMakefileGenerator.cxx @@ -6,7 +6,6 @@ #include <cmext/algorithm> -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmState.h" @@ -36,11 +35,10 @@ void cmGlobalJOMMakefileGenerator::EnableLanguage( this->cmGlobalUnixMakefileGenerator3::EnableLanguage(l, mf, optional); } -void cmGlobalJOMMakefileGenerator::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalJOMMakefileGenerator::GetDocumentation() { - entry.Name = cmGlobalJOMMakefileGenerator::GetActualName(); - entry.Brief = "Generates JOM makefiles."; + return { cmGlobalJOMMakefileGenerator::GetActualName(), + "Generates JOM makefiles." }; } void cmGlobalJOMMakefileGenerator::PrintCompilerAdvice(std::ostream& os, diff --git a/Source/cmGlobalJOMMakefileGenerator.h b/Source/cmGlobalJOMMakefileGenerator.h index 332d1cf..5e74875 100644 --- a/Source/cmGlobalJOMMakefileGenerator.h +++ b/Source/cmGlobalJOMMakefileGenerator.h @@ -13,7 +13,6 @@ class cmMakefile; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalJOMMakefileGenerator * \brief Write a JOM makefiles. @@ -39,7 +38,7 @@ public: static std::string GetActualName() { return "NMake Makefiles JOM"; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); /** * Try to determine system information such as shared library diff --git a/Source/cmGlobalMSYSMakefileGenerator.cxx b/Source/cmGlobalMSYSMakefileGenerator.cxx index d4ff1e0..e543aea 100644 --- a/Source/cmGlobalMSYSMakefileGenerator.cxx +++ b/Source/cmGlobalMSYSMakefileGenerator.cxx @@ -4,7 +4,6 @@ #include "cmsys/FStream.hxx" -#include "cmDocumentationEntry.h" #include "cmMakefile.h" #include "cmState.h" #include "cmStringAlgorithms.h" @@ -53,9 +52,8 @@ void cmGlobalMSYSMakefileGenerator::EnableLanguage( } } -void cmGlobalMSYSMakefileGenerator::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalMSYSMakefileGenerator::GetDocumentation() { - entry.Name = cmGlobalMSYSMakefileGenerator::GetActualName(); - entry.Brief = "Generates MSYS makefiles."; + return { cmGlobalMSYSMakefileGenerator::GetActualName(), + "Generates MSYS makefiles." }; } diff --git a/Source/cmGlobalMSYSMakefileGenerator.h b/Source/cmGlobalMSYSMakefileGenerator.h index 586487f..ee9a4ee 100644 --- a/Source/cmGlobalMSYSMakefileGenerator.h +++ b/Source/cmGlobalMSYSMakefileGenerator.h @@ -11,7 +11,6 @@ class cmMakefile; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalMSYSMakefileGenerator * \brief Write a NMake makefiles. @@ -29,21 +28,21 @@ public: } //! Get the name for the generator. - virtual std::string GetName() const + std::string GetName() const override { return cmGlobalMSYSMakefileGenerator::GetActualName(); } static std::string GetActualName() { return "MSYS Makefiles"; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); /** * Try to determine system information such as shared library * extension, pthreads, byte order etc. */ - virtual void EnableLanguage(std::vector<std::string> const& languages, - cmMakefile*, bool optional); + void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*, + bool optional) override; private: std::string FindMinGW(std::string const& makeloc); diff --git a/Source/cmGlobalMinGWMakefileGenerator.cxx b/Source/cmGlobalMinGWMakefileGenerator.cxx index 5a7edae..a0a52d3 100644 --- a/Source/cmGlobalMinGWMakefileGenerator.cxx +++ b/Source/cmGlobalMinGWMakefileGenerator.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmGlobalMinGWMakefileGenerator.h" -#include "cmDocumentationEntry.h" #include "cmMakefile.h" #include "cmState.h" #include "cmSystemTools.h" @@ -19,9 +18,8 @@ cmGlobalMinGWMakefileGenerator::cmGlobalMinGWMakefileGenerator(cmake* cm) cm->GetState()->SetMinGWMake(true); } -void cmGlobalMinGWMakefileGenerator::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalMinGWMakefileGenerator::GetDocumentation() { - entry.Name = cmGlobalMinGWMakefileGenerator::GetActualName(); - entry.Brief = "Generates a make file for use with mingw32-make."; + return { cmGlobalMinGWMakefileGenerator::GetActualName(), + "Generates a make file for use with mingw32-make." }; } diff --git a/Source/cmGlobalMinGWMakefileGenerator.h b/Source/cmGlobalMinGWMakefileGenerator.h index 92d495c..7dd968b 100644 --- a/Source/cmGlobalMinGWMakefileGenerator.h +++ b/Source/cmGlobalMinGWMakefileGenerator.h @@ -11,7 +11,6 @@ class cmMakefile; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalMinGWMakefileGenerator * \brief Write a NMake makefiles. @@ -28,12 +27,12 @@ public: new cmGlobalGeneratorSimpleFactory<cmGlobalMinGWMakefileGenerator>()); } //! Get the name for the generator. - virtual std::string GetName() const + std::string GetName() const override { return cmGlobalMinGWMakefileGenerator::GetActualName(); } static std::string GetActualName() { return "MinGW Makefiles"; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); }; diff --git a/Source/cmGlobalNMakeMakefileGenerator.cxx b/Source/cmGlobalNMakeMakefileGenerator.cxx index eabacf6..cb53850 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.cxx +++ b/Source/cmGlobalNMakeMakefileGenerator.cxx @@ -8,7 +8,6 @@ #include "cmsys/RegularExpression.hxx" -#include "cmDocumentationEntry.h" #include "cmDuration.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" @@ -80,11 +79,10 @@ void cmGlobalNMakeMakefileGenerator::CheckNMakeFeatures() cmSystemTools::OP_LESS, this->NMakeVersion, "9"); } -void cmGlobalNMakeMakefileGenerator::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalNMakeMakefileGenerator::GetDocumentation() { - entry.Name = cmGlobalNMakeMakefileGenerator::GetActualName(); - entry.Brief = "Generates NMake makefiles."; + return { cmGlobalNMakeMakefileGenerator::GetActualName(), + "Generates NMake makefiles." }; } void cmGlobalNMakeMakefileGenerator::PrintCompilerAdvice( @@ -128,12 +126,8 @@ void cmGlobalNMakeMakefileGenerator::PrintBuildCommandAdvice(std::ostream& os, if (jobs != cmake::NO_BUILD_PARALLEL_LEVEL) { // nmake does not support parallel build level // see https://msdn.microsoft.com/en-us/library/afyyse50.aspx - - /* clang-format off */ - os << - "Warning: NMake does not support parallel builds. " - "Ignoring parallel build command line option.\n"; - /* clang-format on */ + os << "Warning: NMake does not support parallel builds. " + "Ignoring parallel build command line option.\n"; } this->cmGlobalUnixMakefileGenerator3::PrintBuildCommandAdvice( diff --git a/Source/cmGlobalNMakeMakefileGenerator.h b/Source/cmGlobalNMakeMakefileGenerator.h index b3574eb..436ebca 100644 --- a/Source/cmGlobalNMakeMakefileGenerator.h +++ b/Source/cmGlobalNMakeMakefileGenerator.h @@ -15,7 +15,6 @@ class cmMakefile; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalNMakeMakefileGenerator * \brief Write a NMake makefiles. @@ -45,7 +44,7 @@ public: } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); /** * Try to determine system information such as shared library diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 077de42..c24b1e3 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -25,8 +25,7 @@ #include "cmsys/FStream.hxx" #include "cmCxxModuleMapper.h" -#include "cmDocumentationEntry.h" -#include "cmFileSet.h" +#include "cmDyndepCollation.h" #include "cmFortranParser.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpressionEvaluationFile.h" @@ -554,10 +553,10 @@ codecvt::Encoding cmGlobalNinjaGenerator::GetMakefileEncoding() const return this->NinjaExpectedEncoding; } -void cmGlobalNinjaGenerator::GetDocumentation(cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalNinjaGenerator::GetDocumentation() { - entry.Name = cmGlobalNinjaGenerator::GetActualName(); - entry.Brief = "Generates build.ninja files."; + return { cmGlobalNinjaGenerator::GetActualName(), + "Generates build.ninja files." }; } // Implemented in all cmGlobaleGenerator sub-classes. @@ -592,7 +591,9 @@ void cmGlobalNinjaGenerator::Generate() this->TargetAll = this->NinjaOutputPath("all"); this->CMakeCacheFile = this->NinjaOutputPath("CMakeCache.txt"); this->DisableCleandead = false; - this->DiagnosedCxxModuleSupport = false; + this->DiagnosedCxxModuleNinjaSupport = false; + this->ClangTidyExportFixesDirs.clear(); + this->ClangTidyExportFixesFiles.clear(); this->PolicyCMP0058 = this->LocalGenerators[0]->GetMakefile()->GetPolicyStatus( @@ -633,6 +634,8 @@ void cmGlobalNinjaGenerator::Generate() { this->CleanMetaData(); } + + this->RemoveUnknownClangTidyExportFixesFiles(); } void cmGlobalNinjaGenerator::CleanMetaData() @@ -851,18 +854,12 @@ bool cmGlobalNinjaGenerator::CheckLanguages( bool cmGlobalNinjaGenerator::CheckCxxModuleSupport() { - bool const diagnose = !this->DiagnosedCxxModuleSupport && - !this->CMakeInstance->GetIsInTryCompile(); - if (diagnose) { - this->DiagnosedCxxModuleSupport = true; - this->GetCMakeInstance()->IssueMessage( - MessageType::AUTHOR_WARNING, - "C++20 modules support via CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP " - "is experimental. It is meant only for compiler developers to try."); - } + this->CxxModuleSupportCheck(); if (this->NinjaSupportsDyndeps) { return true; } + bool const diagnose = !this->DiagnosedCxxModuleNinjaSupport && + !this->CMakeInstance->GetIsInTryCompile(); if (diagnose) { std::ostringstream e; /* clang-format off */ @@ -1171,7 +1168,8 @@ void cmGlobalNinjaGenerator::AddAdditionalCleanFile(std::string fileName, } void cmGlobalNinjaGenerator::AddCXXCompileCommand( - const std::string& commandLine, const std::string& sourceFile) + const std::string& commandLine, const std::string& sourceFile, + const std::string& objPath) { // Compute Ninja's build file path. std::string buildFileDir = @@ -1205,7 +1203,9 @@ void cmGlobalNinjaGenerator::AddCXXCompileCommand( << R"( "command": ")" << cmGlobalGenerator::EscapeJSON(commandLine) << "\",\n" << R"( "file": ")" - << cmGlobalGenerator::EscapeJSON(sourceFileName) << "\"\n" + << cmGlobalGenerator::EscapeJSON(sourceFileName) << "\",\n" + << R"( "output": ")" + << cmGlobalGenerator::EscapeJSON(objPath) << "\"\n" << "}"; /* clang-format on */ } @@ -1254,7 +1254,7 @@ void cmGlobalNinjaGenerator::AppendTargetOutputs( cmGeneratorTarget const* target, cmNinjaDeps& outputs, const std::string& config, cmNinjaTargetDepends depends) const { - // for frameworks, we want the real name, not smple name + // for frameworks, we want the real name, not sample name // frameworks always appear versioned, and the build.ninja // will always attempt to manage symbolic links instead // of letting cmOSXBundleGenerator do it. @@ -2098,6 +2098,7 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) } std::vector<std::string> byproducts; + byproducts.reserve(this->CrossConfigs.size()); for (auto const& config : this->CrossConfigs) { byproducts.push_back( this->BuildAlias(GetByproductsForCleanTargetName(), config)); @@ -2472,45 +2473,6 @@ cm::optional<cmSourceInfo> cmcmd_cmake_ninja_depends_fortran( } } -struct CxxModuleFileSet -{ - std::string Name; - std::string RelativeDirectory; - std::string SourcePath; - std::string Type; - cmFileSetVisibility Visibility; - cm::optional<std::string> Destination; -}; - -struct CxxModuleBmiInstall -{ - std::string Component; - std::string Destination; - bool ExcludeFromAll; - bool Optional; - std::string Permissions; - std::string MessageLevel; - std::string ScriptLocation; -}; - -struct CxxModuleExport -{ - std::string Name; - std::string Destination; - std::string Prefix; - std::string CxxModuleInfoDir; - std::string Namespace; - bool Install; -}; - -struct cmGlobalNinjaGenerator::CxxModuleExportInfo -{ - std::map<std::string, CxxModuleFileSet> ObjectToFileSet; - cm::optional<CxxModuleBmiInstall> BmiInstallation; - std::vector<CxxModuleExport> Exports; - std::string Config; -}; - bool cmGlobalNinjaGenerator::WriteDyndepFile( std::string const& dir_top_src, std::string const& dir_top_bld, std::string const& dir_cur_src, std::string const& dir_cur_bld, @@ -2518,7 +2480,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( std::string const& module_dir, std::vector<std::string> const& linked_target_dirs, std::string const& arg_lang, std::string const& arg_modmapfmt, - CxxModuleExportInfo const& export_info) + cmCxxModuleExportInfo const& export_info) { // Setup path conversions. { @@ -2610,6 +2572,8 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( cm::optional<CxxModuleMapFormat> modmap_fmt; if (arg_modmapfmt.empty()) { // nothing to do. + } else if (arg_modmapfmt == "clang") { + modmap_fmt = CxxModuleMapFormat::Clang; } else if (arg_modmapfmt == "gcc") { modmap_fmt = CxxModuleMapFormat::Gcc; } else if (arg_modmapfmt == "msvc") { @@ -2753,279 +2717,18 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( cmGeneratedFileStream tmf(target_mods_file); tmf << target_module_info; - bool result = true; - - // Fortran doesn't support any of the file-set or BMI installation considered - // below. - if (arg_lang != "Fortran"_s) { - // Prepare the export information blocks. - std::string const config_upper = - cmSystemTools::UpperCase(export_info.Config); - std::vector<std::pair<std::unique_ptr<cmGeneratedFileStream>, - CxxModuleExport const*>> - exports; - for (auto const& exp : export_info.Exports) { - std::unique_ptr<cmGeneratedFileStream> properties; - - std::string const export_dir = - cmStrCat(exp.Prefix, '/', exp.CxxModuleInfoDir, '/'); - std::string const property_file_path = cmStrCat( - export_dir, "target-", exp.Name, '-', export_info.Config, ".cmake"); - properties = cm::make_unique<cmGeneratedFileStream>(property_file_path); - - // Set up the preamble. - *properties << "set_property(TARGET \"" << exp.Namespace << exp.Name - << "\"\n" - << " PROPERTY IMPORTED_CXX_MODULES_" << config_upper - << '\n'; - - exports.emplace_back(std::move(properties), &exp); + cmDyndepMetadataCallbacks cb; + cb.ModuleFile = + [mod_files](std::string const& name) -> cm::optional<std::string> { + auto m = mod_files.find(name); + if (m != mod_files.end()) { + return m->second; } + return {}; + }; - std::unique_ptr<cmGeneratedFileStream> bmi_install_script; - if (export_info.BmiInstallation) { - bmi_install_script = cm::make_unique<cmGeneratedFileStream>( - export_info.BmiInstallation->ScriptLocation); - } - - auto cmEscape = [](cm::string_view str) { - return cmOutputConverter::EscapeForCMake( - str, cmOutputConverter::WrapQuotes::NoWrap); - }; - auto install_destination = - [&cmEscape](std::string const& dest) -> std::pair<bool, std::string> { - if (cmSystemTools::FileIsFullPath(dest)) { - return std::make_pair(true, cmEscape(dest)); - } - return std::make_pair(false, - cmStrCat("${_IMPORT_PREFIX}/", cmEscape(dest))); - }; - - // public/private requirement tracking. - std::set<std::string> private_modules; - std::map<std::string, std::set<std::string>> public_source_requires; - - for (cmScanDepInfo const& object : objects) { - // Convert to forward slashes. - auto output_path = object.PrimaryOutput; -# ifdef _WIN32 - cmSystemTools::ConvertToUnixSlashes(output_path); -# endif - // Find the fileset for this object. - auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path); - bool const has_provides = !object.Provides.empty(); - if (fileset_info_itr == export_info.ObjectToFileSet.end()) { - // If it provides anything, it should have a `CXX_MODULES` or - // `CXX_MODULE_INTERNAL_PARTITIONS` type and be present. - if (has_provides) { - // Take the first module provided to provide context. - auto const& provides = object.Provides[0]; - char const* ok_types = "`CXX_MODULES`"; - if (provides.LogicalName.find(':') != std::string::npos) { - ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if " - "it is not `export`ed)"; - } - cmSystemTools::Error( - cmStrCat("Output ", object.PrimaryOutput, " provides the `", - provides.LogicalName, - "` module but it is not found in a `FILE_SET` of type ", - ok_types)); - result = false; - } - - // This object file does not provide anything, so nothing more needs to - // be done. - continue; - } - - auto const& file_set = fileset_info_itr->second; - - // Verify the fileset type for the object. - if (file_set.Type == "CXX_MODULES"_s) { - if (!has_provides) { - cmSystemTools::Error(cmStrCat( - "Output ", object.PrimaryOutput, - " is of type `CXX_MODULES` but does not provide a module")); - result = false; - continue; - } - } else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) { - if (!has_provides) { - cmSystemTools::Error(cmStrCat( - "Source ", file_set.SourcePath, - " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not " - "provide a module")); - result = false; - continue; - } - auto const& provides = object.Provides[0]; - if (provides.LogicalName.find(':') == std::string::npos) { - cmSystemTools::Error(cmStrCat( - "Source ", file_set.SourcePath, - " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not " - "provide a module partition")); - result = false; - continue; - } - } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) { - // TODO. - } else { - if (has_provides) { - auto const& provides = object.Provides[0]; - char const* ok_types = "`CXX_MODULES`"; - if (provides.LogicalName.find(':') != std::string::npos) { - ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if " - "it is not `export`ed)"; - } - cmSystemTools::Error(cmStrCat( - "Source ", file_set.SourcePath, " provides the `", - provides.LogicalName, "` C++ module but is of type `", - file_set.Type, "` module but must be of type ", ok_types)); - result = false; - } - - // Not a C++ module; ignore. - continue; - } - - if (!cmFileSetVisibilityIsForInterface(file_set.Visibility)) { - // Nothing needs to be conveyed about non-`PUBLIC` modules. - for (auto const& p : object.Provides) { - private_modules.insert(p.LogicalName); - } - continue; - } - - // The module is public. Record what it directly requires. - { - auto& reqs = public_source_requires[file_set.SourcePath]; - for (auto const& r : object.Requires) { - reqs.insert(r.LogicalName); - } - } - - // Write out properties and install rules for any exports. - for (auto const& p : object.Provides) { - bool bmi_dest_is_abs = false; - std::string bmi_destination; - if (export_info.BmiInstallation) { - auto dest = - install_destination(export_info.BmiInstallation->Destination); - bmi_dest_is_abs = dest.first; - bmi_destination = cmStrCat(dest.second, '/'); - } - - std::string install_bmi_path; - std::string build_bmi_path; - auto m = mod_files.find(p.LogicalName); - if (m != mod_files.end()) { - install_bmi_path = - cmStrCat(bmi_destination, - cmEscape(cmSystemTools::GetFilenameName(m->second))); - build_bmi_path = cmEscape(m->second); - } - - for (auto const& exp : exports) { - std::string iface_source; - if (exp.second->Install && file_set.Destination) { - auto dest = install_destination(*file_set.Destination); - iface_source = cmStrCat( - dest.second, '/', cmEscape(file_set.RelativeDirectory), - cmEscape(cmSystemTools::GetFilenameName(file_set.SourcePath))); - } else { - iface_source = cmEscape(file_set.SourcePath); - } - - std::string bmi_path; - if (exp.second->Install && export_info.BmiInstallation) { - bmi_path = install_bmi_path; - } else if (!exp.second->Install) { - bmi_path = build_bmi_path; - } - - if (iface_source.empty()) { - // No destination for the C++ module source; ignore this property - // value. - continue; - } - - *exp.first << " \"" << cmEscape(p.LogicalName) << '=' - << iface_source; - if (!bmi_path.empty()) { - *exp.first << ',' << bmi_path; - } - *exp.first << "\"\n"; - } - - if (bmi_install_script) { - auto const& bmi_install = *export_info.BmiInstallation; - - *bmi_install_script << "if (CMAKE_INSTALL_COMPONENT STREQUAL \"" - << cmEscape(bmi_install.Component) << '\"'; - if (!bmi_install.ExcludeFromAll) { - *bmi_install_script << " OR NOT CMAKE_INSTALL_COMPONENT"; - } - *bmi_install_script << ")\n"; - *bmi_install_script << " file(INSTALL\n" - " DESTINATION \""; - if (!bmi_dest_is_abs) { - *bmi_install_script << "${CMAKE_INSTALL_PREFIX}/"; - } - *bmi_install_script << cmEscape(bmi_install.Destination) - << "\"\n" - " TYPE FILE\n"; - if (bmi_install.Optional) { - *bmi_install_script << " OPTIONAL\n"; - } - if (!bmi_install.MessageLevel.empty()) { - *bmi_install_script << " " << bmi_install.MessageLevel << "\n"; - } - if (!bmi_install.Permissions.empty()) { - *bmi_install_script << " PERMISSIONS" << bmi_install.Permissions - << "\n"; - } - *bmi_install_script << " FILES \"" << m->second << "\")\n"; - if (bmi_dest_is_abs) { - *bmi_install_script - << " list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n" - " \"" - << cmEscape(cmSystemTools::GetFilenameName(m->second)) - << "\")\n" - " if (CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n" - " message(WARNING\n" - " \"ABSOLUTE path INSTALL DESTINATION : " - "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n" - " endif ()\n" - " if (CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n" - " message(FATAL_ERROR\n" - " \"ABSOLUTE path INSTALL DESTINATION forbidden (by " - "caller): ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n" - " endif ()\n"; - } - *bmi_install_script << "endif ()\n"; - } - } - } - - // Add trailing parenthesis for the `set_property` call. - for (auto const& exp : exports) { - *exp.first << ")\n"; - } - - // Check that public sources only require public modules. - for (auto const& pub_reqs : public_source_requires) { - for (auto const& req : pub_reqs.second) { - if (private_modules.count(req)) { - cmSystemTools::Error(cmStrCat( - "Public C++ module source `", pub_reqs.first, "` requires the `", - req, "` C++ module which is provided by a private source")); - result = false; - } - } - } - } - - return result; + return cmDyndepCollation::WriteDyndepMetadata(arg_lang, objects, export_info, + cb); } int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, @@ -3099,58 +2802,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, } } - cmGlobalNinjaGenerator::CxxModuleExportInfo export_info; - export_info.Config = tdi["config"].asString(); - if (export_info.Config.empty()) { - export_info.Config = "noconfig"; - } - Json::Value const& tdi_exports = tdi["exports"]; - if (tdi_exports.isArray()) { - for (auto const& tdi_export : tdi_exports) { - CxxModuleExport exp; - exp.Install = tdi_export["install"].asBool(); - exp.Name = tdi_export["export-name"].asString(); - exp.Destination = tdi_export["destination"].asString(); - exp.Prefix = tdi_export["export-prefix"].asString(); - exp.CxxModuleInfoDir = tdi_export["cxx-module-info-dir"].asString(); - exp.Namespace = tdi_export["namespace"].asString(); - - export_info.Exports.push_back(exp); - } - } - auto const& bmi_installation = tdi["bmi-installation"]; - if (bmi_installation.isObject()) { - CxxModuleBmiInstall bmi_install; - - bmi_install.Component = bmi_installation["component"].asString(); - bmi_install.Destination = bmi_installation["destination"].asString(); - bmi_install.ExcludeFromAll = bmi_installation["exclude-from-all"].asBool(); - bmi_install.Optional = bmi_installation["optional"].asBool(); - bmi_install.Permissions = bmi_installation["permissions"].asString(); - bmi_install.MessageLevel = bmi_installation["message-level"].asString(); - bmi_install.ScriptLocation = - bmi_installation["script-location"].asString(); - - export_info.BmiInstallation = bmi_install; - } - Json::Value const& tdi_cxx_modules = tdi["cxx-modules"]; - if (tdi_cxx_modules.isObject()) { - for (auto i = tdi_cxx_modules.begin(); i != tdi_cxx_modules.end(); ++i) { - CxxModuleFileSet& fsi = export_info.ObjectToFileSet[i.key().asString()]; - auto const& tdi_cxx_module_info = *i; - fsi.Name = tdi_cxx_module_info["name"].asString(); - fsi.RelativeDirectory = - tdi_cxx_module_info["relative-directory"].asString(); - fsi.SourcePath = tdi_cxx_module_info["source"].asString(); - fsi.Type = tdi_cxx_module_info["type"].asString(); - fsi.Visibility = cmFileSetVisibilityFromName( - tdi_cxx_module_info["visibility"].asString(), nullptr); - auto const& tdi_fs_dest = tdi_cxx_module_info["destination"]; - if (tdi_fs_dest.isString()) { - fsi.Destination = tdi_fs_dest.asString(); - } - } - } + auto export_info = cmDyndepCollation::ParseExportInfo(tdi); cmake cm(cmake::RoleInternal, cmState::Unknown); cm.SetHomeDirectory(dir_top_src); @@ -3160,7 +2812,7 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, !cm::static_reference_cast<cmGlobalNinjaGenerator>(ggd).WriteDyndepFile( dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, arg_dd, arg_ddis, module_dir, linked_target_dirs, arg_lang, arg_modmapfmt, - export_info)) { + *export_info)) { return 1; } return 0; @@ -3208,10 +2860,10 @@ cmGlobalNinjaMultiGenerator::cmGlobalNinjaMultiGenerator(cmake* cm) cm->GetState()->SetNinjaMulti(true); } -void cmGlobalNinjaMultiGenerator::GetDocumentation(cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalNinjaMultiGenerator::GetDocumentation() { - entry.Name = cmGlobalNinjaMultiGenerator::GetActualName(); - entry.Brief = "Generates build-<Config>.ninja files."; + return { cmGlobalNinjaMultiGenerator::GetActualName(), + "Generates build-<Config>.ninja files." }; } std::string cmGlobalNinjaMultiGenerator::ExpandCFGIntDir( diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index defa264..775e792 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -35,7 +35,7 @@ class cmMakefile; class cmOutputConverter; class cmStateDirectory; class cmake; -struct cmDocumentationEntry; +struct cmCxxModuleExportInfo; /** * \class cmGlobalNinjaGenerator @@ -193,7 +193,7 @@ public: /** Get encoding used by generator for ninja files */ codecvt::Encoding GetMakefileEncoding() const override; - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); void EnableLanguage(std::vector<std::string> const& languages, cmMakefile* mf, bool optional) override; @@ -292,7 +292,8 @@ public: } void AddCXXCompileCommand(const std::string& commandLine, - const std::string& sourceFile); + const std::string& sourceFile, + const std::string& objPath); /** * Add a rule to the generated build system. @@ -417,7 +418,6 @@ public: bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); } void StripNinjaOutputPathPrefixAsSuffix(std::string& path); - struct CxxModuleExportInfo; bool WriteDyndepFile( std::string const& dir_top_src, std::string const& dir_top_bld, std::string const& dir_cur_src, std::string const& dir_cur_bld, @@ -425,7 +425,7 @@ public: std::string const& module_dir, std::vector<std::string> const& linked_target_dirs, std::string const& arg_lang, std::string const& arg_modmapfmt, - CxxModuleExportInfo const& export_info); + cmCxxModuleExportInfo const& export_info); virtual std::string BuildAlias(const std::string& alias, const std::string& /*config*/) const @@ -469,7 +469,7 @@ public: bool IsSingleConfigUtility(cmGeneratorTarget const* target) const; - bool CheckCxxModuleSupport(); + bool CheckCxxModuleSupport() override; protected: void Generate() override; @@ -592,7 +592,7 @@ private: codecvt::Encoding NinjaExpectedEncoding = codecvt::None; - bool DiagnosedCxxModuleSupport = false; + bool DiagnosedCxxModuleNinjaSupport = false; void InitOutputPathPrefix(); @@ -655,7 +655,7 @@ public: new cmGlobalGeneratorSimpleFactory<cmGlobalNinjaMultiGenerator>()); } - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); std::string GetName() const override { diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index 21aa89c..30206b5 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -11,7 +11,6 @@ #include <cmext/algorithm> #include <cmext/memory> -#include "cmDocumentationEntry.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" @@ -71,11 +70,10 @@ cmGlobalUnixMakefileGenerator3::CreateLocalGenerator(cmMakefile* mf) cm::make_unique<cmLocalUnixMakefileGenerator3>(this, mf)); } -void cmGlobalUnixMakefileGenerator3::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalUnixMakefileGenerator3::GetDocumentation() { - entry.Name = cmGlobalUnixMakefileGenerator3::GetActualName(); - entry.Brief = "Generates standard UNIX makefiles."; + return { cmGlobalUnixMakefileGenerator3::GetActualName(), + "Generates standard UNIX makefiles." }; } void cmGlobalUnixMakefileGenerator3::ComputeTargetObjectDirectory( @@ -104,6 +102,9 @@ void cmGlobalUnixMakefileGenerator3::Configure() void cmGlobalUnixMakefileGenerator3::Generate() { + this->ClangTidyExportFixesDirs.clear(); + this->ClangTidyExportFixesFiles.clear(); + // first do superclass method this->cmGlobalGenerator::Generate(); @@ -139,11 +140,13 @@ void cmGlobalUnixMakefileGenerator3::Generate() *this->CommandDatabase << "\n]"; this->CommandDatabase.reset(); } + + this->RemoveUnknownClangTidyExportFixesFiles(); } void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand( const std::string& sourceFile, const std::string& workingDirectory, - const std::string& compileCommand) + const std::string& compileCommand, const std::string& objPath) { if (!this->CommandDatabase) { std::string commandDatabaseName = @@ -164,7 +167,9 @@ void cmGlobalUnixMakefileGenerator3::AddCXXCompileCommand( << "\",\n" << R"( "file": ")" << cmGlobalGenerator::EscapeJSON(sourceFile) - << "\"\n}"; + << "\",\n" + << R"( "output": ")" + << cmGlobalGenerator::EscapeJSON(objPath) << "\"\n}"; } void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2() diff --git a/Source/cmGlobalUnixMakefileGenerator3.h b/Source/cmGlobalUnixMakefileGenerator3.h index b9d333e..214ba2a 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.h +++ b/Source/cmGlobalUnixMakefileGenerator3.h @@ -24,7 +24,6 @@ class cmLocalUnixMakefileGenerator3; class cmMakefile; class cmMakefileTargetGenerator; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalUnixMakefileGenerator3 * \brief Write a Unix makefiles. @@ -101,7 +100,7 @@ public: bool SupportsCustomCommandDepfile() const override { return true; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( cmMakefile* mf) override; @@ -174,7 +173,8 @@ public: void AddCXXCompileCommand(const std::string& sourceFile, const std::string& workingDirectory, - const std::string& compileCommand); + const std::string& compileCommand, + const std::string& objPath); /** Does the make tool tolerate .NOTPARALLEL? */ virtual bool AllowNotParallel() const { return true; } diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx index bea2ae7..192663d 100644 --- a/Source/cmGlobalVisualStudio10Generator.cxx +++ b/Source/cmGlobalVisualStudio10Generator.cxx @@ -56,6 +56,7 @@ cmGlobalVisualStudio10Generator::cmGlobalVisualStudio10Generator( { this->DefaultCudaFlagTableName = "v10"; this->DefaultCudaHostFlagTableName = "v10"; + this->DefaultMarmasmFlagTableName = "v10"; this->DefaultNasmFlagTableName = "v10"; } @@ -301,7 +302,7 @@ bool cmGlobalVisualStudio10Generator::ParseGeneratorToolset( std::string const& ts, cmMakefile* mf) { std::vector<std::string> const fields = cmTokenize(ts, ","); - std::vector<std::string>::const_iterator fi = fields.begin(); + auto fi = fields.begin(); if (fi == fields.end()) { return true; } @@ -500,7 +501,8 @@ bool cmGlobalVisualStudio10Generator::InitializeWindowsStore(cmMakefile* mf) bool cmGlobalVisualStudio10Generator::InitializeTegraAndroid(cmMakefile* mf) { - std::string v = this->GetInstalledNsightTegraVersion(); + std::string v = + cmGlobalVisualStudio10Generator::GetInstalledNsightTegraVersion(); if (v.empty()) { mf->IssueMessage(MessageType::FATAL_ERROR, "CMAKE_SYSTEM_NAME is 'Android' but " @@ -772,9 +774,9 @@ std::string cmGlobalVisualStudio10Generator::FindMSBuildCommand() // Search in standard location. mskey = cmStrCat( - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\", + R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\)", this->GetToolsVersion(), ";MSBuildToolsPath"); - if (cmSystemTools::ReadRegistryValue(mskey.c_str(), msbuild, + if (cmSystemTools::ReadRegistryValue(mskey, msbuild, cmSystemTools::KeyWOW64_32)) { cmSystemTools::ConvertToUnixSlashes(msbuild); msbuild += "/MSBuild.exe"; @@ -797,6 +799,7 @@ std::string cmGlobalVisualStudio10Generator::FindDevEnvCommand() } // Skip over the cmGlobalVisualStudio8Generator implementation because // we expect a real devenv and do not want to look for VCExpress. + // NOLINTNEXTLINE(bugprone-parent-virtual-call) return this->cmGlobalVisualStudio71Generator::FindDevEnvCommand(); } @@ -1107,8 +1110,9 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand( // Decide if a restore is performed, based on a cache variable. if (cmValue cached = this->CMakeInstance->GetState()->GetCacheEntryValue( - "CMAKE_VS_NUGET_PACKAGE_RESTORE")) + "CMAKE_VS_NUGET_PACKAGE_RESTORE")) { restorePackages = cached.IsOn(); + } } if (restorePackages) { @@ -1136,7 +1140,7 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand( std::string extension = cmSystemTools::GetFilenameLastExtension(proj->GetRelativePath()); extension = cmSystemTools::LowerCase(extension); - if (extension.compare(".csproj") == 0) { + if (extension == ".csproj") { // Use correct platform name platform = slnData.GetConfigurationTarget(tname, plainConfig, platform); @@ -1154,8 +1158,6 @@ cmGlobalVisualStudio10Generator::GenerateBuildCommand( } else { makeCommand.Add(cmStrCat("/m:", std::to_string(jobs))); } - // Having msbuild.exe and cl.exe using multiple jobs is discouraged - makeCommand.Add("/p:CL_MPCount=1"); } // Respect the verbosity: 'n' normal will show build commands @@ -1466,6 +1468,13 @@ cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetCudaHostFlagTable() "CudaHost"); } +cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMarmasmFlagTable() + const +{ + return LoadFlagTable(std::string(), this->DefaultMarmasmFlagTableName, + "MARMASM"); +} + cmIDEFlagTable const* cmGlobalVisualStudio10Generator::GetMasmFlagTable() const { return LoadFlagTable(this->GetMasmFlagTableName(), @@ -1496,19 +1505,23 @@ std::string cmGlobalVisualStudio10Generator::GetClFlagTableName() const if (toolset == "v142") { return "v142"; - } else if (toolset == "v141") { + } + if (toolset == "v141") { return "v141"; - } else if (useToolset == "v140") { + } + if (useToolset == "v140") { return "v140"; - } else if (useToolset == "v120") { + } + if (useToolset == "v120") { return "v12"; - } else if (useToolset == "v110") { + } + if (useToolset == "v110") { return "v11"; - } else if (useToolset == "v100") { + } + if (useToolset == "v100") { return "v10"; - } else { - return ""; } + return ""; } std::string cmGlobalVisualStudio10Generator::GetCSharpFlagTableName() const @@ -1518,19 +1531,23 @@ std::string cmGlobalVisualStudio10Generator::GetCSharpFlagTableName() const if (useToolset == "v142") { return "v142"; - } else if (useToolset == "v141") { + } + if (useToolset == "v141") { return "v141"; - } else if (useToolset == "v140") { + } + if (useToolset == "v140") { return "v140"; - } else if (useToolset == "v120") { + } + if (useToolset == "v120") { return "v12"; - } else if (useToolset == "v110") { + } + if (useToolset == "v110") { return "v11"; - } else if (useToolset == "v100") { + } + if (useToolset == "v100") { return "v10"; - } else { - return ""; } + return ""; } std::string cmGlobalVisualStudio10Generator::GetRcFlagTableName() const @@ -1541,15 +1558,17 @@ std::string cmGlobalVisualStudio10Generator::GetRcFlagTableName() const if ((useToolset == "v140") || (useToolset == "v141") || (useToolset == "v142")) { return "v14"; - } else if (useToolset == "v120") { + } + if (useToolset == "v120") { return "v12"; - } else if (useToolset == "v110") { + } + if (useToolset == "v110") { return "v11"; - } else if (useToolset == "v100") { + } + if (useToolset == "v100") { return "v10"; - } else { - return ""; } + return ""; } std::string cmGlobalVisualStudio10Generator::GetLibFlagTableName() const @@ -1560,15 +1579,17 @@ std::string cmGlobalVisualStudio10Generator::GetLibFlagTableName() const if ((useToolset == "v140") || (useToolset == "v141") || (useToolset == "v142")) { return "v14"; - } else if (useToolset == "v120") { + } + if (useToolset == "v120") { return "v12"; - } else if (useToolset == "v110") { + } + if (useToolset == "v110") { return "v11"; - } else if (useToolset == "v100") { + } + if (useToolset == "v100") { return "v10"; - } else { - return ""; } + return ""; } std::string cmGlobalVisualStudio10Generator::GetLinkFlagTableName() const @@ -1578,19 +1599,23 @@ std::string cmGlobalVisualStudio10Generator::GetLinkFlagTableName() const if (useToolset == "v142") { return "v142"; - } else if (useToolset == "v141") { + } + if (useToolset == "v141") { return "v141"; - } else if (useToolset == "v140") { + } + if (useToolset == "v140") { return "v140"; - } else if (useToolset == "v120") { + } + if (useToolset == "v120") { return "v12"; - } else if (useToolset == "v110") { + } + if (useToolset == "v110") { return "v11"; - } else if (useToolset == "v100") { + } + if (useToolset == "v100") { return "v10"; - } else { - return ""; } + return ""; } std::string cmGlobalVisualStudio10Generator::GetMasmFlagTableName() const @@ -1601,15 +1626,17 @@ std::string cmGlobalVisualStudio10Generator::GetMasmFlagTableName() const if ((useToolset == "v140") || (useToolset == "v141") || (useToolset == "v142")) { return "v14"; - } else if (useToolset == "v120") { + } + if (useToolset == "v120") { return "v12"; - } else if (useToolset == "v110") { + } + if (useToolset == "v110") { return "v11"; - } else if (useToolset == "v100") { + } + if (useToolset == "v100") { return "v10"; - } else { - return ""; } + return ""; } std::string cmGlobalVisualStudio10Generator::CanonicalToolsetName( diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index b32c0a7..63c21c5 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -163,6 +163,7 @@ public: cmIDEFlagTable const* GetLinkFlagTable() const; cmIDEFlagTable const* GetCudaFlagTable() const; cmIDEFlagTable const* GetCudaHostFlagTable() const; + cmIDEFlagTable const* GetMarmasmFlagTable() const; cmIDEFlagTable const* GetMasmFlagTable() const; cmIDEFlagTable const* GetNasmFlagTable() const; @@ -226,6 +227,7 @@ protected: std::string DefaultLinkFlagTableName; std::string DefaultCudaFlagTableName; std::string DefaultCudaHostFlagTableName; + std::string DefaultMarmasmFlagTableName; std::string DefaultMasmFlagTableName; std::string DefaultNasmFlagTableName; std::string DefaultRCFlagTableName; @@ -239,15 +241,10 @@ protected: private: struct LongestSourcePath { - LongestSourcePath() - : Length(0) - , Target(0) - , SourceFile(0) - { - } - size_t Length; - cmGeneratorTarget* Target; - cmSourceFile const* SourceFile; + LongestSourcePath() = default; + size_t Length = 0; + cmGeneratorTarget* Target = nullptr; + cmSourceFile const* SourceFile = nullptr; std::string SourceRel; }; LongestSourcePath LongestSource; diff --git a/Source/cmGlobalVisualStudio11Generator.cxx b/Source/cmGlobalVisualStudio11Generator.cxx index 086d3af..3ad10eb 100644 --- a/Source/cmGlobalVisualStudio11Generator.cxx +++ b/Source/cmGlobalVisualStudio11Generator.cxx @@ -7,7 +7,6 @@ #include <utility> #include <vector> -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" #include "cmGlobalVisualStudioGenerator.h" @@ -23,7 +22,7 @@ static const char* cmVS11GenName(const std::string& name, std::string& genName) { if (strncmp(name.c_str(), vs11generatorName, sizeof(vs11generatorName) - 6) != 0) { - return 0; + return nullptr; } const char* p = name.c_str() + sizeof(vs11generatorName) - 6; if (cmHasLiteralPrefix(p, " 2012")) { @@ -74,11 +73,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(std::move(ret)); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs11generatorName) + " [arch]"; - entry.Brief = "Deprecated. Generates Visual Studio 2012 project files. " - "Optional [arch] can be \"Win64\" or \"ARM\"."; + return { std::string(vs11generatorName) + " [arch]", + "Deprecated. Generates Visual Studio 2012 project files. " + "Optional [arch] can be \"Win64\" or \"ARM\"." }; } std::vector<std::string> GetGeneratorNames() const override @@ -161,6 +160,18 @@ bool cmGlobalVisualStudio11Generator::MatchesGeneratorName( return false; } +void cmGlobalVisualStudio11Generator::EnableLanguage( + std::vector<std::string> const& lang, cmMakefile* mf, bool optional) +{ + for (std::string const& it : lang) { + if (it == "ASM_MARMASM") { + this->MarmasmEnabled = true; + } + } + this->AddPlatformDefinitions(mf); + cmGlobalVisualStudio10Generator::EnableLanguage(lang, mf, optional); +} + bool cmGlobalVisualStudio11Generator::InitializeWindowsPhone(cmMakefile* mf) { if (!this->SelectWindowsPhoneToolset(this->DefaultPlatformToolset)) { @@ -205,9 +216,8 @@ bool cmGlobalVisualStudio11Generator::SelectWindowsPhoneToolset( this->IsWindowsDesktopToolsetInstalled()) { toolset = "v110_wp80"; return true; - } else { - return false; } + return false; } return this->cmGlobalVisualStudio10Generator::SelectWindowsPhoneToolset( toolset); @@ -221,9 +231,8 @@ bool cmGlobalVisualStudio11Generator::SelectWindowsStoreToolset( this->IsWindowsDesktopToolsetInstalled()) { toolset = "v110"; return true; - } else { - return false; } + return false; } return this->cmGlobalVisualStudio10Generator::SelectWindowsStoreToolset( toolset); @@ -234,6 +243,7 @@ bool cmGlobalVisualStudio11Generator::UseFolderProperty() const // Intentionally skip up to the top-level class implementation. // Folders are not supported by the Express editions in VS10 and earlier, // but they are in VS11 Express and above. + // NOLINTNEXTLINE(bugprone-parent-virtual-call) return cmGlobalGenerator::UseFolderProperty(); } diff --git a/Source/cmGlobalVisualStudio11Generator.h b/Source/cmGlobalVisualStudio11Generator.h index 2f8a7f6..fd25984 100644 --- a/Source/cmGlobalVisualStudio11Generator.h +++ b/Source/cmGlobalVisualStudio11Generator.h @@ -25,6 +25,9 @@ public: bool MatchesGeneratorName(const std::string& name) const override; + void EnableLanguage(std::vector<std::string> const& languages, cmMakefile*, + bool optional) override; + bool SupportsCustomCommandDepfile() const override { return true; } cm::optional<cmDepfileFormat> DepfileFormat() const override diff --git a/Source/cmGlobalVisualStudio12Generator.cxx b/Source/cmGlobalVisualStudio12Generator.cxx index 600ee0a..d417f9e 100644 --- a/Source/cmGlobalVisualStudio12Generator.cxx +++ b/Source/cmGlobalVisualStudio12Generator.cxx @@ -6,7 +6,6 @@ #include <sstream> #include <vector> -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" #include "cmGlobalVisualStudioGenerator.h" @@ -22,7 +21,7 @@ static const char* cmVS12GenName(const std::string& name, std::string& genName) { if (strncmp(name.c_str(), vs12generatorName, sizeof(vs12generatorName) - 6) != 0) { - return 0; + return nullptr; } const char* p = name.c_str() + sizeof(vs12generatorName) - 6; if (cmHasLiteralPrefix(p, " 2013")) { @@ -62,11 +61,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs12generatorName) + " [arch]"; - entry.Brief = "Generates Visual Studio 2013 project files. " - "Optional [arch] can be \"Win64\" or \"ARM\"."; + return { std::string(vs12generatorName) + " [arch]", + "Generates Visual Studio 2013 project files. " + "Optional [arch] can be \"Win64\" or \"ARM\"." }; } std::vector<std::string> GetGeneratorNames() const override @@ -195,9 +194,8 @@ bool cmGlobalVisualStudio12Generator::SelectWindowsPhoneToolset( this->IsWindowsDesktopToolsetInstalled()) { toolset = "v120_wp81"; return true; - } else { - return false; } + return false; } return this->cmGlobalVisualStudio11Generator::SelectWindowsPhoneToolset( toolset); @@ -211,9 +209,8 @@ bool cmGlobalVisualStudio12Generator::SelectWindowsStoreToolset( this->IsWindowsDesktopToolsetInstalled()) { toolset = "v120"; return true; - } else { - return false; } + return false; } return this->cmGlobalVisualStudio11Generator::SelectWindowsStoreToolset( toolset); diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx index 9f94cca..7424ca3 100644 --- a/Source/cmGlobalVisualStudio14Generator.cxx +++ b/Source/cmGlobalVisualStudio14Generator.cxx @@ -7,7 +7,6 @@ #include <cm/vector> -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" #include "cmGlobalVisualStudioGenerator.h" @@ -24,7 +23,7 @@ static const char* cmVS14GenName(const std::string& name, std::string& genName) { if (strncmp(name.c_str(), vs14generatorName, sizeof(vs14generatorName) - 6) != 0) { - return 0; + return nullptr; } const char* p = name.c_str() + sizeof(vs14generatorName) - 6; if (cmHasLiteralPrefix(p, " 2015")) { @@ -64,11 +63,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs14generatorName) + " [arch]"; - entry.Brief = "Generates Visual Studio 2015 project files. " - "Optional [arch] can be \"Win64\" or \"ARM\"."; + return { std::string(vs14generatorName) + " [arch]", + "Generates Visual Studio 2015 project files. " + "Optional [arch] can be \"Win64\" or \"ARM\"." }; } std::vector<std::string> GetGeneratorNames() const override @@ -214,9 +213,8 @@ bool cmGlobalVisualStudio14Generator::SelectWindowsStoreToolset( this->IsWindowsDesktopToolsetInstalled()) { toolset = "v140"; return true; - } else { - return false; } + return false; } return this->cmGlobalVisualStudio12Generator::SelectWindowsStoreToolset( toolset); @@ -256,7 +254,7 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKMaxVersion( return std::string(); } // If the value is something else, trust that it is a valid SDK value. - else if (value) { + if (value) { return *value; } // If value is an invalid pointer, leave result unchanged. @@ -374,6 +372,7 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion( return sdks.at(0); } #endif + (void)mf; // Return an empty string return std::string(); } diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index 758ce83..06fd61c 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -101,14 +101,14 @@ void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout, // check to see if this is a fortran build std::string ext = ".vcproj"; const char* project = - "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \""; + R"(Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = ")"; if (this->TargetIsFortranOnly(t)) { ext = ".vfproj"; - project = "Project(\"{6989167D-11E4-40FE-8C1A-2192A86A7E90}\") = \""; + project = R"(Project("{6989167D-11E4-40FE-8C1A-2192A86A7E90}") = ")"; } if (t->IsCSharpOnly()) { ext = ".csproj"; - project = "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \""; + project = R"(Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = ")"; } cmValue targetExt = t->GetProperty("GENERATOR_FILE_NAME_EXT"); if (targetExt) { @@ -125,11 +125,11 @@ void cmGlobalVisualStudio71Generator::WriteProject(std::ostream& fout, fout << "EndProject\n"; - UtilityDependsMap::iterator ui = this->UtilityDepends.find(t); + auto ui = this->UtilityDepends.find(t); if (ui != this->UtilityDepends.end()) { const char* uname = ui->second.c_str(); /* clang-format off */ - fout << "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"" + fout << R"(Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = ")" << uname << "\", \"" << this->ConvertToSolutionPath(dir) << (dir[0]? "\\":"") << uname << ".vcproj" << "\", \"{" @@ -169,7 +169,9 @@ void cmGlobalVisualStudio71Generator::WriteExternalProject( { fout << "Project(\"{" << (typeGuid ? typeGuid - : std::string(this->ExternalProjectType(location))) + : std::string( + cmGlobalVisualStudio71Generator::ExternalProjectType( + location))) << "}\") = \"" << name << "\", \"" << this->ConvertToSolutionPath(location) << "\", \"{" << this->GetGUID(name) << "}\"\n"; @@ -216,8 +218,7 @@ void cmGlobalVisualStudio71Generator::WriteProjectConfigurations( } fout << "\t\t{" << guid << "}." << i << ".ActiveCfg = " << dstConfig << "|" << platformName << std::endl; - std::set<std::string>::const_iterator ci = - configsPartOfDefaultBuild.find(i); + auto ci = configsPartOfDefaultBuild.find(i); if (!(ci == configsPartOfDefaultBuild.end())) { fout << "\t\t{" << guid << "}." << i << ".Build.0 = " << dstConfig << "|" << platformName << std::endl; diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index ff76762..c375d60 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -70,14 +70,13 @@ cmGlobalVisualStudio7Generator::cmGlobalVisualStudio7Generator( : cmGlobalVisualStudioGenerator(cm, platformInGeneratorName) { this->DevEnvCommandInitialized = false; + this->MarmasmEnabled = false; this->MasmEnabled = false; this->NasmEnabled = false; this->ExtraFlagTable = cmVS7ExtraFlagTable; } -cmGlobalVisualStudio7Generator::~cmGlobalVisualStudio7Generator() -{ -} +cmGlobalVisualStudio7Generator::~cmGlobalVisualStudio7Generator() = default; // Package GUID of Intel Visual Fortran plugin to VS IDE #define CM_INTEL_PLUGIN_GUID "{B68A201D-CB9B-47AF-A52F-7EEC72E217E4}" @@ -159,7 +158,7 @@ std::string cmGlobalVisualStudio7Generator::FindDevEnvCommand() // Search in standard location. vskey = this->GetRegistryBase() + ";InstallDir"; - if (cmSystemTools::ReadRegistryValue(vskey.c_str(), vscmd, + if (cmSystemTools::ReadRegistryValue(vskey, vscmd, cmSystemTools::KeyWOW64_32)) { cmSystemTools::ConvertToUnixSlashes(vscmd); vscmd += "/devenv.com"; @@ -170,9 +169,9 @@ std::string cmGlobalVisualStudio7Generator::FindDevEnvCommand() // Search where VS15Preview places it. vskey = cmStrCat( - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7;", + R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7;)", this->GetIDEVersion()); - if (cmSystemTools::ReadRegistryValue(vskey.c_str(), vscmd, + if (cmSystemTools::ReadRegistryValue(vskey, vscmd, cmSystemTools::KeyWOW64_32)) { cmSystemTools::ConvertToUnixSlashes(vscmd); vscmd += "/Common7/IDE/devenv.com"; @@ -191,17 +190,23 @@ const char* cmGlobalVisualStudio7Generator::ExternalProjectType( std::string extension = cmSystemTools::GetFilenameLastExtension(location); if (extension == ".vbproj") { return "F184B08F-C81C-45F6-A57F-5ABD9991F28F"; - } else if (extension == ".csproj") { + } + if (extension == ".csproj") { return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC"; - } else if (extension == ".fsproj") { + } + if (extension == ".fsproj") { return "F2A71F9B-5D33-465A-A702-920D77279786"; - } else if (extension == ".vdproj") { + } + if (extension == ".vdproj") { return "54435603-DBB4-11D2-8724-00A0C9A8B90C"; - } else if (extension == ".dbproj") { + } + if (extension == ".dbproj") { return "C8D11400-126E-41CD-887F-60BD40844F9E"; - } else if (extension == ".wixproj") { + } + if (extension == ".wixproj") { return "930C7802-8A8C-48F9-8165-68863BCCD9DD"; - } else if (extension == ".pyproj") { + } + if (extension == ".pyproj") { return "888888A0-9F3D-457C-B088-3A5042F75D52"; } return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942"; @@ -333,7 +338,7 @@ void cmGlobalVisualStudio7Generator::OutputSLNFile( } this->CurrentProject = root->GetProjectName(); std::string fname = GetSLNFile(root); - cmGeneratedFileStream fout(fname.c_str()); + cmGeneratedFileStream fout(fname); fout.SetCopyIfDifferent(true); if (!fout) { return; @@ -379,7 +384,8 @@ void cmGlobalVisualStudio7Generator::WriteTargetConfigurations( // On VS 19 and above, always map .NET SDK projects to "Any CPU". if (target->IsDotNetSdkTarget() && this->GetVersion() >= VSVersion::VS16 && - !this->IsReservedTarget(target->GetName())) { + !cmGlobalVisualStudio7Generator::IsReservedTarget( + target->GetName())) { mapping = "Any CPU"; } this->WriteProjectConfigurations(fout, *vcprojName, *target, configs, @@ -420,7 +426,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT"); if (expath) { std::string project = target->GetName(); - std::string location = *expath; + std::string const& location = *expath; this->WriteExternalProject(fout, project, location, target->GetProperty("VS_PROJECT_TYPE"), @@ -451,7 +457,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( std::string cumulativePath; for (std::string const& iter : tokens) { - if (!iter.size()) { + if (iter.empty()) { continue; } @@ -500,7 +506,7 @@ void cmGlobalVisualStudio7Generator::WriteFoldersContent(std::ostream& fout) std::string guidParent(this->GetGUID(key)); for (std::string const& it : iter.second) { - std::string value(it); + std::string const& value(it); std::string guid(this->GetGUID(value)); fout << "\t\t{" << guid << "} = {" << guidParent << "}\n"; @@ -516,7 +522,7 @@ std::string cmGlobalVisualStudio7Generator::ConvertToSolutionPath( // use windows slashes. std::string d = path; std::string::size_type pos = 0; - while ((pos = d.find('/', pos)) != d.npos) { + while ((pos = d.find('/', pos)) != std::string::npos) { d[pos++] = '\\'; } return d; @@ -540,8 +546,9 @@ void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections( } else if (cmHasLiteralPrefix(name, "POST_")) { name = name.substr(5); sectionType = "postSolution"; - } else + } else { continue; + } if (!name.empty()) { bool addGuid = false; if (name == "ExtensibilityGlobals" && sectionType == "postSolution") { @@ -579,9 +586,10 @@ void cmGlobalVisualStudio7Generator::WriteSLNGlobalSections( << "\t\tSolutionGuid = {" << guid << "}\n" << "\tEndGlobalSection\n"; } - if (!extensibilityAddInsOverridden) + if (!extensibilityAddInsOverridden) { fout << "\tGlobalSection(ExtensibilityAddIns) = postSolution\n" << "\tEndGlobalSection\n"; + } } // Standard end of dsw file @@ -600,13 +608,13 @@ std::string cmGlobalVisualStudio7Generator::WriteUtilityDepend( std::string fname = cmStrCat(target->GetLocalGenerator()->GetCurrentBinaryDirectory(), '/', pname, ".vcproj"); - cmGeneratedFileStream fout(fname.c_str()); + cmGeneratedFileStream fout(fname); fout.SetCopyIfDifferent(true); - std::string guid = this->GetGUID(pname.c_str()); + std::string guid = this->GetGUID(pname); /* clang-format off */ fout << - "<?xml version=\"1.0\" encoding = \"" + R"(<?xml version="1.0" encoding = ")" << this->Encoding() << "\"?>\n" "<VisualStudioProject\n" "\tProjectType=\"Visual C++\"\n" @@ -729,13 +737,12 @@ std::set<std::string> cmGlobalVisualStudio7Generator::IsPartOfDefaultBuild( bool cmGlobalVisualStudio7Generator::IsDependedOn( OrderedTargetDependSet const& projectTargets, cmGeneratorTarget const* gtIn) { - for (cmTargetDepend const& l : projectTargets) { - TargetDependSet const& tgtdeps = this->GetTargetDirectDepends(l); - if (tgtdeps.count(gtIn)) { - return true; - } - } - return false; + return std::any_of(projectTargets.begin(), projectTargets.end(), + [this, gtIn](cmTargetDepend const& l) { + TargetDependSet const& tgtdeps = + this->GetTargetDirectDepends(l); + return tgtdeps.count(gtIn); + }); } std::string cmGlobalVisualStudio7Generator::Encoding() diff --git a/Source/cmGlobalVisualStudio7Generator.h b/Source/cmGlobalVisualStudio7Generator.h index 288069c..6f6109e 100644 --- a/Source/cmGlobalVisualStudio7Generator.h +++ b/Source/cmGlobalVisualStudio7Generator.h @@ -31,7 +31,7 @@ class BT; class cmGlobalVisualStudio7Generator : public cmGlobalVisualStudioGenerator { public: - ~cmGlobalVisualStudio7Generator(); + ~cmGlobalVisualStudio7Generator() override; //! Create a local generator appropriate to this Global Generator std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( @@ -106,6 +106,7 @@ public: bool FindMakeProgram(cmMakefile* mf) override; /** Is the Microsoft Assembler enabled? */ + bool IsMarmasmEnabled() const { return this->MarmasmEnabled; } bool IsMasmEnabled() const { return this->MasmEnabled; } bool IsNasmEnabled() const { return this->NasmEnabled; } @@ -114,6 +115,8 @@ public: cmIDEFlagTable const* ExtraFlagTable; + virtual bool SupportsCxxModuleDyndep() const { return false; } + protected: cmGlobalVisualStudio7Generator(cmake* cm, std::string const& platformInGeneratorName); @@ -157,8 +160,6 @@ protected: cmValue typeGuid, const std::set<BT<std::pair<std::string, bool>>>& dependencies) = 0; - virtual bool SupportsCxxModuleDyndep() const { return false; } - std::string ConvertToSolutionPath(const std::string& path); std::set<std::string> IsPartOfDefaultBuild( @@ -176,6 +177,7 @@ protected: // Set during OutputSLNFile with the name of the current project. // There is one SLN file per project. std::string CurrentProject; + bool MarmasmEnabled; bool MasmEnabled; bool NasmEnabled; diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index 323ee67..647fc2d 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -44,7 +44,8 @@ cmGlobalVisualStudio8Generator::cmGlobalVisualStudio8Generator( { this->ProjectConfigurationSectionName = "ProjectConfigurationPlatforms"; this->Name = name; - this->ExtraFlagTable = this->GetExtraFlagTableVS8(); + this->ExtraFlagTable = + cmGlobalVisualStudio8Generator::GetExtraFlagTableVS8(); } std::string cmGlobalVisualStudio8Generator::FindDevEnvCommand() @@ -52,9 +53,9 @@ std::string cmGlobalVisualStudio8Generator::FindDevEnvCommand() // First look for VCExpress. std::string vsxcmd; std::string vsxkey = - cmStrCat("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\", + cmStrCat(R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VCExpress\)", this->GetIDEVersion(), ";InstallDir"); - if (cmSystemTools::ReadRegistryValue(vsxkey.c_str(), vsxcmd, + if (cmSystemTools::ReadRegistryValue(vsxkey, vsxcmd, cmSystemTools::KeyWOW64_32)) { cmSystemTools::ConvertToUnixSlashes(vsxcmd); vsxcmd += "/VCExpress.exe"; @@ -149,6 +150,7 @@ void cmGlobalVisualStudio8Generator::Configure() bool cmGlobalVisualStudio8Generator::UseFolderProperty() const { + // NOLINTNEXTLINE(bugprone-parent-virtual-call) return IsExpressEdition() ? false : cmGlobalGenerator::UseFolderProperty(); } @@ -172,7 +174,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() std::move(cc)); auto ptr = cm::make_unique<cmGeneratorTarget>(tgt, &lg); - auto gt = ptr.get(); + auto* gt = ptr.get(); lg.AddGeneratorTarget(std::move(ptr)); // Organize in the "predefined targets" folder: @@ -190,7 +192,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() cmStrCat(generators[0]->GetMakefile()->GetCurrentBinaryDirectory(), '/', stampList); std::string stampFile; - cmGeneratedFileStream fout(stampListFile.c_str()); + cmGeneratedFileStream fout(stampListFile); for (const auto& gi : generators) { stampFile = cmStrCat(gi->GetMakefile()->GetCurrentBinaryDirectory(), "/CMakeFiles/generate.stamp"); @@ -237,8 +239,7 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() // Sort the list of input files and remove duplicates. std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>()); - std::vector<std::string>::iterator new_end = - std::unique(listFiles.begin(), listFiles.end()); + auto new_end = std::unique(listFiles.begin(), listFiles.end()); listFiles.erase(new_end, listFiles.end()); // Create a rule to re-run CMake. @@ -277,8 +278,8 @@ void cmGlobalVisualStudio8Generator::AddExtraIDETargets() { cmGlobalVisualStudio7Generator::AddExtraIDETargets(); if (this->AddCheckTarget()) { - for (unsigned int i = 0; i < this->LocalGenerators.size(); ++i) { - const auto& tgts = this->LocalGenerators[i]->GetGeneratorTargets(); + for (auto& LocalGenerator : this->LocalGenerators) { + const auto& tgts = LocalGenerator->GetGeneratorTargets(); // All targets depend on the build-system check target. for (const auto& ti : tgts) { if (ti->GetName() != CMAKE_CHECK_BUILD_SYSTEM_TARGET) { @@ -324,8 +325,7 @@ void cmGlobalVisualStudio8Generator::WriteProjectConfigurations( << (!platformMapping.empty() ? platformMapping : this->GetPlatformName()) << "\n"; - std::set<std::string>::const_iterator ci = - configsPartOfDefaultBuild.find(i); + auto ci = configsPartOfDefaultBuild.find(i); if (!(ci == configsPartOfDefaultBuild.end())) { fout << "\t\t{" << guid << "}." << i << "|" << this->GetPlatformName() << ".Build.0 = " << dstConfig << "|" @@ -382,6 +382,7 @@ bool cmGlobalVisualStudio8Generator::ComputeTargetDepends() { // Skip over the cmGlobalVisualStudioGenerator implementation! // We do not need the support that VS <= 7.1 needs. + // NOLINTNEXTLINE(bugprone-parent-virtual-call) return this->cmGlobalGenerator::ComputeTargetDepends(); } @@ -404,20 +405,23 @@ bool cmGlobalVisualStudio8Generator::NeedLinkLibraryDependencies( cmGeneratorTarget* target) { // Look for utility dependencies that magically link. - for (BT<std::pair<std::string, bool>> const& ui : target->GetUtilities()) { - if (cmGeneratorTarget* depTarget = - target->GetLocalGenerator()->FindGeneratorTargetToUse( - ui.Value.first)) { - if (depTarget->IsInBuildSystem() && - depTarget->GetProperty("EXTERNAL_MSPROJECT")) { - // This utility dependency names an external .vcproj target. - // We use LinkLibraryDependencies="true" to link to it without - // predicting the .lib file location or name. - return true; + auto const& utilities = target->GetUtilities(); + return std::any_of( + utilities.begin(), utilities.end(), + [target](BT<std::pair<std::string, bool>> const& ui) { + if (cmGeneratorTarget* depTarget = + target->GetLocalGenerator()->FindGeneratorTargetToUse( + ui.Value.first)) { + if (depTarget->IsInBuildSystem() && + depTarget->GetProperty("EXTERNAL_MSPROJECT")) { + // This utility dependency names an external .vcproj target. + // We use LinkLibraryDependencies="true" to link to it without + // predicting the .lib file location or name. + return true; + } } - } - } - return false; + return false; + }); } static cmVS7FlagTable cmVS8ExtraFlagTable[] = { diff --git a/Source/cmGlobalVisualStudio9Generator.cxx b/Source/cmGlobalVisualStudio9Generator.cxx index e03e665..9f6550b 100644 --- a/Source/cmGlobalVisualStudio9Generator.cxx +++ b/Source/cmGlobalVisualStudio9Generator.cxx @@ -6,7 +6,6 @@ #include <utility> #include <vector> -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" #include "cmGlobalVisualStudioGenerator.h" @@ -62,11 +61,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(std::move(ret)); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs9generatorName) + " [arch]"; - entry.Brief = "Generates Visual Studio 2008 project files. " - "Optional [arch] can be \"Win64\" or \"IA64\"."; + return { std::string(vs9generatorName) + " [arch]", + "Generates Visual Studio 2008 project files. " + "Optional [arch] can be \"Win64\" or \"IA64\"." }; } std::vector<std::string> GetGeneratorNames() const override @@ -159,5 +158,5 @@ std::string cmGlobalVisualStudio9Generator::GetUserMacrosDirectory() std::string cmGlobalVisualStudio9Generator::GetUserMacrosRegKeyBase() { - return "Software\\Microsoft\\VisualStudio\\9.0\\vsmacros"; + return R"(Software\Microsoft\VisualStudio\9.0\vsmacros)"; } diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 9d168d0..31f6f77 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -51,9 +51,7 @@ cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator( } } -cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator() -{ -} +cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator() = default; cmGlobalVisualStudioGenerator::VSVersion cmGlobalVisualStudioGenerator::GetVersion() const @@ -188,7 +186,7 @@ std::string cmGlobalVisualStudioGenerator::GetRegistryBase() std::string cmGlobalVisualStudioGenerator::GetRegistryBase(const char* version) { - std::string key = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\"; + std::string key = R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\)"; return key + version; } @@ -520,13 +518,12 @@ std::string cmGlobalVisualStudioGenerator::GetStartupProjectName( std::string startup = *n; if (this->FindTarget(startup)) { return startup; - } else { - root->GetMakefile()->IssueMessage( - MessageType::AUTHOR_WARNING, - "Directory property VS_STARTUP_PROJECT specifies target " - "'" + - startup + "' that does not exist. Ignoring."); } + root->GetMakefile()->IssueMessage( + MessageType::AUTHOR_WARNING, + "Directory property VS_STARTUP_PROJECT specifies target " + "'" + + startup + "' that does not exist. Ignoring."); } // default, if not specified @@ -961,7 +958,7 @@ void cmGlobalVisualStudioGenerator::AddSymbolExportCommand( commands.push_back(std::move(command)); } -static bool OpenSolution(std::string sln) +static bool OpenSolution(std::string const& sln) { HRESULT comInitialized = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 576e4f2..3e20ada 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -44,7 +44,7 @@ public: VS17 = 170 }; - virtual ~cmGlobalVisualStudioGenerator(); + ~cmGlobalVisualStudioGenerator() override; VSVersion GetVersion() const; void SetVersion(VSVersion v); @@ -133,8 +133,8 @@ public: std::string First; public: - TargetCompare(std::string const& first) - : First(first) + TargetCompare(std::string first) + : First(std::move(first)) { } bool operator()(cmGeneratorTarget const* l, @@ -193,7 +193,6 @@ protected: using UtilityDependsMap = std::map<cmGeneratorTarget const*, std::string>; UtilityDependsMap UtilityDepends; -protected: VSVersion Version; bool ExpressEdition; diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.cxx b/Source/cmGlobalVisualStudioVersionedGenerator.cxx index be318c1..415eb7c 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.cxx +++ b/Source/cmGlobalVisualStudioVersionedGenerator.cxx @@ -14,7 +14,6 @@ #include "cmsys/Glob.hxx" #include "cmsys/RegularExpression.hxx" -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmGlobalGeneratorFactory.h" #include "cmMakefile.h" @@ -54,7 +53,8 @@ static bool VSIsArm64Host() # undef CM_VS_GCC_DIAGNOSTIC_PUSHED #endif - USHORT processMachine, nativeMachine; + USHORT processMachine; + USHORT nativeMachine; return s_IsWow64Process2Impl != nullptr && s_IsWow64Process2Impl(GetCurrentProcess(), &processMachine, @@ -66,7 +66,7 @@ static bool VSHasDotNETFrameworkArm64() { std::string dotNetArm64; return cmSystemTools::ReadRegistryValue( - "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\.NETFramework;InstallRootArm64", + R"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework;InstallRootArm64)", dotNetArm64, cmSystemTools::KeyWOW64_64); } @@ -86,19 +86,19 @@ static std::string VSHostPlatformName() { if (VSIsArm64Host()) { return "ARM64"; - } else if (VSIsWow64()) { + } + if (VSIsWow64()) { return "x64"; - } else { + } #if defined(_M_ARM) - return "ARM"; + return "ARM"; #elif defined(_M_IA64) - return "Itanium"; + return "Itanium"; #elif defined(_WIN64) - return "x64"; + return "x64"; #else - return "Win32"; + return "Win32"; #endif - } } static std::string VSHostArchitecture( @@ -106,19 +106,19 @@ static std::string VSHostArchitecture( { if (VSIsArm64Host()) { return v >= cmGlobalVisualStudioGenerator::VSVersion::VS17 ? "ARM64" : ""; - } else if (VSIsWow64()) { + } + if (VSIsWow64()) { return "x64"; - } else { + } #if defined(_M_ARM) - return ""; + return ""; #elif defined(_M_IA64) - return ""; + return ""; #elif defined(_WIN64) - return "x64"; + return "x64"; #else - return "x86"; + return "x86"; #endif - } } static unsigned int VSVersionToMajor( @@ -212,7 +212,7 @@ static const char* cmVS15GenName(const std::string& name, std::string& genName) { if (strncmp(name.c_str(), vs15generatorName, sizeof(vs15generatorName) - 6) != 0) { - return 0; + return nullptr; } const char* p = name.c_str() + sizeof(vs15generatorName) - 6; if (cmHasLiteralPrefix(p, " 2017")) { @@ -255,11 +255,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs15generatorName) + " [arch]"; - entry.Brief = "Generates Visual Studio 2017 project files. " - "Optional [arch] can be \"Win64\" or \"ARM\"."; + return { std::string(vs15generatorName) + " [arch]", + "Generates Visual Studio 2017 project files. " + "Optional [arch] can be \"Win64\" or \"ARM\"." }; } std::vector<std::string> GetGeneratorNames() const override @@ -307,7 +307,7 @@ static const char* cmVS16GenName(const std::string& name, std::string& genName) { if (strncmp(name.c_str(), vs16generatorName, sizeof(vs16generatorName) - 6) != 0) { - return 0; + return nullptr; } const char* p = name.c_str() + sizeof(vs16generatorName) - 6; if (cmHasLiteralPrefix(p, " 2019")) { @@ -321,7 +321,7 @@ static const char* cmVS17GenName(const std::string& name, std::string& genName) { if (strncmp(name.c_str(), vs17generatorName, sizeof(vs17generatorName) - 6) != 0) { - return 0; + return nullptr; } const char* p = name.c_str() + sizeof(vs17generatorName) - 6; if (cmHasLiteralPrefix(p, " 2022")) { @@ -351,11 +351,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs16generatorName); - entry.Brief = "Generates Visual Studio 2019 project files. " - "Use -A option to specify architecture."; + return { std::string(vs16generatorName), + "Generates Visual Studio 2019 project files. " + "Use -A option to specify architecture." }; } std::vector<std::string> GetGeneratorNames() const override @@ -416,11 +416,11 @@ public: return std::unique_ptr<cmGlobalGenerator>(); } - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - entry.Name = std::string(vs17generatorName); - entry.Brief = "Generates Visual Studio 2022 project files. " - "Use -A option to specify architecture."; + return { std::string(vs17generatorName), + "Generates Visual Studio 2022 project files. " + "Use -A option to specify architecture." }; } std::vector<std::string> GetGeneratorNames() const override @@ -521,6 +521,7 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance( { if (this->LastGeneratorInstanceString && i == *(this->LastGeneratorInstanceString)) { + this->SetVSVersionVar(mf); return true; } @@ -531,7 +532,7 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance( if (!this->GeneratorInstanceVersion.empty()) { std::string const majorStr = VSVersionToMajorString(this->Version); cmsys::RegularExpression versionRegex( - cmStrCat("^", majorStr, "\\.[0-9]+\\.[0-9]+\\.[0-9]+$")); + cmStrCat("^", majorStr, R"(\.[0-9]+\.[0-9]+\.[0-9]+$)")); if (!versionRegex.find(this->GeneratorInstanceVersion)) { std::ostringstream e; /* clang-format off */ @@ -592,6 +593,8 @@ bool cmGlobalVisualStudioVersionedGenerator::SetGeneratorInstance( cmStateEnums::INTERNAL); } + this->SetVSVersionVar(mf); + // The selected instance may have a different MSBuild than previously found. this->MSBuildCommandInitialized = false; @@ -607,7 +610,7 @@ bool cmGlobalVisualStudioVersionedGenerator::ParseGeneratorInstance( this->GeneratorInstanceVersion.clear(); std::vector<std::string> const fields = cmTokenize(is, ","); - std::vector<std::string>::const_iterator fi = fields.begin(); + auto fi = fields.begin(); if (fi == fields.end()) { return true; } @@ -672,6 +675,13 @@ bool cmGlobalVisualStudioVersionedGenerator::ParseGeneratorInstance( return true; } +void cmGlobalVisualStudioVersionedGenerator::SetVSVersionVar(cmMakefile* mf) +{ + if (cm::optional<std::string> vsVer = this->GetVSInstanceVersion()) { + mf->AddDefinition("CMAKE_VS_VERSION_BUILD_NUMBER", *vsVer); + } +} + bool cmGlobalVisualStudioVersionedGenerator::ProcessGeneratorInstanceField( std::string const& key, std::string const& value) { @@ -901,9 +911,8 @@ bool cmGlobalVisualStudioVersionedGenerator::SelectWindowsStoreToolset( this->IsWindowsDesktopToolsetInstalled()) { toolset = VSVersionToToolset(this->Version); return true; - } else { - return false; } + return false; } return this->cmGlobalVisualStudio14Generator::SelectWindowsStoreToolset( toolset); diff --git a/Source/cmGlobalVisualStudioVersionedGenerator.h b/Source/cmGlobalVisualStudioVersionedGenerator.h index 2e573ec..45aca74 100644 --- a/Source/cmGlobalVisualStudioVersionedGenerator.h +++ b/Source/cmGlobalVisualStudioVersionedGenerator.h @@ -46,6 +46,16 @@ public: const char* GetAndroidApplicationTypeRevision() const override; + bool CheckCxxModuleSupport() override + { + this->CxxModuleSupportCheck(); + return this->SupportsCxxModuleDyndep(); + } + bool SupportsCxxModuleDyndep() const override + { + return this->Version >= cmGlobalVisualStudioGenerator::VSVersion::VS17; + } + protected: cmGlobalVisualStudioVersionedGenerator( VSVersion version, cmake* cm, const std::string& name, @@ -83,6 +93,7 @@ private: mutable cmVSSetupAPIHelper vsSetupAPIHelper; bool ParseGeneratorInstance(std::string const& is, cmMakefile* mf); + void SetVSVersionVar(cmMakefile* mf); std::string GeneratorInstance; std::string GeneratorInstanceVersion; diff --git a/Source/cmGlobalWatcomWMakeGenerator.cxx b/Source/cmGlobalWatcomWMakeGenerator.cxx index fb2a8b6..ed44e6b 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.cxx +++ b/Source/cmGlobalWatcomWMakeGenerator.cxx @@ -4,7 +4,6 @@ #include <ostream> -#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmState.h" @@ -54,11 +53,10 @@ bool cmGlobalWatcomWMakeGenerator::SetSystemName(std::string const& s, return this->cmGlobalUnixMakefileGenerator3::SetSystemName(s, mf); } -void cmGlobalWatcomWMakeGenerator::GetDocumentation( - cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalWatcomWMakeGenerator::GetDocumentation() { - entry.Name = cmGlobalWatcomWMakeGenerator::GetActualName(); - entry.Brief = "Generates Watcom WMake makefiles."; + return { cmGlobalWatcomWMakeGenerator::GetActualName(), + "Generates Watcom WMake makefiles." }; } std::vector<cmGlobalGenerator::GeneratedMakeCommand> diff --git a/Source/cmGlobalWatcomWMakeGenerator.h b/Source/cmGlobalWatcomWMakeGenerator.h index eb93934..5579120 100644 --- a/Source/cmGlobalWatcomWMakeGenerator.h +++ b/Source/cmGlobalWatcomWMakeGenerator.h @@ -15,7 +15,6 @@ class cmMakefile; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalWatcomWMakeGenerator * \brief Write a NMake makefiles. @@ -39,7 +38,7 @@ public: static std::string GetActualName() { return "Watcom WMake"; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); /** Tell the generator about the target system. */ bool SetSystemName(std::string const& s, cmMakefile* mf) override; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 116e510..f19dfd5 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -13,6 +13,7 @@ #include <utility> #include <cm/memory> +#include <cm/optional> #include <cmext/algorithm> #include <cmext/string_view> @@ -24,7 +25,6 @@ #include "cmCustomCommandGenerator.h" #include "cmCustomCommandLines.h" #include "cmCustomCommandTypes.h" -#include "cmDocumentationEntry.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" @@ -149,9 +149,9 @@ public: std::unique_ptr<cmGlobalGenerator> CreateGlobalGenerator( const std::string& name, bool allowArch, cmake* cm) const override; - void GetDocumentation(cmDocumentationEntry& entry) const override + cmDocumentationEntry GetDocumentation() const override { - cmGlobalXCodeGenerator::GetDocumentation(entry); + return cmGlobalXCodeGenerator::GetDocumentation(); } std::vector<std::string> GetGeneratorNames() const override @@ -2281,11 +2281,11 @@ void cmGlobalXCodeGenerator::CreateCustomRulesMakefile( } makefileStream << "\n"; - if (const char* comment = ccg.GetComment()) { + if (cm::optional<std::string> comment = ccg.GetComment()) { std::string echo_cmd = cmStrCat("echo ", (this->CurrentLocalGenerator->EscapeForShell( - comment, ccg.GetCC().GetEscapeAllowMakeVars()))); + *comment, ccg.GetCC().GetEscapeAllowMakeVars()))); makefileStream << "\t" << echo_cmd << "\n"; } @@ -3623,7 +3623,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) } // Add a pair of config and item to target-item map auto& itemVector = targetItemMap[libName]; - itemVector.emplace_back(ConfigItemPair(configName, &libItem)); + itemVector.emplace_back(configName, &libItem); // Add product file-name to a lib-product map auto productName = cmSystemTools::GetFilenameName(libItem.Value.Value); @@ -3962,7 +3962,7 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) void cmGlobalXCodeGenerator::AddEmbeddedObjects( cmXCodeObject* target, const std::string& copyFilesBuildPhaseName, const std::string& embedPropertyName, const std::string& dstSubfolderSpec, - int actionsOnByDefault) + int actionsOnByDefault, const std::string& defaultDstPath) { cmGeneratorTarget* gt = target->GetTarget(); if (!gt) { @@ -3998,7 +3998,8 @@ void cmGlobalXCodeGenerator::AddEmbeddedObjects( copyFilesBuildPhase->AddAttribute("dstPath", this->CreateString(*fwEmbedPath)); } else { - copyFilesBuildPhase->AddAttribute("dstPath", this->CreateString("")); + copyFilesBuildPhase->AddAttribute("dstPath", + this->CreateString(defaultDstPath)); } copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing", this->CreateString("0")); @@ -4124,6 +4125,17 @@ void cmGlobalXCodeGenerator::AddEmbeddedAppExtensions(cmXCodeObject* target) RemoveHeadersOnCopyByDefault); } +void cmGlobalXCodeGenerator::AddEmbeddedExtensionKitExtensions( + cmXCodeObject* target) +{ + static const auto dstSubfolderSpec = "16"; + + this->AddEmbeddedObjects(target, "Embed App Extensions", + "XCODE_EMBED_EXTENSIONKIT_EXTENSIONS", + dstSubfolderSpec, RemoveHeadersOnCopyByDefault, + "$(EXTENSIONS_FOLDER_PATH)"); +} + bool cmGlobalXCodeGenerator::CreateGroups( std::vector<cmLocalGenerator*>& generators) { @@ -4369,7 +4381,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( cmXCodeObject* config = this->CreateObject(cmXCodeObject::XCBuildConfiguration); config->AddAttribute("name", this->CreateString(name)); - configs.push_back(std::make_pair(name, config)); + configs.emplace_back(name, config); } if (defaultConfigName.empty()) { defaultConfigName = "Debug"; @@ -4444,12 +4456,20 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( buildSettings->AddAttribute("CODE_SIGNING_ALLOWED", this->CreateString("NO")); } + auto debugConfigs = this->GetCMakeInstance()->GetDebugConfigs(); + std::set<std::string> debugConfigSet(debugConfigs.begin(), + debugConfigs.end()); for (auto& config : configs) { CreateGlobalXCConfigSettings(root, config.second, config.first); cmXCodeObject* buildSettingsForCfg = this->CreateFlatClone(buildSettings); + if (debugConfigSet.count(cmSystemTools::UpperCase(config.first)) == 0) { + buildSettingsForCfg->AddAttribute("SWIFT_COMPILATION_MODE", + this->CreateString("wholemodule")); + } + // Put this last so it can override existing settings // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly. for (const auto& var : this->CurrentMakefile->GetDefinitions()) { @@ -4507,6 +4527,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( this->AddEmbeddedFrameworks(t); this->AddEmbeddedPlugIns(t); this->AddEmbeddedAppExtensions(t); + this->AddEmbeddedExtensionKitExtensions(t); // Inherit project-wide values for any target-specific search paths. this->InheritBuildSettingAttribute(t, "HEADER_SEARCH_PATHS"); this->InheritBuildSettingAttribute(t, "SYSTEM_HEADER_SEARCH_PATHS"); @@ -4888,10 +4909,10 @@ std::string cmGlobalXCodeGenerator::ExpandCFGIntDir( return tmp; } -void cmGlobalXCodeGenerator::GetDocumentation(cmDocumentationEntry& entry) +cmDocumentationEntry cmGlobalXCodeGenerator::GetDocumentation() { - entry.Name = cmGlobalXCodeGenerator::GetActualName(); - entry.Brief = "Generate Xcode project files."; + return { cmGlobalXCodeGenerator::GetActualName(), + "Generate Xcode project files." }; } std::string cmGlobalXCodeGenerator::ConvertToRelativeForMake( @@ -4974,7 +4995,13 @@ void cmGlobalXCodeGenerator::AppendDefines( std::string def; for (auto const& define : defines) { // Start with -D if requested. - def = cmStrCat(dflag ? "-D" : "", define); + if (dflag && !cmHasLiteralPrefix(define, "-D")) { + def = cmStrCat("-D", define); + } else if (!dflag && cmHasLiteralPrefix(define, "-D")) { + def = define.substr(2); + } else { + def = define; + } // Append the flag with needed escapes. std::string tmp; diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 9ae75fb..1fdd189 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -14,6 +14,7 @@ #include <cm/optional> #include <cm/string_view> +#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmTransformDepfile.h" #include "cmValue.h" @@ -28,7 +29,6 @@ class cmMakefile; class cmSourceFile; class cmSourceGroup; class cmake; -struct cmDocumentationEntry; /** \class cmGlobalXCodeGenerator * \brief Write a Unix makefiles. @@ -54,7 +54,7 @@ public: static std::string GetActualName() { return "Xcode"; } /** Get the documentation entry for this generator. */ - static void GetDocumentation(cmDocumentationEntry& entry); + static cmDocumentationEntry GetDocumentation(); //! Create a local generator appropriate to this Global Generator std::unique_ptr<cmLocalGenerator> CreateLocalGenerator( @@ -218,10 +218,12 @@ private: const std::string& copyFilesBuildPhaseName, const std::string& embedPropertyName, const std::string& dstSubfolderSpec, - int actionsOnByDefault); + int actionsOnByDefault, + const std::string& defaultDstPath = ""); void AddEmbeddedFrameworks(cmXCodeObject* target); void AddEmbeddedPlugIns(cmXCodeObject* target); void AddEmbeddedAppExtensions(cmXCodeObject* target); + void AddEmbeddedExtensionKitExtensions(cmXCodeObject* target); void AddPositionIndependentLinkAttribute(cmGeneratorTarget* target, cmXCodeObject* buildSettings, const std::string& configName); diff --git a/Source/cmIDEOptions.cxx b/Source/cmIDEOptions.cxx index c09aa46..9468d4a 100644 --- a/Source/cmIDEOptions.cxx +++ b/Source/cmIDEOptions.cxx @@ -20,15 +20,13 @@ cmIDEOptions::cmIDEOptions() this->AllowDefine = true; this->DoingInclude = false; this->AllowSlash = false; - this->DoingFollowing = 0; - for (int i = 0; i < FlagTableCount; ++i) { - this->FlagTable[i] = 0; + this->DoingFollowing = nullptr; + for (auto& flag : this->FlagTable) { + flag = nullptr; } } -cmIDEOptions::~cmIDEOptions() -{ -} +cmIDEOptions::~cmIDEOptions() = default; void cmIDEOptions::HandleFlag(std::string const& flag) { @@ -49,7 +47,7 @@ void cmIDEOptions::HandleFlag(std::string const& flag) // If the last option expected a following value, this is it. if (this->DoingFollowing) { this->FlagMapUpdate(this->DoingFollowing, flag); - this->DoingFollowing = 0; + this->DoingFollowing = nullptr; return; } @@ -248,8 +246,7 @@ bool cmIDEOptions::HasFlag(std::string const& flag) const const char* cmIDEOptions::GetFlag(std::string const& flag) const { // This method works only for single-valued flags! - std::map<std::string, FlagValue>::const_iterator i = - this->FlagMap.find(flag); + auto i = this->FlagMap.find(flag); if (i != this->FlagMap.cend() && i->second.size() == 1) { return i->second[0].c_str(); } diff --git a/Source/cmInstalledFile.cxx b/Source/cmInstalledFile.cxx index 0974eea..5bf8320 100644 --- a/Source/cmInstalledFile.cxx +++ b/Source/cmInstalledFile.cxx @@ -21,7 +21,7 @@ cmInstalledFile::Property::~Property() = default; void cmInstalledFile::SetName(cmMakefile* mf, const std::string& name) { cmListFileBacktrace backtrace = mf->GetBacktrace(); - cmGeneratorExpression ge(backtrace); + cmGeneratorExpression ge(*mf->GetCMakeInstance(), backtrace); this->Name = name; this->NameExpression = ge.Parse(name); @@ -56,7 +56,7 @@ void cmInstalledFile::AppendProperty(cmMakefile const* mf, bool /*asString*/) { cmListFileBacktrace backtrace = mf->GetBacktrace(); - cmGeneratorExpression ge(backtrace); + cmGeneratorExpression ge(*mf->GetCMakeInstance(), backtrace); Property& property = this->Properties[prop]; property.ValueExpressions.push_back(ge.Parse(value)); diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index b2b724a..cedb367 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1021,12 +1021,6 @@ void cmLocalGenerator::AddCompileOptions(std::vector<BT<std::string>>& flags, } } - std::string compReqFlag; - this->AddCompilerRequirementFlag(compReqFlag, target, lang, config); - if (!compReqFlag.empty()) { - flags.emplace_back(std::move(compReqFlag)); - } - // Add Warning as errors flags if (!this->GetCMakeInstance()->GetIgnoreWarningAsError()) { const cmValue wError = target->GetProperty("COMPILE_WARNING_AS_ERROR"); @@ -1932,6 +1926,30 @@ void cmLocalGenerator::AddLanguageFlags(std::string& flags, this->AddConfigVariableFlags(flags, cmStrCat("CMAKE_", lang, "_FLAGS"), config); + // Add the language standard flag for compiling, and sometimes linking. + if (compileOrLink == cmBuildStep::Compile || + (compileOrLink == cmBuildStep::Link && + // Some toolchains require use of the language standard flag + // when linking in order to use the matching standard library. + // FIXME: If CMake gains an abstraction for standard library + // selection, this will have to be reconciled with it. + this->Makefile->IsOn( + cmStrCat("CMAKE_", lang, "_LINK_WITH_STANDARD_COMPILE_OPTION")))) { + cmStandardLevelResolver standardResolver(this->Makefile); + std::string const& optionFlagDef = + standardResolver.GetCompileOptionDef(target, lang, config); + if (!optionFlagDef.empty()) { + cmValue opt = + target->Target->GetMakefile()->GetDefinition(optionFlagDef); + if (opt) { + std::vector<std::string> optVec = cmExpandedList(*opt); + for (std::string const& i : optVec) { + this->AppendFlagEscape(flags, i); + } + } + } + } + std::string compiler = this->Makefile->GetSafeDefinition( cmStrCat("CMAKE_", lang, "_COMPILER_ID")); @@ -2076,15 +2094,6 @@ void cmLocalGenerator::AddLanguageFlagsForLinking( std::string& flags, cmGeneratorTarget const* target, const std::string& lang, const std::string& config) { - if (this->Makefile->IsOn("CMAKE_" + lang + - "_LINK_WITH_STANDARD_COMPILE_OPTION")) { - // This toolchain requires use of the language standard flag - // when linking in order to use the matching standard library. - // FIXME: If CMake gains an abstraction for standard library - // selection, this will have to be reconciled with it. - this->AddCompilerRequirementFlag(flags, target, lang, config); - } - this->AddLanguageFlags(flags, target, cmBuildStep::Link, lang, config); if (target->IsIPOEnabled(lang, config)) { @@ -2224,25 +2233,6 @@ void cmLocalGenerator::AddSharedFlags(std::string& flags, } } -void cmLocalGenerator::AddCompilerRequirementFlag( - std::string& flags, cmGeneratorTarget const* target, const std::string& lang, - const std::string& config) -{ - cmStandardLevelResolver standardResolver(this->Makefile); - - std::string const& optionFlagDef = - standardResolver.GetCompileOptionDef(target, lang, config); - if (!optionFlagDef.empty()) { - cmValue opt = target->Target->GetMakefile()->GetDefinition(optionFlagDef); - if (opt) { - std::vector<std::string> optVec = cmExpandedList(*opt); - for (std::string const& i : optVec) { - this->AppendFlagEscape(flags, i); - } - } - } -} - static void AddVisibilityCompileOption(std::string& flags, cmGeneratorTarget const* target, cmLocalGenerator* lg, @@ -3387,7 +3377,12 @@ void cmLocalGenerator::AppendDefines( if (!this->CheckDefinition(d.Value)) { continue; } - defines.insert(d); + // remove any leading -D + if (cmHasLiteralPrefix(d.Value, "-D")) { + defines.emplace(d.Value.substr(2), d.Backtrace); + } else { + defines.insert(d); + } } } @@ -3484,8 +3479,8 @@ std::string cmLocalGenerator::ConstructComment( cmCustomCommandGenerator const& ccg, const char* default_comment) const { // Check for a comment provided with the command. - if (ccg.GetComment()) { - return ccg.GetComment(); + if (cm::optional<std::string> comment = ccg.GetComment()) { + return *comment; } // Construct a reasonable default comment if possible. @@ -4505,7 +4500,7 @@ std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputGenex( std::string const& o, cmListFileBacktrace const& bt) { std::vector<std::string> allConfigOutputs; - cmGeneratorExpression ge(bt); + cmGeneratorExpression ge(*this->GetCMakeInstance(), bt); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(o); std::vector<std::string> configs = this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 765441c..20f23de 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -164,10 +164,6 @@ public: const std::string& lang); void AddConfigVariableFlags(std::string& flags, const std::string& var, const std::string& config); - void AddCompilerRequirementFlag(std::string& flags, - cmGeneratorTarget const* target, - const std::string& lang, - const std::string& config); void AddColorDiagnosticsFlags(std::string& flags, const std::string& lang); //! Append flags to a string. virtual void AppendFlags(std::string& flags, diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index c11f5b4..1e2ea2a 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -701,7 +701,7 @@ bool cmLocalNinjaGenerator::HasUniqueByproducts( { std::vector<std::string> configs = this->GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); - cmGeneratorExpression ge(bt); + cmGeneratorExpression ge(*this->GetCMakeInstance(), bt); for (std::string const& p : byproducts) { if (cmGeneratorExpression::Find(p) == std::string::npos) { return false; diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index de1d3cd..7172d34 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -10,6 +10,7 @@ #include <utility> #include <cm/memory> +#include <cm/optional> #include <cm/string_view> #include <cm/vector> #include <cmext/algorithm> @@ -945,9 +946,8 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( // post-build command comments. Custom build step commands have // their comments generated elsewhere. if (echo_comment) { - const char* comment = ccg.GetComment(); - if (comment && *comment) { - this->AppendEcho(commands, comment, + if (cm::optional<std::string> comment = ccg.GetComment()) { + this->AppendEcho(commands, *comment, cmLocalUnixMakefileGenerator3::EchoGenerate); } } diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx index 4c0d2eea..8fe6677 100644 --- a/Source/cmLocalVisualStudio10Generator.cxx +++ b/Source/cmLocalVisualStudio10Generator.cxx @@ -18,8 +18,8 @@ class cmGeneratorTarget; class cmVS10XMLParser : public cmXMLParser { public: - virtual void EndElement(const std::string& /* name */) {} - virtual void CharacterDataHandler(const char* data, int length) + void EndElement(const std::string& /* name */) override {} + void CharacterDataHandler(const char* data, int length) override { if (this->DoGUID) { if (data[0] == '{') { @@ -31,7 +31,7 @@ public: this->DoGUID = false; } } - virtual void StartElement(const std::string& name, const char**) + void StartElement(const std::string& name, const char**) override { // once the GUID is found do nothing if (!this->GUID.empty()) { @@ -41,7 +41,7 @@ public: this->DoGUID = true; } } - int InitializeParser() + int InitializeParser() override { this->DoGUID = false; int ret = cmXMLParser::InitializeParser(); @@ -63,9 +63,7 @@ cmLocalVisualStudio10Generator::cmLocalVisualStudio10Generator( { } -cmLocalVisualStudio10Generator::~cmLocalVisualStudio10Generator() -{ -} +cmLocalVisualStudio10Generator::~cmLocalVisualStudio10Generator() = default; void cmLocalVisualStudio10Generator::GenerateTarget(cmGeneratorTarget* target) { diff --git a/Source/cmLocalVisualStudio10Generator.h b/Source/cmLocalVisualStudio10Generator.h index 7bfe3b7..fe44bb5 100644 --- a/Source/cmLocalVisualStudio10Generator.h +++ b/Source/cmLocalVisualStudio10Generator.h @@ -24,7 +24,7 @@ public: //! Set cache only and recurse to false by default. cmLocalVisualStudio10Generator(cmGlobalGenerator* gg, cmMakefile* mf); - virtual ~cmLocalVisualStudio10Generator(); + ~cmLocalVisualStudio10Generator() override; void ReadAndStoreExternalGUID(const std::string& name, const char* path) override; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index af2d31d..ded1647 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -10,6 +10,7 @@ #include <utility> #include <cm/memory> +#include <cm/optional> #include <cmext/algorithm> #include <windows.h> @@ -56,7 +57,7 @@ public: using ItemVector = cmComputeLinkInformation::ItemVector; void OutputLibraries(std::ostream& fout, ItemVector const& libs); void OutputObjects(std::ostream& fout, cmGeneratorTarget* t, - std::string const& config, const char* isep = 0); + std::string const& config, const char* isep = nullptr); private: cmLocalVisualStudio7Generator* LocalGenerator; @@ -107,8 +108,8 @@ void cmLocalVisualStudio7Generator::Generate() } auto& gtVisited = this->GetSourcesVisited(gt); - auto& deps = this->GlobalGenerator->GetTargetDirectDepends(gt); - for (auto& d : deps) { + auto const& deps = this->GlobalGenerator->GetTargetDirectDepends(gt); + for (auto const& d : deps) { // Take the union of visited source files of custom commands auto depVisited = this->GetSourcesVisited(d); gtVisited.insert(depVisited.begin(), depVisited.end()); @@ -126,7 +127,7 @@ void cmLocalVisualStudio7Generator::FixGlobalTargets() // commands for targets in which no sources are built. Add dummy // rules to force these targets to build. const auto& tgts = this->GetGeneratorTargets(); - for (auto& l : tgts) { + for (auto const& l : tgts) { if (l->GetType() == cmStateEnums::GLOBAL_TARGET) { cmCustomCommandLines force_commands = cmMakeSingleCommandLine({ "cd", "." }); @@ -178,8 +179,7 @@ void cmLocalVisualStudio7Generator::WriteStampFiles() // Sort the list of input files and remove duplicates. std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>()); - std::vector<std::string>::iterator new_end = - std::unique(listFiles.begin(), listFiles.end()); + auto new_end = std::unique(listFiles.begin(), listFiles.end()); listFiles.erase(new_end, listFiles.end()); for (const std::string& lf : listFiles) { @@ -216,7 +216,7 @@ void cmLocalVisualStudio7Generator::GenerateTarget(cmGeneratorTarget* target) // Generate the project file and replace it atomically with // copy-if-different. We use a separate timestamp so that the IDE // does not reload project files unnecessarily. - cmGeneratedFileStream fout(fname.c_str()); + cmGeneratedFileStream fout(fname); fout.SetCopyIfDifferent(true); this->WriteVCProjFile(fout, lname, target); if (fout.Close()) { @@ -252,8 +252,7 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() // Sort the list of input files and remove duplicates. std::sort(listFiles.begin(), listFiles.end(), std::less<std::string>()); - std::vector<std::string>::iterator new_end = - std::unique(listFiles.begin(), listFiles.end()); + auto new_end = std::unique(listFiles.begin(), listFiles.end()); listFiles.erase(new_end, listFiles.end()); std::string argS = cmStrCat("-S", this->GetSourceDirectory()); @@ -279,10 +278,9 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() // the generator validated all project-named sources. file->ResolveFullPath(); return file; - } else { - cmSystemTools::Error("Error adding rule for " + makefileIn); - return nullptr; } + cmSystemTools::Error("Error adding rule for " + makefileIn); + return nullptr; } void cmLocalVisualStudio7Generator::WriteConfigurations( @@ -558,12 +556,11 @@ cmVS7FlagTable cmLocalVisualStudio7GeneratorFortranLinkFlagTable[] = { class cmLocalVisualStudio7Generator::EventWriter { public: - EventWriter(cmLocalVisualStudio7Generator* lg, const std::string& config, + EventWriter(cmLocalVisualStudio7Generator* lg, std::string config, std::ostream& os) : LG(lg) - , Config(config) + , Config(std::move(config)) , Stream(os) - , First(true) { } void Start(const char* tool) @@ -592,9 +589,8 @@ public: { cmCustomCommandGenerator ccg(cc, this->Config, this->LG); if (this->First) { - const char* comment = ccg.GetComment(); - if (comment && *comment) { - this->Stream << "\nDescription=\"" << this->LG->EscapeForXML(comment) + if (cm::optional<std::string> comment = ccg.GetComment()) { + this->Stream << "\nDescription=\"" << this->LG->EscapeForXML(*comment) << "\""; } this->Stream << "\nCommandLine=\""; @@ -610,7 +606,7 @@ private: cmLocalVisualStudio7Generator* LG; std::string Config; std::ostream& Stream; - bool First; + bool First = true; }; void cmLocalVisualStudio7Generator::WriteConfiguration( @@ -634,7 +630,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( // 1 == executable // 10 == utility const char* configType = "10"; - const char* projectType = 0; + const char* projectType = nullptr; bool targetBuilds = true; switch (target->GetType()) { @@ -842,8 +838,26 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( } } fout << "/>\n"; // end of <Tool Name=VCCLCompilerTool + if (gg->IsMarmasmEnabled() && !this->FortranProject) { + Options marmasmOptions(this, Options::MarmasmCompiler, nullptr, nullptr); + /* clang-format off */ + fout << + "\t\t\t<Tool\n" + "\t\t\t\tName=\"MARMASM\"\n" + ; + /* clang-format on */ + targetOptions.OutputAdditionalIncludeDirectories(fout, 4, "ASM_MARMASM"); + // Use same preprocessor definitions as VCCLCompilerTool. + targetOptions.OutputPreprocessorDefinitions(fout, 4, "ASM_MARMASM"); + marmasmOptions.OutputFlagMap(fout, 4); + /* clang-format off */ + fout << + "\t\t\t\tObjectFile=\"$(IntDir)\\\"\n" + "\t\t\t/>\n"; + /* clang-format on */ + } if (gg->IsMasmEnabled() && !this->FortranProject) { - Options masmOptions(this, Options::MasmCompiler, 0, 0); + Options masmOptions(this, Options::MasmCompiler, nullptr, nullptr); /* clang-format off */ fout << "\t\t\t<Tool\n" @@ -939,7 +953,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( } std::string cmLocalVisualStudio7Generator::GetBuildTypeLinkerFlags( - std::string rootLinkerFlags, const std::string& configName) + std::string const& rootLinkerFlags, const std::string& configName) { std::string configTypeUpper = cmSystemTools::UpperCase(configName); std::string extraLinkOptionsBuildTypeDef = @@ -1421,8 +1435,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, fout << "\t<Files>\n"; // Loop through every source group. - for (unsigned int i = 0; i < sourceGroups.size(); ++i) { - cmSourceGroup sg = sourceGroups[i]; + for (auto const& sg : sourceGroups) { this->WriteGroup(&sg, target, fout, libName, configs, sources); } @@ -1616,10 +1629,9 @@ std::string cmLocalVisualStudio7Generator::ComputeLongestObjectDirectory( // Compute the maximum length configuration name. std::string config_max; - for (std::vector<std::string>::iterator i = configs.begin(); - i != configs.end(); ++i) { - if (i->size() > config_max.size()) { - config_max = *i; + for (auto& config : configs) { + if (config.size() > config_max.size()) { + config_max = config; } } @@ -1645,9 +1657,8 @@ bool cmLocalVisualStudio7Generator::WriteGroup( // Write the children to temporary output. bool hasChildrenWithSources = false; std::ostringstream tmpOut; - for (unsigned int i = 0; i < children.size(); ++i) { - if (this->WriteGroup(&children[i], target, tmpOut, libName, configs, - sources)) { + for (const auto& child : children) { + if (this->WriteGroup(&child, target, tmpOut, libName, configs, sources)) { hasChildrenWithSources = true; } } @@ -1673,8 +1684,7 @@ bool cmLocalVisualStudio7Generator::WriteGroup( target->GetType() == cmStateEnums::GLOBAL_TARGET || target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { // Look up the source kind and configs. - std::map<cmSourceFile const*, size_t>::const_iterator map_it = - sources.Index.find(sf); + auto map_it = sources.Index.find(sf); // The map entry must exist because we populated it earlier. assert(map_it != sources.Index.end()); cmGeneratorTarget::AllConfigSource const& acs = @@ -1720,6 +1730,10 @@ bool cmLocalVisualStudio7Generator::WriteGroup( aCompilerTool = "VFCustomBuildTool"; } } + if (gg->IsMarmasmEnabled() && !this->FortranProject && + lang == "ASM_MARMASM") { + aCompilerTool = "MARMASM"; + } if (gg->IsMasmEnabled() && !this->FortranProject && lang == "ASM_MASM") { aCompilerTool = "MASM"; @@ -1921,7 +1935,7 @@ void cmLocalVisualStudio7Generator::OutputTargetRules( } std::unique_ptr<cmCustomCommand> pcc( this->MaybeCreateImplibDir(target, configName, this->FortranProject)); - if (pcc.get()) { + if (pcc) { event.Write(*pcc); } event.Finish(); @@ -1964,7 +1978,7 @@ void cmLocalVisualStudio7Generator::WriteProjectStartFortran( cmGlobalVisualStudio7Generator* gg = static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator); /* clang-format off */ - fout << "<?xml version=\"1.0\" encoding = \"" + fout << R"(<?xml version="1.0" encoding = ")" << gg->Encoding() << "\"?>\n" << "<VisualStudioProject\n" << "\tProjectCreator=\"Intel Fortran\"\n" @@ -1972,7 +1986,7 @@ void cmLocalVisualStudio7Generator::WriteProjectStartFortran( /* clang-format on */ cmValue p = target->GetProperty("VS_KEYWORD"); const char* keyword = p ? p->c_str() : "Console Application"; - const char* projectType = 0; + const char* projectType = nullptr; switch (target->GetType()) { case cmStateEnums::OBJECT_LIBRARY: case cmStateEnums::STATIC_LIBRARY: @@ -1992,7 +2006,7 @@ void cmLocalVisualStudio7Generator::WriteProjectStartFortran( if (!keyword) { keyword = "Console Application"; } - projectType = 0; + projectType = nullptr; break; case cmStateEnums::UTILITY: case cmStateEnums::GLOBAL_TARGET: @@ -2026,7 +2040,7 @@ void cmLocalVisualStudio7Generator::WriteProjectStart( static_cast<cmGlobalVisualStudio7Generator*>(this->GlobalGenerator); /* clang-format off */ - fout << "<?xml version=\"1.0\" encoding = \"" + fout << R"(<?xml version="1.0" encoding = ")" << gg->Encoding() << "\"?>\n" << "<VisualStudioProject\n" << "\tProjectType=\"Visual C++\"\n"; @@ -2050,6 +2064,17 @@ void cmLocalVisualStudio7Generator::WriteProjectStart( << "\t\t<Platform\n\t\t\tName=\"" << gg->GetPlatformName() << "\"/>\n" << "\t</Platforms>\n"; /* clang-format on */ + if (gg->IsMarmasmEnabled()) { + /* clang-format off */ + fout << + "\t<ToolFiles>\n" + "\t\t<DefaultToolFile\n" + "\t\t\tFileName=\"marmasm.rules\"\n" + "\t\t/>\n" + "\t</ToolFiles>\n" + ; + /* clang-format on */ + } if (gg->IsMasmEnabled()) { /* clang-format off */ fout << @@ -2133,8 +2158,8 @@ void cmVS7GeneratorOptions::OutputFlag(std::ostream& fout, int indent, class cmVS7XMLParser : public cmXMLParser { public: - virtual void EndElement(const std::string& /* name */) {} - virtual void StartElement(const std::string& name, const char** atts) + void EndElement(const std::string& /* name */) override {} + void StartElement(const std::string& name, const char** atts) override { // once the GUID is found do nothing if (!this->GUID.empty()) { @@ -2159,7 +2184,7 @@ public: } } } - int InitializeParser() + int InitializeParser() override { int ret = cmXMLParser::InitializeParser(); if (ret == 0) { @@ -2202,7 +2227,7 @@ static bool cmLVS7G_IsFAT(const char* dir) volRoot[0] = dir[0]; char fsName[16]; if (GetVolumeInformationA(volRoot, 0, 0, 0, 0, 0, fsName, 16) && - strstr(fsName, "FAT") != 0) { + strstr(fsName, "FAT") != nullptr) { return true; } } diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index d95ebc2..ce1156f 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -48,7 +48,7 @@ public: //! Set cache only and recurse to false by default. cmLocalVisualStudio7Generator(cmGlobalGenerator* gg, cmMakefile* mf); - virtual ~cmLocalVisualStudio7Generator(); + ~cmLocalVisualStudio7Generator() override; cmLocalVisualStudio7Generator(const cmLocalVisualStudio7Generator&) = delete; const cmLocalVisualStudio7Generator& operator=( @@ -97,7 +97,7 @@ protected: private: using Options = cmVS7GeneratorOptions; using FCInfo = cmLocalVisualStudio7GeneratorFCInfo; - std::string GetBuildTypeLinkerFlags(std::string rootLinkerFlags, + std::string GetBuildTypeLinkerFlags(std::string const& rootLinkerFlags, const std::string& configName); void FixGlobalTargets(); void WriteVCProjHeader(std::ostream& fout, const std::string& libName, diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index 2703c7b..58d46f1 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -4,6 +4,8 @@ #include <utility> +#include <cm/memory> + #include "windows.h" #include "cmCustomCommand.h" @@ -24,9 +26,7 @@ cmLocalVisualStudioGenerator::cmLocalVisualStudioGenerator( { } -cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator() -{ -} +cmLocalVisualStudioGenerator::~cmLocalVisualStudioGenerator() = default; cmGlobalVisualStudioGenerator::VSVersion cmLocalVisualStudioGenerator::GetVersion() const @@ -107,7 +107,7 @@ cmLocalVisualStudioGenerator::MaybeCreateImplibDir(cmGeneratorTarget* target, // Add a pre-build event to create the directory. cmCustomCommandLines commands = cmMakeSingleCommandLine( { cmSystemTools::GetCMakeCommand(), "-E", "make_directory", impDir }); - pcc.reset(new cmCustomCommand()); + pcc = cm::make_unique<cmCustomCommand>(); pcc->SetCommandLines(commands); pcc->SetStdPipesUTF8(true); pcc->SetEscapeOldStyle(false); diff --git a/Source/cmLocalVisualStudioGenerator.h b/Source/cmLocalVisualStudioGenerator.h index cf4f4d9..8fed1bd 100644 --- a/Source/cmLocalVisualStudioGenerator.h +++ b/Source/cmLocalVisualStudioGenerator.h @@ -29,7 +29,7 @@ class cmLocalVisualStudioGenerator : public cmLocalGenerator { public: cmLocalVisualStudioGenerator(cmGlobalGenerator* gg, cmMakefile* mf); - virtual ~cmLocalVisualStudioGenerator(); + ~cmLocalVisualStudioGenerator() override; std::string ConstructScript(cmCustomCommandGenerator const& ccg, const std::string& newline = "\n"); @@ -47,7 +47,7 @@ public: void ComputeObjectFilenames( std::map<cmSourceFile const*, std::string>& mapping, - cmGeneratorTarget const* = 0) override; + cmGeneratorTarget const* = nullptr) override; protected: virtual const char* ReportErrorLabel() const; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 6e0d704..db8f785 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -375,19 +375,28 @@ public: ++this->Makefile->RecursionDepth; this->Makefile->ExecutionStatusStack.push_back(&status); #if !defined(CMAKE_BOOTSTRAP) - if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) { - this->Makefile->GetCMakeInstance()->GetProfilingOutput().StartEntry(lff, - lfc); - } + this->ProfilingDataRAII = + this->Makefile->GetCMakeInstance()->CreateProfilingEntry( + "script", lff.LowerCaseName(), [&lff, &lfc]() -> Json::Value { + Json::Value argsValue = Json::objectValue; + if (!lff.Arguments().empty()) { + std::string args; + for (auto const& a : lff.Arguments()) { + args = cmStrCat(args, args.empty() ? "" : " ", a.Value); + } + argsValue["functionArgs"] = args; + } + argsValue["location"] = + cmStrCat(lfc.FilePath, ':', std::to_string(lfc.Line)); + return argsValue; + }); #endif } ~cmMakefileCall() { #if !defined(CMAKE_BOOTSTRAP) - if (this->Makefile->GetCMakeInstance()->IsProfilingEnabled()) { - this->Makefile->GetCMakeInstance()->GetProfilingOutput().StopEntry(); - } + this->ProfilingDataRAII.reset(); #endif this->Makefile->ExecutionStatusStack.pop_back(); --this->Makefile->RecursionDepth; @@ -399,6 +408,9 @@ public: private: cmMakefile* Makefile; +#if !defined(CMAKE_BOOTSTRAP) + cm::optional<cmMakefileProfilingData::RAII> ProfilingDataRAII; +#endif }; void cmMakefile::OnExecuteCommand(std::function<void()> callback) @@ -3584,6 +3596,9 @@ int cmMakefile::TryCompile(const std::string& srcdir, gg->RecursionDepth = this->RecursionDepth; cm.SetGlobalGenerator(std::move(gg)); + // copy trace state + cm.SetTraceRedirect(this->GetCMakeInstance()); + // do a configure cm.SetHomeDirectory(srcdir); cm.SetHomeOutputDirectory(bindir); @@ -4470,12 +4485,12 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, } // Deprecate old policies. - if (status == cmPolicies::OLD && id <= cmPolicies::CMP0102 && + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0108 && !(this->GetCMakeInstance()->GetIsInTryCompile() && ( // Policies set by cmCoreTryCompile::TryCompileCode. id == cmPolicies::CMP0065 || id == cmPolicies::CMP0083 || - id == cmPolicies::CMP0091)) && + id == cmPolicies::CMP0091 || id == cmPolicies::CMP0104)) && (!this->IsSet("CMAKE_WARN_DEPRECATED") || this->IsOn("CMAKE_WARN_DEPRECATED"))) { this->IssueMessage(MessageType::DEPRECATION_WARNING, diff --git a/Source/cmMakefileProfilingData.cxx b/Source/cmMakefileProfilingData.cxx index 1cd97c9..e903ae1 100644 --- a/Source/cmMakefileProfilingData.cxx +++ b/Source/cmMakefileProfilingData.cxx @@ -4,7 +4,8 @@ #include <chrono> #include <stdexcept> -#include <vector> +#include <type_traits> +#include <utility> #include <cm3p/json/value.h> #include <cm3p/json/writer.h> @@ -12,7 +13,6 @@ #include "cmsys/FStream.hxx" #include "cmsys/SystemInformation.hxx" -#include "cmListFileCache.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" @@ -43,8 +43,9 @@ cmMakefileProfilingData::~cmMakefileProfilingData() noexcept } } -void cmMakefileProfilingData::StartEntry(const cmListFileFunction& lff, - cmListFileContext const& lfc) +void cmMakefileProfilingData::StartEntry(const std::string& category, + const std::string& name, + cm::optional<Json::Value> args) { /* Do not try again if we previously failed to write to output. */ if (!this->ProfileStream.good()) { @@ -58,24 +59,17 @@ void cmMakefileProfilingData::StartEntry(const cmListFileFunction& lff, cmsys::SystemInformation info; Json::Value v; v["ph"] = "B"; - v["name"] = lff.LowerCaseName(); - v["cat"] = "cmake"; + v["name"] = name; + v["cat"] = category; v["ts"] = static_cast<Json::Value::UInt64>( std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::steady_clock::now().time_since_epoch()) .count()); v["pid"] = static_cast<int>(info.GetProcessId()); v["tid"] = 0; - Json::Value argsValue; - if (!lff.Arguments().empty()) { - std::string args; - for (auto const& a : lff.Arguments()) { - args += (args.empty() ? "" : " ") + a.Value; - } - argsValue["functionArgs"] = args; + if (args) { + v["args"] = *std::move(args); } - argsValue["location"] = lfc.FilePath + ":" + std::to_string(lfc.Line); - v["args"] = argsValue; this->JsonWriter->write(v, &this->ProfileStream); } catch (std::ios_base::failure& fail) { @@ -112,3 +106,36 @@ void cmMakefileProfilingData::StopEntry() cmSystemTools::Error("Error writing profiling output!"); } } + +cmMakefileProfilingData::RAII::RAII(cmMakefileProfilingData& data, + const std::string& category, + const std::string& name, + cm::optional<Json::Value> args) + : Data(&data) +{ + this->Data->StartEntry(category, name, std::move(args)); +} + +cmMakefileProfilingData::RAII::RAII(RAII&& other) noexcept + : Data(other.Data) +{ + other.Data = nullptr; +} + +cmMakefileProfilingData::RAII::~RAII() +{ + if (this->Data) { + this->Data->StopEntry(); + } +} + +cmMakefileProfilingData::RAII& cmMakefileProfilingData::RAII::operator=( + RAII&& other) noexcept +{ + if (this->Data) { + this->Data->StopEntry(); + } + this->Data = other.Data; + other.Data = nullptr; + return *this; +} diff --git a/Source/cmMakefileProfilingData.h b/Source/cmMakefileProfilingData.h index a86764a..4cf0bfa 100644 --- a/Source/cmMakefileProfilingData.h +++ b/Source/cmMakefileProfilingData.h @@ -4,23 +4,45 @@ #include <memory> #include <string> +#include <cm/optional> + +#include <cm3p/json/value.h> // IWYU pragma: keep + #include "cmsys/FStream.hxx" namespace Json { class StreamWriter; } -class cmListFileContext; -class cmListFileFunction; - class cmMakefileProfilingData { public: cmMakefileProfilingData(const std::string&); ~cmMakefileProfilingData() noexcept; - void StartEntry(const cmListFileFunction& lff, cmListFileContext const& lfc); + void StartEntry(const std::string& category, const std::string& name, + cm::optional<Json::Value> args = cm::nullopt); void StopEntry(); + class RAII + { + public: + RAII() = delete; + RAII(const RAII&) = delete; + RAII(RAII&&) noexcept; + + RAII(cmMakefileProfilingData& data, const std::string& category, + const std::string& name, + cm::optional<Json::Value> args = cm::nullopt); + + ~RAII(); + + RAII& operator=(const RAII&) = delete; + RAII& operator=(RAII&&) noexcept; + + private: + cmMakefileProfilingData* Data = nullptr; + }; + private: cmsys::ofstream ProfileStream; std::unique_ptr<Json::StreamWriter> JsonWriter; diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index d19bbb9..20cc2c3 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -25,6 +25,7 @@ #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" +#include "cmGlobalCommonGenerator.h" #include "cmGlobalUnixMakefileGenerator3.h" #include "cmLinkLineComputer.h" // IWYU pragma: keep #include "cmLocalCommonGenerator.h" @@ -1031,7 +1032,7 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( } this->GlobalGenerator->AddCXXCompileCommand( - source.GetFullPath(), workingDirectory, compileCommand); + source.GetFullPath(), workingDirectory, compileCommand, relativeObj); } // See if we need to use a compiler launcher like ccache or distcc @@ -1107,8 +1108,29 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( } else { driverMode = lang == "C" ? "gcc" : "g++"; } + std::string d = + this->GeneratorTarget->GetClangTidyExportFixesDirectory(lang); + std::string exportFixes; + if (!d.empty()) { + this->GlobalCommonGenerator->AddClangTidyExportFixesDir(d); + std::string fixesFile = cmSystemTools::CollapseFullPath(cmStrCat( + d, '/', + this->LocalGenerator->MaybeRelativeToTopBinDir(cmStrCat( + this->LocalGenerator->GetCurrentBinaryDirectory(), '/', + this->LocalGenerator->GetTargetDirectory( + this->GeneratorTarget), + '/', objectName, ".yaml")))); + this->GlobalCommonGenerator->AddClangTidyExportFixesFile( + fixesFile); + cmSystemTools::MakeDirectory( + cmSystemTools::GetFilenamePath(fixesFile)); + fixesFile = + this->LocalGenerator->MaybeRelativeToCurBinDir(fixesFile); + exportFixes = cmStrCat(";--export-fixes=", fixesFile); + } run_iwyu += this->LocalGenerator->EscapeForShell( - cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode)); + cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode, + exportFixes)); } if (cmNonempty(cpplint)) { run_iwyu += " --cpplint="; @@ -2249,6 +2271,7 @@ void cmMakefileTargetGenerator::CreateObjectLists( std::string responseFileName = (responseMode == Link) ? "objects" : "deviceObjects"; responseFileName += std::to_string(i + 1); + responseFileName += ".rsp"; // Create this response file. std::string objects_rsp = this->CreateResponseFile( diff --git a/Source/cmMessenger.cxx b/Source/cmMessenger.cxx index 333003b..ff513be 100644 --- a/Source/cmMessenger.cxx +++ b/Source/cmMessenger.cxx @@ -107,8 +107,8 @@ static void printMessageText(std::ostream& msg, std::string const& text) { msg << ":\n"; cmDocumentationFormatter formatter; - formatter.SetIndent(" "); - formatter.PrintFormatted(msg, text.c_str()); + formatter.SetIndent(2u); + formatter.PrintFormatted(msg, text); } static void displayMessage(MessageType t, std::ostringstream& msg) diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index bda8a5f..6ec1781 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -64,9 +64,9 @@ void cmNinjaNormalTargetGenerator::Generate(const std::string& config) { std::string lang = this->GeneratorTarget->GetLinkerLanguage(config); if (this->TargetLinkLanguage(config).empty()) { - cmSystemTools::Error("CMake can not determine linker language for " - "target: " + - this->GetGeneratorTarget()->GetName()); + cmSystemTools::Error( + cmStrCat("CMake can not determine linker language for target: ", + this->GetGeneratorTarget()->GetName())); return; } @@ -117,7 +117,7 @@ void cmNinjaNormalTargetGenerator::WriteLanguagesRules( #ifdef NINJA_GEN_VERBOSE_FILES cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream()); this->GetRulesFileStream() - << "# Rules for each languages for " + << "# Rules for each language for " << cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) << " target " << this->GetTargetName() << "\n\n"; #endif @@ -372,7 +372,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile, vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME"; vars.SwiftModule = "$SWIFT_MODULE"; vars.SwiftModuleName = "$SWIFT_MODULE_NAME"; - vars.SwiftOutputFileMap = "$SWIFT_OUTPUT_FILE_MAP"; vars.SwiftSources = "$SWIFT_SOURCES"; vars.Defines = "$DEFINES"; @@ -1072,12 +1071,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( cmOutputConverter::SHELL); }(vars["SWIFT_MODULE_NAME"]); - const std::string map = cmStrCat(gt->GetSupportDirectory(), '/', config, - '/', "output-file-map.json"); - vars["SWIFT_OUTPUT_FILE_MAP"] = - this->GetLocalGenerator()->ConvertToOutputFormat( - this->ConvertToNinjaPath(map), cmOutputConverter::SHELL); - vars["SWIFT_SOURCES"] = [this, config]() -> std::string { std::vector<cmSourceFile const*> sources; std::stringstream oss; @@ -1101,6 +1094,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( vars["DEFINES"] = this->GetDefines("Swift", config); vars["FLAGS"] = this->GetFlags("Swift", config); vars["INCLUDES"] = this->GetIncludes("Swift", config); + this->GenerateSwiftOutputFileMap(config, vars["FLAGS"]); } // Compute specific libraries to link with. @@ -1118,7 +1112,9 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement( this->GetObjectFilePath(source, config)); } } - linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]); + if (targetType != cmStateEnums::EXECUTABLE) { + linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]); + } } else { linkBuild.ExplicitDeps = this->GetObjects(config); } diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index e4427f5..6887376 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -4,6 +4,7 @@ #include <algorithm> #include <cassert> +#include <functional> #include <iterator> #include <map> #include <ostream> @@ -21,17 +22,13 @@ #include "cmComputeLinkInformation.h" #include "cmCustomCommandGenerator.h" -#include "cmExportBuildFileGenerator.h" -#include "cmExportSet.h" +#include "cmDyndepCollation.h" #include "cmFileSet.h" #include "cmGeneratedFileStream.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" +#include "cmGlobalCommonGenerator.h" #include "cmGlobalNinjaGenerator.h" -#include "cmInstallCxxModuleBmiGenerator.h" -#include "cmInstallExportGenerator.h" -#include "cmInstallFileSetGenerator.h" -#include "cmInstallGenerator.h" #include "cmLocalGenerator.h" #include "cmLocalNinjaGenerator.h" #include "cmMakefile.h" @@ -47,7 +44,6 @@ #include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" -#include "cmTargetExport.h" #include "cmValue.h" #include "cmake.h" @@ -109,12 +105,13 @@ cmGlobalNinjaGenerator* cmNinjaTargetGenerator::GetGlobalGenerator() const } std::string cmNinjaTargetGenerator::LanguageCompilerRule( - const std::string& lang, const std::string& config) const + const std::string& lang, const std::string& config, + WithScanning withScanning) const { return cmStrCat( lang, "_COMPILER__", cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()), - '_', config); + withScanning == WithScanning::Yes ? "_scanned_" : "_unscanned_", config); } std::string cmNinjaTargetGenerator::LanguagePreprocessAndScanRule( @@ -156,23 +153,6 @@ std::string cmNinjaTargetGenerator::LanguageDyndepRule( '_', config); } -bool cmNinjaTargetGenerator::NeedCxxModuleSupport( - std::string const& lang, std::string const& config) const -{ - if (lang != "CXX"_s) { - return false; - } - return this->GetGeneratorTarget()->HaveCxxModuleSupport(config) == - cmGeneratorTarget::Cxx20SupportLevel::Supported && - this->GetGlobalGenerator()->CheckCxxModuleSupport(); -} - -bool cmNinjaTargetGenerator::NeedDyndep(std::string const& lang, - std::string const& config) const -{ - return lang == "Fortran" || this->NeedCxxModuleSupport(lang, config); -} - std::string cmNinjaTargetGenerator::OrderDependsTargetForTarget( const std::string& config) { @@ -256,54 +236,17 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( flags, genexInterpreter.Evaluate(pchOptions, COMPILE_OPTIONS)); } - auto const& path = source->GetFullPath(); - auto const* tgt = this->GeneratorTarget->Target; - - std::string file_set_type; - - for (auto const& name : tgt->GetAllFileSetNames()) { - auto const* file_set = tgt->GetFileSet(name); - if (!file_set) { + auto const* fs = this->GeneratorTarget->GetFileSetForSource(config, source); + if (fs && + (fs->GetType() == "CXX_MODULES"_s || + fs->GetType() == "CXX_MODULE_HEADER_UNITS"_s)) { + if (source->GetLanguage() != "CXX"_s) { this->GetMakefile()->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("Target \"", tgt->GetName(), - "\" is tracked to have file set \"", name, - "\", but it was not found.")); - continue; - } - - auto fileEntries = file_set->CompileFileEntries(); - auto directoryEntries = file_set->CompileDirectoryEntries(); - auto directories = file_set->EvaluateDirectoryEntries( - directoryEntries, this->LocalGenerator, config, this->GeneratorTarget); - - std::map<std::string, std::vector<std::string>> files; - for (auto const& entry : fileEntries) { - file_set->EvaluateFileEntry(directories, files, entry, - this->LocalGenerator, config, - this->GeneratorTarget); - } - - for (auto const& it : files) { - for (auto const& filename : it.second) { - if (filename == path) { - file_set_type = file_set->GetType(); - break; - } - } - } - - if (file_set_type == "CXX_MODULES"_s || - file_set_type == "CXX_MODULE_HEADER_UNITS"_s) { - if (source->GetLanguage() != "CXX"_s) { - this->GetMakefile()->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat( - "Target \"", tgt->GetName(), "\" contains the source\n ", path, - "\nin a file set of type \"", file_set_type, - R"(" but the source is not classified as a "CXX" source.)")); - continue; - } + MessageType::FATAL_ERROR, + cmStrCat("Target \"", this->GeneratorTarget->Target->GetName(), + "\" contains the source\n ", source->GetFullPath(), + "\nin a file set of type \"", fs->GetType(), + R"(" but the source is not classified as a "CXX" source.)")); } } @@ -452,6 +395,24 @@ std::string cmNinjaTargetGenerator::GetObjectFilePath( return path; } +std::string cmNinjaTargetGenerator::GetClangTidyReplacementsFilePath( + const std::string& directory, cmSourceFile const* source, + const std::string& config) const +{ + std::string path = this->LocalGenerator->GetHomeRelativeOutputPath(); + if (!path.empty()) { + path += '/'; + } + path = cmStrCat(directory, '/', path); + std::string const& objectName = this->GeneratorTarget->GetObjectName(source); + path = + cmStrCat(std::move(path), + this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), + this->GetGlobalGenerator()->ConfigDirectory(config), '/', + objectName, ".yaml"); + return path; +} + std::string cmNinjaTargetGenerator::GetPreprocessedFilePath( cmSourceFile const* source, const std::string& config) const { @@ -600,9 +561,9 @@ cmNinjaRule GetScanRule( // Scanning always uses a depfile for preprocessor dependencies. if (deptype == "msvc"_s) { rule.DepType = deptype; - rule.DepFile = ""; + rule.DepFile.clear(); } else { - rule.DepType = ""; // no deps= for multiple outputs + rule.DepType.clear(); // no deps= for multiple outputs rule.DepFile = "$DEP_FILE"; } @@ -650,6 +611,19 @@ cmNinjaRule GetScanRule( void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, const std::string& config) { + // For some cases we scan to dynamically discover dependencies. + bool const needDyndep = this->GetGeneratorTarget()->NeedDyndep(lang, config); + + if (needDyndep) { + this->WriteCompileRule(lang, config, WithScanning::Yes); + } + this->WriteCompileRule(lang, config, WithScanning::No); +} + +void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, + const std::string& config, + WithScanning withScanning) +{ cmRulePlaceholderExpander::RuleVariables vars; vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str(); vars.CMTargetType = @@ -669,7 +643,6 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, cmMakefile* mf = this->GetMakefile(); // For some cases we scan to dynamically discover dependencies. - bool const needDyndep = this->NeedDyndep(lang, config); bool const compilationPreprocesses = !this->NeedExplicitPreprocessing(lang); std::string flags = "$FLAGS"; @@ -707,7 +680,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, this->GetLocalGenerator()->ConvertToOutputFormat( cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL); - if (needDyndep) { + if (withScanning == WithScanning::Yes) { const auto& scanDepType = this->GetMakefile()->GetSafeDefinition( cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_SCANDEP_DEPFILE_FORMAT")); @@ -813,7 +786,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, this->GetGlobalGenerator()->AddRule(rule); } - cmNinjaRule rule(this->LanguageCompilerRule(lang, config)); + cmNinjaRule rule(this->LanguageCompilerRule(lang, config, withScanning)); // If using a response file, move defines, includes, and flags into it. if (!responseFlag.empty()) { rule.RspFile = "$RSP_FILE"; @@ -867,7 +840,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, } } - if (needDyndep && !modmapFormat.empty()) { + if (withScanning == WithScanning::Yes && !modmapFormat.empty()) { std::string modmapFlags = mf->GetRequiredDefinition( cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FLAG")); cmSystemTools::ReplaceString(modmapFlags, "<MODULE_MAP_FILE>", @@ -978,8 +951,24 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, } else { driverMode = lang == "C" ? "gcc" : "g++"; } + const bool haveClangTidyExportFixesDir = + !this->GeneratorTarget->GetClangTidyExportFixesDirectory(lang) + .empty(); + std::string exportFixes; + if (haveClangTidyExportFixesDir) { + exportFixes = ";--export-fixes=$CLANG_TIDY_EXPORT_FIXES"; + } run_iwyu += this->GetLocalGenerator()->EscapeForShell( - cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode)); + cmStrCat(*tidy, ";--extra-arg-before=--driver-mode=", driverMode, + exportFixes)); + if (haveClangTidyExportFixesDir) { + std::string search = cmStrCat( + this->GetLocalGenerator()->GetState()->UseWindowsShell() ? "" + : "\\", + "$$CLANG_TIDY_EXPORT_FIXES"); + auto loc = run_iwyu.rfind(search); + run_iwyu.replace(loc, search.length(), "$CLANG_TIDY_EXPORT_FIXES"); + } } if (cmNonempty(cpplint)) { run_iwyu += cmStrCat( @@ -1177,30 +1166,42 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( } this->GetImplFileStream(fileConfig) << "\n"; +} - if (!this->Configs[config].SwiftOutputMap.empty()) { - std::string const mapFilePath = - cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/', - "output-file-map.json"); - std::string const targetSwiftDepsPath = [this, config]() -> std::string { - cmGeneratorTarget const* target = this->GeneratorTarget; - if (cmValue name = target->GetProperty("Swift_DEPENDENCIES_FILE")) { - return *name; - } - return this->ConvertToNinjaPath( - cmStrCat(target->GetSupportDirectory(), '/', config, '/', - target->GetName(), ".swiftdeps")); - }(); +void cmNinjaTargetGenerator::GenerateSwiftOutputFileMap( + const std::string& config, std::string& flags) +{ + if (this->Configs[config].SwiftOutputMap.empty()) { + return; + } + + std::string const targetSwiftDepsPath = [this, config]() -> std::string { + cmGeneratorTarget const* target = this->GeneratorTarget; + if (cmValue name = target->GetProperty("Swift_DEPENDENCIES_FILE")) { + return *name; + } + return this->ConvertToNinjaPath(cmStrCat(target->GetSupportDirectory(), + '/', config, '/', + target->GetName(), ".swiftdeps")); + }(); - // build the global target dependencies - // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps - Json::Value deps(Json::objectValue); - deps["swift-dependencies"] = targetSwiftDepsPath; - this->Configs[config].SwiftOutputMap[""] = deps; + std::string mapFilePath = + cmStrCat(this->GeneratorTarget->GetSupportDirectory(), '/', config, '/', + "output-file-map.json"); - cmGeneratedFileStream output(mapFilePath); - output << this->Configs[config].SwiftOutputMap; - } + // build the global target dependencies + // https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps + Json::Value deps(Json::objectValue); + deps["swift-dependencies"] = targetSwiftDepsPath; + this->Configs[config].SwiftOutputMap[""] = deps; + + cmGeneratedFileStream output(mapFilePath); + output << this->Configs[config].SwiftOutputMap; + + // Add flag + this->LocalGenerator->AppendFlags(flags, "-output-file-map"); + this->LocalGenerator->AppendFlagEscape(flags, + ConvertToNinjaPath(mapFilePath)); } namespace { @@ -1315,8 +1316,11 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( !(language == "RC" || (language == "CUDA" && !flag)); int const commandLineLengthLimit = ((lang_supports_response && this->ForceResponseFile())) ? -1 : 0; + bool const needDyndep = + this->GeneratorTarget->NeedDyndepForSource(language, config, source); - cmNinjaBuild objBuild(this->LanguageCompilerRule(language, config)); + cmNinjaBuild objBuild(this->LanguageCompilerRule( + language, config, needDyndep ? WithScanning::Yes : WithScanning::No)); cmNinjaVars& vars = objBuild.Variables; vars["FLAGS"] = this->ComputeFlagsForObject(source, language, config); vars["DEFINES"] = this->ComputeDefines(source, language, config); @@ -1345,6 +1349,18 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( } } + std::string d = + this->GeneratorTarget->GetClangTidyExportFixesDirectory(language); + if (!d.empty()) { + this->GlobalCommonGenerator->AddClangTidyExportFixesDir(d); + std::string fixesFile = + this->GetClangTidyReplacementsFilePath(d, source, config); + this->GlobalCommonGenerator->AddClangTidyExportFixesFile(fixesFile); + cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(fixesFile)); + fixesFile = this->ConvertToNinjaPath(fixesFile); + vars["CLANG_TIDY_EXPORT_FIXES"] = fixesFile; + } + if (firstForConfig) { this->ExportObjectCompileCommand( language, sourceFilePath, objectDir, objectFileName, objectFileDir, @@ -1425,7 +1441,6 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( } // For some cases we scan to dynamically discover dependencies. - bool const needDyndep = this->NeedDyndep(language, config); bool const compilationPreprocesses = !this->NeedExplicitPreprocessing(language); @@ -1664,214 +1679,15 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang, tdi_linked_target_dirs.append(l); } - cmTarget* tgt = this->GeneratorTarget->Target; - auto all_file_sets = tgt->GetAllFileSetNames(); - Json::Value& tdi_cxx_module_info = tdi["cxx-modules"] = Json::objectValue; - for (auto const& file_set_name : all_file_sets) { - auto* file_set = tgt->GetFileSet(file_set_name); - if (!file_set) { - this->GetMakefile()->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("Target \"", tgt->GetName(), - "\" is tracked to have file set \"", file_set_name, - "\", but it was not found.")); - continue; - } - auto fs_type = file_set->GetType(); - // We only care about C++ module sources here. - if (fs_type != "CXX_MODULES"_s) { - continue; - } - - auto fileEntries = file_set->CompileFileEntries(); - auto directoryEntries = file_set->CompileDirectoryEntries(); - - auto directories = file_set->EvaluateDirectoryEntries( - directoryEntries, this->GeneratorTarget->LocalGenerator, config, - this->GeneratorTarget); - std::map<std::string, std::vector<std::string>> files_per_dirs; - for (auto const& entry : fileEntries) { - file_set->EvaluateFileEntry(directories, files_per_dirs, entry, - this->GeneratorTarget->LocalGenerator, - config, this->GeneratorTarget); - } - - std::map<std::string, cmSourceFile const*> sf_map; - { - std::vector<cmSourceFile const*> objectSources; - this->GeneratorTarget->GetObjectSources(objectSources, config); - for (auto const* sf : objectSources) { - auto full_path = sf->GetFullPath(); - if (full_path.empty()) { - this->GetMakefile()->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("Target \"", tgt->GetName(), - "\" has a full path-less source file.")); - continue; - } - sf_map[full_path] = sf; - } - } - - Json::Value fs_dest = Json::nullValue; - for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) { - if (auto const* fsg = - dynamic_cast<cmInstallFileSetGenerator const*>(ig.get())) { - if (fsg->GetTarget() == this->GeneratorTarget && - fsg->GetFileSet() == file_set) { - fs_dest = fsg->GetDestination(config); - continue; - } - } - } - - for (auto const& files_per_dir : files_per_dirs) { - for (auto const& file : files_per_dir.second) { - auto lookup = sf_map.find(file); - if (lookup == sf_map.end()) { - this->GetMakefile()->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("Target \"", tgt->GetName(), "\" has source file \"", - file, - R"(" which is not in any of its "FILE_SET BASE_DIRS".)")); - continue; - } - - auto const* sf = lookup->second; - - if (!sf) { - this->GetMakefile()->IssueMessage( - MessageType::INTERNAL_ERROR, - cmStrCat("Target \"", tgt->GetName(), "\" has source file \"", - file, "\" which has not been tracked properly.")); - continue; - } - - auto obj_path = this->GetObjectFilePath(sf, config); - Json::Value& tdi_module_info = tdi_cxx_module_info[obj_path] = - Json::objectValue; - - tdi_module_info["source"] = file; - tdi_module_info["relative-directory"] = files_per_dir.first; - tdi_module_info["name"] = file_set->GetName(); - tdi_module_info["type"] = file_set->GetType(); - tdi_module_info["visibility"] = - std::string(cmFileSetVisibilityToName(file_set->GetVisibility())); - tdi_module_info["destination"] = fs_dest; - } - } - } - - tdi["config"] = config; - - // Add information about the export sets that this target is a member of. - Json::Value& tdi_exports = tdi["exports"] = Json::arrayValue; - std::string export_name = this->GeneratorTarget->GetExportName(); - - cmInstallCxxModuleBmiGenerator const* bmi_gen = nullptr; - for (auto const& ig : this->GetMakefile()->GetInstallGenerators()) { - if (auto const* bmig = - dynamic_cast<cmInstallCxxModuleBmiGenerator const*>(ig.get())) { - if (bmig->GetTarget() == this->GeneratorTarget) { - bmi_gen = bmig; - continue; - } - } - } - if (bmi_gen) { - Json::Value tdi_bmi_info = Json::objectValue; - - tdi_bmi_info["permissions"] = bmi_gen->GetFilePermissions(); - tdi_bmi_info["destination"] = bmi_gen->GetDestination(config); - const char* msg_level = ""; - switch (bmi_gen->GetMessageLevel()) { - case cmInstallGenerator::MessageDefault: - break; - case cmInstallGenerator::MessageAlways: - msg_level = "MESSAGE_ALWAYS"; - break; - case cmInstallGenerator::MessageLazy: - msg_level = "MESSAGE_LAZY"; - break; - case cmInstallGenerator::MessageNever: - msg_level = "MESSAGE_NEVER"; - break; - } - tdi_bmi_info["message-level"] = msg_level; - tdi_bmi_info["script-location"] = bmi_gen->GetScriptLocation(config); - - tdi["bmi-installation"] = tdi_bmi_info; - } else { - tdi["bmi-installation"] = Json::nullValue; - } - - auto const& all_install_exports = - this->GetGlobalGenerator()->GetExportSets(); - for (auto const& exp : all_install_exports) { - // Ignore exports sets which are not for this target. - auto const& targets = exp.second.GetTargetExports(); - auto tgt_export = - std::find_if(targets.begin(), targets.end(), - [this](std::unique_ptr<cmTargetExport> const& te) { - return te->Target == this->GeneratorTarget; - }); - if (tgt_export == targets.end()) { - continue; - } - - auto const* installs = exp.second.GetInstallations(); - for (auto const* install : *installs) { - Json::Value tdi_export_info = Json::objectValue; - - auto const& ns = install->GetNamespace(); - auto const& dest = install->GetDestination(); - auto const& cxxm_dir = install->GetCxxModuleDirectory(); - auto const& export_prefix = install->GetTempDir(); - - tdi_export_info["namespace"] = ns; - tdi_export_info["export-name"] = export_name; - tdi_export_info["destination"] = dest; - tdi_export_info["cxx-module-info-dir"] = cxxm_dir; - tdi_export_info["export-prefix"] = export_prefix; - tdi_export_info["install"] = true; - - tdi_exports.append(tdi_export_info); - } - } - - auto const& all_build_exports = - this->GetMakefile()->GetExportBuildFileGenerators(); - for (auto const& exp : all_build_exports) { - std::vector<std::string> targets; - exp->GetTargets(targets); + cmDyndepGeneratorCallbacks cb; + cb.ObjectFilePath = [this](cmSourceFile const* sf, std::string const& cnf) { + return this->GetObjectFilePath(sf, cnf); + }; - // Ignore exports sets which are not for this target. - auto const& name = this->GeneratorTarget->GetName(); - bool has_current_target = - std::any_of(targets.begin(), targets.end(), - [name](std::string const& tname) { return tname == name; }); - if (!has_current_target) { - continue; - } - - Json::Value tdi_export_info = Json::objectValue; - - auto const& ns = exp->GetNamespace(); - auto const& main_fn = exp->GetMainExportFileName(); - auto const& cxxm_dir = exp->GetCxxModuleDirectory(); - auto dest = cmsys::SystemTools::GetParentDirectory(main_fn); - auto const& export_prefix = - cmSystemTools::GetFilenamePath(exp->GetMainExportFileName()); - - tdi_export_info["namespace"] = ns; - tdi_export_info["export-name"] = export_name; - tdi_export_info["destination"] = dest; - tdi_export_info["cxx-module-info-dir"] = cxxm_dir; - tdi_export_info["export-prefix"] = export_prefix; - tdi_export_info["install"] = false; - - tdi_exports.append(tdi_export_info); - } +#if !defined(CMAKE_BOOTSTRAP) + cmDyndepCollation::AddCollationInformation(tdi, this->GeneratorTarget, + config, cb); +#endif std::string const tdin = this->GetTargetDependInfoPath(lang, config); cmGeneratedFileStream tdif(tdin); @@ -1998,7 +1814,8 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( std::string cmdLine = this->GetLocalGenerator()->BuildCommandLine( compileCmds, outputConfig, outputConfig); - this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName); + this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName, + objectFileName); } void cmNinjaTargetGenerator::AdditionalCleanFiles(const std::string& config) diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h index 4b4cf8d..8bf7986 100644 --- a/Source/cmNinjaTargetGenerator.h +++ b/Source/cmNinjaTargetGenerator.h @@ -63,19 +63,22 @@ protected: cmMakefile* GetMakefile() const { return this->Makefile; } + enum class WithScanning + { + No, + Yes, + }; std::string LanguageCompilerRule(const std::string& lang, - const std::string& config) const; + const std::string& config, + WithScanning withScanning) const; std::string LanguagePreprocessAndScanRule(std::string const& lang, const std::string& config) const; std::string LanguageScanRule(std::string const& lang, const std::string& config) const; std::string LanguageDyndepRule(std::string const& lang, const std::string& config) const; - bool NeedDyndep(std::string const& lang, std::string const& config) const; bool NeedExplicitPreprocessing(std::string const& lang) const; bool CompileWithDefines(std::string const& lang) const; - bool NeedCxxModuleSupport(std::string const& lang, - std::string const& config) const; std::string OrderDependsTargetForTarget(const std::string& config); @@ -131,6 +134,11 @@ protected: std::string GetPreprocessedFilePath(cmSourceFile const* source, const std::string& config) const; + /// @return the clang-tidy replacements file path for the given @a source. + std::string GetClangTidyReplacementsFilePath( + const std::string& directory, cmSourceFile const* source, + const std::string& config) const; + /// @return the dyndep file path for this target. std::string GetDyndepFilePath(std::string const& lang, const std::string& config) const; @@ -150,6 +158,8 @@ protected: const std::string& config); void WriteCompileRule(const std::string& language, const std::string& config); + void WriteCompileRule(const std::string& language, const std::string& config, + WithScanning withScanning); void WriteObjectBuildStatements(const std::string& config, const std::string& fileConfig, bool firstForConfig); @@ -163,6 +173,9 @@ protected: void EmitSwiftDependencyInfo(cmSourceFile const* source, const std::string& config); + void GenerateSwiftOutputFileMap(const std::string& config, + std::string& flags); + void ExportObjectCompileCommand( std::string const& language, std::string const& sourceFileName, std::string const& objectDir, std::string const& objectFileName, diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 4643868..fa24f57 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -431,7 +431,10 @@ class cmMakefile; SELECT(POLICY, CMP0142, \ "The Xcode generator does not append per-config suffixes to " \ "library search paths.", \ - 3, 25, 0, cmPolicies::WARN) + 3, 25, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0143, \ + "Global property USE_FOLDERS treated as ON by default", 3, 26, 0, \ + cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx index 249fe2d..4d1ccfe 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -34,6 +34,15 @@ bool cmProjectCommand(std::vector<std::string> const& args, } cmMakefile& mf = status.GetMakefile(); + if (mf.IsRootMakefile() && + !mf.GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION")) { + mf.IssueMessage( + MessageType::AUTHOR_WARNING, + "cmake_minimum_required() should be called prior to this top-level " + "project() call. Please see the cmake-commands(7) manual for usage " + "documentation of both commands."); + } + if (!IncludeByVariable(status, "CMAKE_PROJECT_INCLUDE_BEFORE")) { return false; } diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 96649ab..66e591e 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -970,8 +970,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() uiHeader, uiHeaderGenex, cmStrCat(this->Dir.Build, "/include"_s), uiHeaderFilePath); - this->Uic.UiHeaders.emplace_back( - std::make_pair(uiHeader, uiHeaderGenex)); + this->Uic.UiHeaders.emplace_back(uiHeader, uiHeaderGenex); } else { // Register skipped .ui file this->Uic.SkipUi.insert(fullPath); @@ -2095,7 +2094,7 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars, // Evaluate generator expression { cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - cmGeneratorExpression ge(lfbt); + cmGeneratorExpression ge(*this->Makefile->GetCMakeInstance(), lfbt); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(val); genVars.Executable = cge->Evaluate(this->LocalGen, ""); } diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 4753e61..683c18f 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -1981,6 +1981,9 @@ void cmQtAutoMocUicT::JobCompileMocT::Process() std::string const& sourceFile = this->Mapping->SourceFile->FileName; std::string const& outputFile = this->Mapping->OutputFile; + // Remove output file in case the case of the source file has changed + cmSystemTools::RemoveFile(outputFile); + // Compose moc command std::vector<std::string> cmd; { diff --git a/Source/cmRulePlaceholderExpander.cxx b/Source/cmRulePlaceholderExpander.cxx index b63d11c..638bb42 100644 --- a/Source/cmRulePlaceholderExpander.cxx +++ b/Source/cmRulePlaceholderExpander.cxx @@ -119,11 +119,6 @@ std::string cmRulePlaceholderExpander::ExpandVariable( return this->ReplaceValues->SwiftModuleName; } } - if (this->ReplaceValues->SwiftOutputFileMap) { - if (variable == "SWIFT_OUTPUT_FILE_MAP") { - return this->ReplaceValues->SwiftOutputFileMap; - } - } if (this->ReplaceValues->SwiftSources) { if (variable == "SWIFT_SOURCES") { return this->ReplaceValues->SwiftSources; diff --git a/Source/cmRulePlaceholderExpander.h b/Source/cmRulePlaceholderExpander.h index 23ec405..5d1f199 100644 --- a/Source/cmRulePlaceholderExpander.h +++ b/Source/cmRulePlaceholderExpander.h @@ -64,7 +64,7 @@ public: const char* SwiftLibraryName = nullptr; const char* SwiftModule = nullptr; const char* SwiftModuleName = nullptr; - const char* SwiftOutputFileMap = nullptr; + const char* SwiftOutputFileMapOption = nullptr; const char* SwiftSources = nullptr; const char* ISPCHeader = nullptr; const char* CudaCompileMode = nullptr; diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx index 6c53b85..44f37cb 100644 --- a/Source/cmSearchPath.cxx +++ b/Source/cmSearchPath.cxx @@ -179,12 +179,27 @@ void cmSearchPath::AddPrefixPaths(const std::vector<std::string>& paths, cmValue arch = this->FC->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE"); if (cmNonempty(arch)) { + std::string archNoUnknown = arch; + auto unknownAtPos = archNoUnknown.find("-unknown-"); + bool foundUnknown = unknownAtPos != std::string::npos; + if (foundUnknown) { + // Replace "-unknown-" with "-". + archNoUnknown.replace(unknownAtPos, 9, "-"); + } if (this->FC->Makefile->IsDefinitionSet("CMAKE_SYSROOT") && this->FC->Makefile->IsDefinitionSet( "CMAKE_PREFIX_LIBRARY_ARCHITECTURE")) { + if (foundUnknown) { + this->AddPathInternal(cmStrCat('/', archNoUnknown, dir, subdir), + cmStrCat('/', archNoUnknown, prefix), base); + } this->AddPathInternal(cmStrCat('/', *arch, dir, subdir), cmStrCat('/', *arch, prefix), base); } else { + if (foundUnknown) { + this->AddPathInternal(cmStrCat(dir, subdir, '/', archNoUnknown), + prefix, base); + } this->AddPathInternal(cmStrCat(dir, subdir, '/', *arch), prefix, base); } diff --git a/Source/cmState.cxx b/Source/cmState.cxx index e54ccfc..f12f91f 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -786,6 +786,8 @@ std::string cmState::ModeToString(cmState::Mode mode) return "CTEST"; case CPack: return "CPACK"; + case Help: + return "HELP"; case Unknown: return "UNKNOWN"; } diff --git a/Source/cmState.h b/Source/cmState.h index 2d0c521..9a17b22 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -53,6 +53,7 @@ public: FindPackage, CTest, CPack, + Help }; enum class ProjectKind diff --git a/Source/cmStringAlgorithms.cxx b/Source/cmStringAlgorithms.cxx index f73c854..66bf383 100644 --- a/Source/cmStringAlgorithms.cxx +++ b/Source/cmStringAlgorithms.cxx @@ -203,17 +203,45 @@ cmAlphaNum::cmAlphaNum(double val) MakeDigits(this->View_, this->Digits_, "%g", val); } -std::string cmCatViews(std::initializer_list<cm::string_view> views) +std::string cmCatViews( + std::initializer_list<std::pair<cm::string_view, std::string*>> views) { - std::size_t total_size = 0; - for (cm::string_view const& view : views) { - total_size += view.size(); + std::size_t totalSize = 0; + std::string* rvalueString = nullptr; + std::size_t rvalueStringLength = 0; + std::size_t rvalueStringOffset = 0; + for (auto const& view : views) { + // Find the rvalue string with the largest capacity. + if (view.second && + (!rvalueString || + view.second->capacity() > rvalueString->capacity())) { + rvalueString = view.second; + rvalueStringLength = rvalueString->length(); + rvalueStringOffset = totalSize; + } + totalSize += view.first.size(); } - std::string result(total_size, '\0'); - std::string::iterator sit = result.begin(); - for (cm::string_view const& view : views) { - sit = std::copy_n(view.data(), view.size(), sit); + std::string result; + std::string::size_type initialLen = 0; + if (rvalueString && rvalueString->capacity() >= totalSize) { + result = std::move(*rvalueString); + } else { + rvalueString = nullptr; + } + result.resize(totalSize); + if (rvalueString && rvalueStringOffset > 0) { + std::copy_backward(result.begin(), result.begin() + rvalueStringLength, + result.begin() + rvalueStringOffset + + rvalueStringLength); + } + std::string::iterator sit = result.begin() + initialLen; + for (auto const& view : views) { + if (rvalueString && view.second == rvalueString) { + sit += rvalueStringLength; + } else { + sit = std::copy_n(view.first.data(), view.first.size(), sit); + } } return result; } diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h index 83938bc..9ea7491 100644 --- a/Source/cmStringAlgorithms.h +++ b/Source/cmStringAlgorithms.h @@ -146,7 +146,8 @@ std::vector<std::string> cmExpandedLists(InputIt first, InputIt last) } /** Concatenate string pieces into a single string. */ -std::string cmCatViews(std::initializer_list<cm::string_view> views); +std::string cmCatViews( + std::initializer_list<std::pair<cm::string_view, std::string*>> views); /** Utility class for cmStrCat. */ class cmAlphaNum @@ -160,6 +161,10 @@ public: : View_(str) { } + cmAlphaNum(std::string&& str) + : RValueString_(&str) + { + } cmAlphaNum(const char* str) : View_(str) { @@ -182,20 +187,34 @@ public: { } - cm::string_view View() const { return this->View_; } + cm::string_view View() const + { + if (this->RValueString_) { + return *this->RValueString_; + } + return this->View_; + } + + std::string* RValueString() const { return this->RValueString_; } private: + std::string* RValueString_ = nullptr; cm::string_view View_; char Digits_[32]; }; /** Concatenate string pieces and numbers into a single string. */ -template <typename... AV> -inline std::string cmStrCat(cmAlphaNum const& a, cmAlphaNum const& b, - AV const&... args) +template <typename A, typename B, typename... AV> +inline std::string cmStrCat(A&& a, B&& b, AV&&... args) { - return cmCatViews( - { a.View(), b.View(), static_cast<cmAlphaNum const&>(args).View()... }); + static auto const makePair = + [](const cmAlphaNum& arg) -> std::pair<cm::string_view, std::string*> { + return { arg.View(), arg.RValueString() }; + }; + + return cmCatViews({ makePair(std::forward<A>(a)), + makePair(std::forward<B>(b)), + makePair(std::forward<AV>(args))... }); } /** Joins wrapped elements of a range with separator into a single string. */ @@ -206,8 +225,13 @@ std::string cmWrap(cm::string_view prefix, Range const& rng, if (rng.empty()) { return std::string(); } - return cmCatViews( - { prefix, cmJoin(rng, cmCatViews({ suffix, sep, prefix })), suffix }); + return cmCatViews({ { prefix, nullptr }, + { cmJoin(rng, + cmCatViews({ { suffix, nullptr }, + { sep, nullptr }, + { prefix, nullptr } })), + nullptr }, + { suffix, nullptr } }); } /** Joins wrapped elements of a range with separator into a single string. */ diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index c12d1fe..5a64588 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -9,7 +9,6 @@ #include <cctype> #include <cstdio> #include <cstdlib> -#include <initializer_list> #include <limits> #include <memory> #include <stdexcept> @@ -950,9 +949,9 @@ struct Args : cmRange<typename std::vector<std::string>::const_iterator> class json_error : public std::runtime_error { public: - json_error(std::initializer_list<cm::string_view> message, + json_error(const std::string& message, cm::optional<Args> errorPath = cm::nullopt) - : std::runtime_error(cmCatViews(message)) + : std::runtime_error(message) , ErrorPath{ std::move(errorPath) // NOLINT(performance-move-const-arg) } @@ -964,7 +963,7 @@ public: const std::string& Args::PopFront(cm::string_view error) { if (this->empty()) { - throw json_error({ error }); + throw json_error(std::string(error)); } const std::string& res = *this->begin(); this->advance(1); @@ -974,7 +973,7 @@ const std::string& Args::PopFront(cm::string_view error) const std::string& Args::PopBack(cm::string_view error) { if (this->empty()) { - throw json_error({ error }); + throw json_error(std::string(error)); } const std::string& res = *(this->end() - 1); this->retreat(1); @@ -999,7 +998,7 @@ cm::string_view JsonTypeToString(Json::ValueType type) case Json::ValueType::objectValue: return "OBJECT"_s; } - throw json_error({ "invalid JSON type found"_s }); + throw json_error("invalid JSON type found"); } int ParseIndex( @@ -1008,14 +1007,14 @@ int ParseIndex( { unsigned long lindex; if (!cmStrToULong(str, &lindex)) { - throw json_error({ "expected an array index, got: '"_s, str, "'"_s }, + throw json_error(cmStrCat("expected an array index, got: '"_s, str, "'"_s), progress); } Json::ArrayIndex index = static_cast<Json::ArrayIndex>(lindex); if (index >= max) { cmAlphaNum sizeStr{ max }; - throw json_error({ "expected an index less than "_s, sizeStr.View(), - " got '"_s, str, "'"_s }, + throw json_error(cmStrCat("expected an index less than "_s, sizeStr.View(), + " got '"_s, str, "'"_s), progress); } return index; @@ -1036,16 +1035,16 @@ Json::Value& ResolvePath(Json::Value& json, Args path) } else if (search->isObject()) { if (!search->isMember(field)) { const auto progressStr = cmJoin(progress, " "_s); - throw json_error({ "member '"_s, progressStr, "' not found"_s }, + throw json_error(cmStrCat("member '"_s, progressStr, "' not found"_s), progress); } search = &(*search)[field]; } else { const auto progressStr = cmJoin(progress, " "_s); throw json_error( - { "invalid path '"_s, progressStr, - "', need element of OBJECT or ARRAY type to lookup '"_s, field, - "' got "_s, JsonTypeToString(search->type()) }, + cmStrCat("invalid path '"_s, progressStr, + "', need element of OBJECT or ARRAY type to lookup '"_s, + field, "' got "_s, JsonTypeToString(search->type())), progress); } } @@ -1061,7 +1060,7 @@ Json::Value ReadJson(const std::string& jsonstr) std::string error; if (!jsonReader->parse(jsonstr.data(), jsonstr.data() + jsonstr.size(), &json, &error)) { - throw json_error({ "failed parsing json string: "_s, error }); + throw json_error(cmStrCat("failed parsing json string: "_s, error)); } return json; } @@ -1101,9 +1100,9 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments, mode != "LENGTH"_s && mode != "REMOVE"_s && mode != "SET"_s && mode != "EQUAL"_s) { throw json_error( - { "got an invalid mode '"_s, mode, - "', expected one of GET, TYPE, MEMBER, LENGTH, REMOVE, SET, " - " EQUAL"_s }); + cmStrCat("got an invalid mode '"_s, mode, + "', expected one of GET, TYPE, MEMBER, LENGTH, REMOVE, SET, " + " EQUAL"_s)); } const auto& jsonstr = args.PopFront("missing json string argument"_s); @@ -1127,10 +1126,11 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments, const auto& indexStr = args.PopBack("missing member index"_s); const auto& value = ResolvePath(json, args); if (!value.isObject()) { - throw json_error({ "MEMBER needs to be called with an element of " - "type OBJECT, got "_s, - JsonTypeToString(value.type()) }, - args); + throw json_error( + cmStrCat("MEMBER needs to be called with an element of " + "type OBJECT, got "_s, + JsonTypeToString(value.type())), + args); } const auto index = ParseIndex( indexStr, Args{ args.begin(), args.end() + 1 }, value.size()); @@ -1140,9 +1140,9 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments, } else if (mode == "LENGTH"_s) { const auto& value = ResolvePath(json, args); if (!value.isArray() && !value.isObject()) { - throw json_error({ "LENGTH needs to be called with an " - "element of type ARRAY or OBJECT, got "_s, - JsonTypeToString(value.type()) }, + throw json_error(cmStrCat("LENGTH needs to be called with an " + "element of type ARRAY or OBJECT, got "_s, + JsonTypeToString(value.type())), args); } @@ -1165,9 +1165,9 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments, value.removeMember(toRemove, &removed); } else { - throw json_error({ "REMOVE needs to be called with an " - "element of type ARRAY or OBJECT, got "_s, - JsonTypeToString(value.type()) }, + throw json_error(cmStrCat("REMOVE needs to be called with an " + "element of type ARRAY or OBJECT, got "_s, + JsonTypeToString(value.type())), args); } makefile.AddDefinition(*outputVariable, WriteJson(json)); @@ -1189,9 +1189,9 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments, value.append(newValue); } } else { - throw json_error({ "SET needs to be called with an " - "element of type OBJECT or ARRAY, got "_s, - JsonTypeToString(value.type()) }); + throw json_error(cmStrCat("SET needs to be called with an " + "element of type OBJECT or ARRAY, got "_s, + JsonTypeToString(value.type()))); } makefile.AddDefinition(*outputVariable, WriteJson(json)); @@ -1207,7 +1207,7 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments, if (outputVariable && e.ErrorPath) { const auto errorPath = cmJoin(*e.ErrorPath, "-"); makefile.AddDefinition(*outputVariable, - cmCatViews({ errorPath, "-NOTFOUND"_s })); + cmStrCat(errorPath, "-NOTFOUND"_s)); } else if (outputVariable) { makefile.AddDefinition(*outputVariable, "NOTFOUND"_s); } @@ -1215,7 +1215,7 @@ bool HandleJSONCommand(std::vector<std::string> const& arguments, if (errorVariable) { makefile.AddDefinition(*errorVariable, e.what()); } else { - status.SetError(cmCatViews({ "sub-command JSON "_s, e.what(), "."_s })); + status.SetError(cmStrCat("sub-command JSON "_s, e.what(), "."_s)); success = false; } } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index ee74908..f94c4d3 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -1111,16 +1111,9 @@ bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname, } #endif -bool cmSystemTools::CopySingleFile(const std::string& oldname, - const std::string& newname) -{ - return cmSystemTools::CopySingleFile(oldname, newname, CopyWhen::Always) == - CopyResult::Success; -} - cmSystemTools::CopyResult cmSystemTools::CopySingleFile( std::string const& oldname, std::string const& newname, CopyWhen when, - std::string* err) + CopyInputRecent inputRecent, std::string* err) { switch (when) { case CopyWhen::Always: @@ -1140,23 +1133,50 @@ cmSystemTools::CopyResult cmSystemTools::CopySingleFile( return CopyResult::Success; } - cmsys::Status status; + cmsys::SystemTools::CopyStatus status; status = cmsys::SystemTools::CloneFileContent(oldname, newname); if (!status) { // if cloning did not succeed, fall back to blockwise copy +#ifdef _WIN32 + if (inputRecent == CopyInputRecent::Yes) { + // Windows sometimes locks a file immediately after creation. + // Retry a few times. + WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry(); + while ((status = + cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname), + status.Path == cmsys::SystemTools::CopyStatus::SourcePath && + status.GetPOSIX() == EACCES && --retry.Count)) { + cmSystemTools::Delay(retry.Delay); + } + } else { + status = cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname); + } +#else + static_cast<void>(inputRecent); status = cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname); +#endif } if (!status) { if (err) { *err = status.GetString(); + switch (status.Path) { + case cmsys::SystemTools::CopyStatus::SourcePath: + *err = cmStrCat(*err, " (input)"); + break; + case cmsys::SystemTools::CopyStatus::DestPath: + *err = cmStrCat(*err, " (output)"); + break; + default: + break; + } } return CopyResult::Failure; } if (perms) { - status = SystemTools::SetPermissions(newname, perm); - if (!status) { + perms = SystemTools::SetPermissions(newname, perm); + if (!perms) { if (err) { - *err = status.GetString(); + *err = cmStrCat(perms.GetString(), " (output)"); } return CopyResult::Failure; } diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 87b354c..09f2bf0 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -149,6 +149,11 @@ public: Always, OnlyIfDifferent, }; + enum class CopyInputRecent + { + No, + Yes, + }; enum class CopyResult { Success, @@ -177,10 +182,9 @@ public: const mode_t* mode = nullptr); /** Copy a file. */ - static bool CopySingleFile(const std::string& oldname, - const std::string& newname); static CopyResult CopySingleFile(std::string const& oldname, std::string const& newname, CopyWhen when, + CopyInputRecent inputRecent, std::string* err = nullptr); enum class Replace diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 874195b..37f9e98 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -526,6 +526,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("ANDROID_ANT_ADDITIONAL_OPTIONS"); initProp("BUILD_RPATH"); initProp("BUILD_RPATH_USE_ORIGIN"); + initProp("CXX_SCAN_FOR_MODULES"); initProp("INSTALL_NAME_DIR"); initProp("INSTALL_REMOVE_ENVIRONMENT_RPATH"); initPropValue("INSTALL_RPATH", ""); @@ -572,12 +573,14 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("NO_SYSTEM_FROM_IMPORTED"); initProp("BUILD_WITH_INSTALL_NAME_DIR"); initProp("C_CLANG_TIDY"); + initProp("C_CLANG_TIDY_EXPORT_FIXES_DIR"); initProp("C_CPPLINT"); initProp("C_CPPCHECK"); initProp("C_INCLUDE_WHAT_YOU_USE"); initProp("C_LINKER_LAUNCHER"); initProp("LINK_WHAT_YOU_USE"); initProp("CXX_CLANG_TIDY"); + initProp("CXX_CLANG_TIDY_EXPORT_FIXES_DIR"); initProp("CXX_CPPLINT"); initProp("CXX_CPPCHECK"); initProp("CXX_INCLUDE_WHAT_YOU_USE"); @@ -599,8 +602,10 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("LINK_SEARCH_START_STATIC"); initProp("LINK_SEARCH_END_STATIC"); initProp("OBJC_CLANG_TIDY"); + initProp("OBJC_CLANG_TIDY_EXPORT_FIXES_DIR"); initProp("OBJC_LINKER_LAUNCHER"); initProp("OBJCXX_CLANG_TIDY"); + initProp("OBJCXX_CLANG_TIDY_EXPORT_FIXES_DIR"); initProp("OBJCXX_LINKER_LAUNCHER"); initProp("Swift_LANGUAGE_VERSION"); initProp("Swift_MODULE_DIRECTORY"); @@ -2657,7 +2662,8 @@ std::pair<cmFileSet*, bool> cmTarget::GetOrCreateFileSet( const std::string& name, const std::string& type, cmFileSetVisibility vis) { auto result = this->impl->FileSets.emplace( - std::make_pair(name, cmFileSet(name, type, vis))); + name, + cmFileSet(*this->GetMakefile()->GetCMakeInstance(), name, type, vis)); if (result.second) { auto bt = this->impl->Makefile->GetBacktrace(); if (type == this->impl->HeadersFileSets.TypeName) { diff --git a/Source/cmTargetIncludeDirectoriesCommand.cxx b/Source/cmTargetIncludeDirectoriesCommand.cxx index cb83873..7a2dd09 100644 --- a/Source/cmTargetIncludeDirectoriesCommand.cxx +++ b/Source/cmTargetIncludeDirectoriesCommand.cxx @@ -100,8 +100,7 @@ bool cmTargetIncludeDirectoriesCommand(std::vector<std::string> const& args, { return TargetIncludeDirectoriesImpl(status).HandleArguments( args, "INCLUDE_DIRECTORIES", - static_cast<TargetIncludeDirectoriesImpl::ArgumentFlags>( - TargetIncludeDirectoriesImpl::PROCESS_BEFORE | + TargetIncludeDirectoriesImpl::PROCESS_BEFORE | TargetIncludeDirectoriesImpl::PROCESS_AFTER | - TargetIncludeDirectoriesImpl::PROCESS_SYSTEM)); + TargetIncludeDirectoriesImpl::PROCESS_SYSTEM); } diff --git a/Source/cmTargetPropCommandBase.cxx b/Source/cmTargetPropCommandBase.cxx index 391b954..8d2ff71 100644 --- a/Source/cmTargetPropCommandBase.cxx +++ b/Source/cmTargetPropCommandBase.cxx @@ -23,7 +23,7 @@ void cmTargetPropCommandBase::SetError(std::string const& e) bool cmTargetPropCommandBase::HandleArguments( std::vector<std::string> const& args, const std::string& prop, - ArgumentFlags flags) + unsigned int flags) { if (args.size() < 2) { this->SetError("called with incorrect number of arguments"); diff --git a/Source/cmTargetPropCommandBase.h b/Source/cmTargetPropCommandBase.h index 6bf7c3c..ac50b4d 100644 --- a/Source/cmTargetPropCommandBase.h +++ b/Source/cmTargetPropCommandBase.h @@ -24,13 +24,12 @@ public: NO_FLAGS = 0x0, PROCESS_BEFORE = 0x1, PROCESS_AFTER = 0x2, - PROCESS_SYSTEM = 0x3, - PROCESS_REUSE_FROM = 0x4 + PROCESS_SYSTEM = 0x4, + PROCESS_REUSE_FROM = 0x8 }; bool HandleArguments(std::vector<std::string> const& args, - const std::string& prop, - ArgumentFlags flags = NO_FLAGS); + const std::string& prop, unsigned int flags = NO_FLAGS); protected: std::string Property; diff --git a/Source/cmTestGenerator.cxx b/Source/cmTestGenerator.cxx index dbb0876..5e325dd 100644 --- a/Source/cmTestGenerator.cxx +++ b/Source/cmTestGenerator.cxx @@ -127,7 +127,8 @@ void cmTestGenerator::GenerateScriptForConfig(std::ostream& os, this->TestGenerated = true; // Set up generator expression evaluation context. - cmGeneratorExpression ge(this->Test->GetBacktrace()); + cmGeneratorExpression ge(*this->Test->GetMakefile()->GetCMakeInstance(), + this->Test->GetBacktrace()); // Determine if policy CMP0110 is set to NEW. const bool quote_test_name = diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index 677fdb6..7e47b4e 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -128,8 +128,8 @@ std::string cmTimestamp::CreateTimestampFromTimeT(time_t timeT, : static_cast<char>(0); if (c1 == '%' && c2 != 0) { - result += - this->AddTimestampComponent(c2, timeStruct, timeT, microseconds); + result += this->AddTimestampComponent(c2, timeStruct, timeT, utcFlag, + microseconds); ++i; } else { result += c1; @@ -179,7 +179,7 @@ time_t cmTimestamp::CreateUtcTimeTFromTm(struct tm& tm) const } std::string cmTimestamp::AddTimestampComponent( - char flag, struct tm& timeStruct, const time_t timeT, + char flag, struct tm& timeStruct, const time_t timeT, const bool utcFlag, const uint32_t microseconds) const { std::string formatString = cmStrCat('%', flag); @@ -203,6 +203,63 @@ std::string cmTimestamp::AddTimestampComponent( case 'Y': case '%': break; + case 'Z': +#if defined(__GLIBC__) + // 'struct tm' has the time zone, so strftime can honor UTC. + static_cast<void>(utcFlag); +#else + // 'struct tm' may not have the time zone, so strftime may + // use local time. Hard-code the UTC result. + if (utcFlag) { + return std::string("GMT"); + } +#endif + break; + case 'z': { +#if defined(__GLIBC__) + // 'struct tm' has the time zone, so strftime can honor UTC. + static_cast<void>(utcFlag); +#else + // 'struct tm' may not have the time zone, so strftime may + // use local time. Hard-code the UTC result. + if (utcFlag) { + return std::string("+0000"); + } +#endif +#ifndef _AIX + break; +#else + std::string xpg_sus_old; + bool const xpg_sus_was_set = + cmSystemTools::GetEnv("XPG_SUS_ENV", xpg_sus_old); + if (xpg_sus_was_set && xpg_sus_old == "ON") { + break; + } + xpg_sus_old = "XPG_SUS_ENV=" + xpg_sus_old; + + // On AIX systems, %z requires XPG_SUS_ENV=ON to work as desired. + cmSystemTools::PutEnv("XPG_SUS_ENV=ON"); + tzset(); + + char buffer[16]; + size_t size = strftime(buffer, sizeof(buffer), "%z", &timeStruct); + +# ifndef CMAKE_BOOTSTRAP + if (xpg_sus_was_set) { + cmSystemTools::PutEnv(xpg_sus_old); + } else { + cmSystemTools::UnsetEnv("XPG_SUS_ENV"); + } +# else + // No UnsetEnv during bootstrap. This is good enough for CMake itself. + cmSystemTools::PutEnv(xpg_sus_old); + static_cast<void>(xpg_sus_was_set); +# endif + tzset(); + + return std::string(buffer, size); +#endif + } case 's': // Seconds since UNIX epoch (midnight 1-jan-1970) { // Build a time_t for UNIX epoch and subtract from the input "timeT": diff --git a/Source/cmTimestamp.h b/Source/cmTimestamp.h index ada5006..05c6342 100644 --- a/Source/cmTimestamp.h +++ b/Source/cmTimestamp.h @@ -32,6 +32,6 @@ private: time_t CreateUtcTimeTFromTm(struct tm& timeStruct) const; std::string AddTimestampComponent(char flag, struct tm& timeStruct, - time_t timeT, - uint32_t microseconds = 0) const; + time_t timeT, bool utcFlag, + uint32_t microseconds) const; }; diff --git a/Source/cmTryCompileCommand.cxx b/Source/cmTryCompileCommand.cxx index a2c4ce1..c70c03e 100644 --- a/Source/cmTryCompileCommand.cxx +++ b/Source/cmTryCompileCommand.cxx @@ -2,6 +2,9 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmTryCompileCommand.h" +#include <cm/optional> + +#include "cmConfigureLog.h" #include "cmCoreTryCompile.h" #include "cmExecutionStatus.h" #include "cmMakefile.h" @@ -13,6 +16,24 @@ #include "cmValue.h" #include "cmake.h" +namespace { +#ifndef CMAKE_BOOTSTRAP +void WriteTryCompileEvent(cmConfigureLog& log, cmMakefile const& mf, + cmTryCompileResult const& compileResult) +{ + // Keep in sync with cmFileAPIConfigureLog's DumpEventKindNames. + static const std::vector<unsigned long> LogVersionsWithTryCompileV1{ 1 }; + + if (log.IsAnyLogVersionEnabled(LogVersionsWithTryCompileV1)) { + log.BeginEvent("try_compile-v1"); + log.WriteBacktrace(mf); + cmCoreTryCompile::WriteTryCompileEventFields(log, compileResult); + log.EndEvent(); + } +} +#endif +} + bool cmTryCompileCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -59,7 +80,15 @@ bool cmTryCompileCommand(std::vector<std::string> const& args, if (!arguments) { return true; } - tc.TryCompileCode(arguments, targetType); + + if (cm::optional<cmTryCompileResult> compileResult = + tc.TryCompileCode(arguments, targetType)) { +#ifndef CMAKE_BOOTSTRAP + if (cmConfigureLog* log = mf.GetCMakeInstance()->GetConfigureLog()) { + WriteTryCompileEvent(*log, mf, *compileResult); + } +#endif + } // if They specified clean then we clean up what we can if (tc.SrcFileSignature) { diff --git a/Source/cmTryRunCommand.cxx b/Source/cmTryRunCommand.cxx index 8d62cb1..ef59c32 100644 --- a/Source/cmTryRunCommand.cxx +++ b/Source/cmTryRunCommand.cxx @@ -3,12 +3,15 @@ #include "cmTryRunCommand.h" #include <cstdio> +#include <stdexcept> #include <cm/optional> +#include <cmext/string_view> #include "cmsys/FStream.hxx" #include "cmArgumentParserTypes.h" +#include "cmConfigureLog.h" #include "cmCoreTryCompile.h" #include "cmDuration.h" #include "cmExecutionStatus.h" @@ -23,6 +26,49 @@ #include "cmake.h" namespace { +struct cmTryRunResult +{ + bool VariableCached = true; + std::string Variable; + cm::optional<std::string> Stdout; + cm::optional<std::string> Stderr; + cm::optional<std::string> ExitCode; +}; + +#ifndef CMAKE_BOOTSTRAP +void WriteTryRunEvent(cmConfigureLog& log, cmMakefile const& mf, + cmTryCompileResult const& compileResult, + cmTryRunResult const& runResult) +{ + // Keep in sync with cmFileAPIConfigureLog's DumpEventKindNames. + static const std::vector<unsigned long> LogVersionsWithTryRunV1{ 1 }; + + if (log.IsAnyLogVersionEnabled(LogVersionsWithTryRunV1)) { + log.BeginEvent("try_run-v1"); + log.WriteBacktrace(mf); + cmCoreTryCompile::WriteTryCompileEventFields(log, compileResult); + + log.BeginObject("runResult"_s); + log.WriteValue("variable"_s, runResult.Variable); + log.WriteValue("cached"_s, runResult.VariableCached); + if (runResult.Stdout) { + log.WriteLiteralTextBlock("stdout"_s, *runResult.Stdout); + } + if (runResult.Stderr) { + log.WriteLiteralTextBlock("stderr"_s, *runResult.Stderr); + } + if (runResult.ExitCode) { + try { + log.WriteValue("exitCode"_s, std::stoi(*runResult.ExitCode)); + } catch (std::invalid_argument const&) { + log.WriteValue("exitCode"_s, *runResult.ExitCode); + } + } + log.EndObject(); + log.EndEvent(); + } +} +#endif class TryRunCommandImpl : public cmCoreTryCompile { @@ -44,7 +90,8 @@ public: std::string const& compileResultVariable, std::string* runOutputContents, std::string* runOutputStdOutContents, - std::string* runOutputStdErrContents); + std::string* runOutputStdErrContents, + bool stdOutErrRequired); bool NoCache; std::string RunResultVariable; @@ -96,23 +143,35 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv) } bool captureRunOutput = false; - bool captureRunOutputStdOutErr = false; if (arguments.OutputVariable) { captureRunOutput = true; } else if (arguments.CompileOutputVariable) { arguments.OutputVariable = arguments.CompileOutputVariable; } - if (arguments.RunOutputStdOutVariable || arguments.RunOutputStdErrVariable) { - captureRunOutputStdOutErr = true; - } else if (arguments.RunOutputVariable) { - captureRunOutput = true; + + // Capture the split output for the configure log unless the caller + // requests combined output to be captured by a variable. + bool captureRunOutputStdOutErr = true; + if (!arguments.RunOutputStdOutVariable && + !arguments.RunOutputStdErrVariable) { + if (arguments.RunOutputVariable) { + captureRunOutput = true; + captureRunOutputStdOutErr = false; + } else if (arguments.OutputVariable) { + captureRunOutputStdOutErr = false; + } } // do the try compile - bool compiled = this->TryCompileCode(arguments, cmStateEnums::EXECUTABLE); + cm::optional<cmTryCompileResult> compileResult = + this->TryCompileCode(arguments, cmStateEnums::EXECUTABLE); + + cmTryRunResult runResult; + runResult.Variable = this->RunResultVariable; + runResult.VariableCached = !arguments.NoCache; // now try running the command if it compiled - if (compiled) { + if (compileResult && compileResult->ExitCode == 0) { if (this->OutputFile.empty()) { cmSystemTools::Error(this->FindErrorMessage); } else { @@ -127,26 +186,35 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv) std::string runOutputStdErrContents; if (this->Makefile->IsOn("CMAKE_CROSSCOMPILING") && !this->Makefile->IsDefinitionSet("CMAKE_CROSSCOMPILING_EMULATOR")) { + // We only require the stdout/stderr cache entries if the project + // actually asked for the values, not just for logging. + bool const stdOutErrRequired = (arguments.RunOutputStdOutVariable || + arguments.RunOutputStdErrVariable); this->DoNotRunExecutable( runArgs, arguments.SourceDirectoryOrFile, *arguments.CompileResultVariable, captureRunOutput ? &runOutputContents : nullptr, - captureRunOutputStdOutErr && arguments.RunOutputStdOutVariable - ? &runOutputStdOutContents - : nullptr, - captureRunOutputStdOutErr && arguments.RunOutputStdErrVariable - ? &runOutputStdErrContents - : nullptr); + captureRunOutputStdOutErr ? &runOutputStdOutContents : nullptr, + captureRunOutputStdOutErr ? &runOutputStdErrContents : nullptr, + stdOutErrRequired); } else { this->RunExecutable( runArgs, arguments.RunWorkingDirectory, captureRunOutput ? &runOutputContents : nullptr, - captureRunOutputStdOutErr && arguments.RunOutputStdOutVariable - ? &runOutputStdOutContents - : nullptr, - captureRunOutputStdOutErr && arguments.RunOutputStdErrVariable - ? &runOutputStdErrContents - : nullptr); + captureRunOutputStdOutErr ? &runOutputStdOutContents : nullptr, + captureRunOutputStdOutErr ? &runOutputStdErrContents : nullptr); + } + + if (captureRunOutputStdOutErr) { + runResult.Stdout = runOutputStdOutContents; + runResult.Stderr = runOutputStdErrContents; + } else { + runResult.Stdout = runOutputContents; + } + + if (cmValue ec = + this->Makefile->GetDefinition(this->RunResultVariable)) { + runResult.ExitCode = *ec; } // now put the output into the variables @@ -177,6 +245,15 @@ bool TryRunCommandImpl::TryRunCode(std::vector<std::string> const& argv) } } +#ifndef CMAKE_BOOTSTRAP + if (compileResult) { + cmMakefile const& mf = *(this->Makefile); + if (cmConfigureLog* log = mf.GetCMakeInstance()->GetConfigureLog()) { + WriteTryRunEvent(*log, mf, *compileResult, runResult); + } + } +#endif + // if we created a directory etc, then cleanup after ourselves if (!this->Makefile->GetCMakeInstance()->GetDebugTryCompile()) { this->CleanupFiles(this->BinaryDirectory); @@ -240,7 +317,7 @@ void TryRunCommandImpl::RunExecutable(const std::string& runArgs, void TryRunCommandImpl::DoNotRunExecutable( const std::string& runArgs, cm::optional<std::string> const& srcFile, std::string const& compileResultVariable, std::string* out, - std::string* stdOut, std::string* stdErr) + std::string* stdOut, std::string* stdErr, bool stdOutErrRequired) { // copy the executable out of the CMakeFiles/ directory, so it is not // removed at the end of try_run() and the user can run it manually @@ -286,7 +363,7 @@ void TryRunCommandImpl::DoNotRunExecutable( } // is the output from the executable used ? - if (stdOut || stdErr) { + if (stdOutErrRequired) { if (!this->Makefile->GetDefinition(internalRunOutputStdOutName)) { // if the variables doesn't exist, create it with a helpful error text // and mark it as advanced diff --git a/Source/cmUVProcessChain.cxx b/Source/cmUVProcessChain.cxx index 6040fd8..3faf2f6 100644 --- a/Source/cmUVProcessChain.cxx +++ b/Source/cmUVProcessChain.cxx @@ -241,6 +241,7 @@ bool cmUVProcessChain::InternalData::AddCommand( options.file = config.Arguments[0].c_str(); std::vector<const char*> arguments; + arguments.reserve(config.Arguments.size()); for (auto const& arg : config.Arguments) { arguments.push_back(arg.c_str()); } diff --git a/Source/cmVSSetupHelper.cxx b/Source/cmVSSetupHelper.cxx index 8764f21..6702b7b 100644 --- a/Source/cmVSSetupHelper.cxx +++ b/Source/cmVSSetupHelper.cxx @@ -87,12 +87,11 @@ std::string VSInstanceInfo::GetInstallLocation() const cmVSSetupAPIHelper::cmVSSetupAPIHelper(unsigned int version) : Version(version) - , setupConfig(NULL) - , setupConfig2(NULL) - , setupHelper(NULL) - , initializationFailure(false) + , setupConfig(nullptr) + , setupConfig2(nullptr) + , setupHelper(nullptr) { - comInitialized = CoInitializeEx(NULL, 0); + comInitialized = CoInitializeEx(nullptr, 0); if (SUCCEEDED(comInitialized)) { Initialize(); } else { @@ -102,11 +101,12 @@ cmVSSetupAPIHelper::cmVSSetupAPIHelper(unsigned int version) cmVSSetupAPIHelper::~cmVSSetupAPIHelper() { - setupHelper = NULL; - setupConfig2 = NULL; - setupConfig = NULL; - if (SUCCEEDED(comInitialized)) + setupHelper = nullptr; + setupConfig2 = nullptr; + setupConfig = nullptr; + if (SUCCEEDED(comInitialized)) { CoUninitialize(); + } } bool cmVSSetupAPIHelper::SetVSInstance(std::string const& vsInstallLocation, @@ -159,12 +159,12 @@ bool cmVSSetupAPIHelper::CheckInstalledComponent( // the // component name ex: Microsoft.VisualStudio.Component.Windows10SDK.10240 if (id.find(Win10SDKComponent) != std::wstring::npos && - type.compare(ComponentType) == 0) { + type == ComponentType) { bWin10SDK = true; ret = true; } - if (id.compare(Win81SDKComponent) == 0 && type.compare(ComponentType) == 0) { + if (id == Win81SDKComponent && type == ComponentType) { bWin81SDK = true; ret = true; } @@ -177,8 +177,9 @@ bool cmVSSetupAPIHelper::CheckInstalledComponent( bool cmVSSetupAPIHelper::GetVSInstanceInfo( SmartCOMPtr<ISetupInstance2> pInstance, VSInstanceInfo& vsInstanceInfo) { - if (pInstance == NULL) + if (pInstance == nullptr) { return false; + } InstanceState state; if (FAILED(pInstance->GetState(&state))) { @@ -188,21 +189,19 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo( SmartBSTR bstrVersion; if (FAILED(pInstance->GetInstallationVersion(&bstrVersion))) { return false; - } else { - vsInstanceInfo.Version = - cmsys::Encoding::ToNarrow(std::wstring(bstrVersion)); } + vsInstanceInfo.Version = + cmsys::Encoding::ToNarrow(std::wstring(bstrVersion)); // Reboot may have been required before the installation path was created. SmartBSTR bstrInstallationPath; if ((eLocal & state) == eLocal) { if (FAILED(pInstance->GetInstallationPath(&bstrInstallationPath))) { return false; - } else { - vsInstanceInfo.VSInstallLocation = - cmsys::Encoding::ToNarrow(std::wstring(bstrInstallationPath)); - cmSystemTools::ConvertToUnixSlashes(vsInstanceInfo.VSInstallLocation); } + vsInstanceInfo.VSInstallLocation = + cmsys::Encoding::ToNarrow(std::wstring(bstrInstallationPath)); + cmSystemTools::ConvertToUnixSlashes(vsInstanceInfo.VSInstallLocation); } // Check if a compiler is installed with this instance. @@ -220,7 +219,7 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo( LPSAFEARRAY lpsaPackages; if (FAILED(pInstance->GetPackages(&lpsaPackages)) || - lpsaPackages == NULL) { + lpsaPackages == nullptr) { return false; } @@ -229,11 +228,12 @@ bool cmVSSetupAPIHelper::GetVSInstanceInfo( IUnknown** ppData = (IUnknown**)lpsaPackages->pvData; for (int i = lower; i < upper; i++) { - SmartCOMPtr<ISetupPackageReference> package = NULL; + SmartCOMPtr<ISetupPackageReference> package = nullptr; if (FAILED(ppData[i]->QueryInterface(IID_ISetupPackageReference, (void**)&package)) || - package == NULL) + package == nullptr) { continue; + } bool win10SDKInstalled = false; bool win81SDkInstalled = false; @@ -289,7 +289,8 @@ bool cmVSSetupAPIHelper::GetVCToolsetVersion(std::string& vsToolsetVersion) bool cmVSSetupAPIHelper::IsEWDKEnabled() { - std::string envEnterpriseWDK, envDisableRegistryUse; + std::string envEnterpriseWDK; + std::string envDisableRegistryUse; cmSystemTools::GetEnv("EnterpriseWDK", envEnterpriseWDK); cmSystemTools::GetEnv("DisableRegistryUse", envDisableRegistryUse); if (!cmSystemTools::Strucmp(envEnterpriseWDK.c_str(), "True") && @@ -370,11 +371,12 @@ bool cmVSSetupAPIHelper::EnumerateVSInstancesWithVswhere( bool cmVSSetupAPIHelper::EnumerateVSInstancesWithCOM( std::vector<VSInstanceInfo>& VSInstances) { - if (initializationFailure || setupConfig == NULL || setupConfig2 == NULL || - setupHelper == NULL) + if (initializationFailure || setupConfig == nullptr || + setupConfig2 == nullptr || setupHelper == nullptr) { return false; + } - SmartCOMPtr<IEnumSetupInstances> enumInstances = NULL; + SmartCOMPtr<IEnumSetupInstances> enumInstances = nullptr; if (FAILED( setupConfig2->EnumInstances((IEnumSetupInstances**)&enumInstances)) || !enumInstances) { @@ -382,20 +384,21 @@ bool cmVSSetupAPIHelper::EnumerateVSInstancesWithCOM( } SmartCOMPtr<ISetupInstance> instance; - while (SUCCEEDED(enumInstances->Next(1, &instance, NULL)) && instance) { - SmartCOMPtr<ISetupInstance2> instance2 = NULL; + while (SUCCEEDED(enumInstances->Next(1, &instance, nullptr)) && instance) { + SmartCOMPtr<ISetupInstance2> instance2 = nullptr; if (FAILED( instance->QueryInterface(IID_ISetupInstance2, (void**)&instance2)) || !instance2) { - instance = NULL; + instance = nullptr; continue; } VSInstanceInfo instanceInfo; bool isInstalled = GetVSInstanceInfo(instance2, instanceInfo); - instance = instance2 = NULL; - if (isInstalled) + instance = instance2 = nullptr; + if (isInstalled) { VSInstances.push_back(instanceInfo); + } } return true; } @@ -403,18 +406,21 @@ bool cmVSSetupAPIHelper::EnumerateVSInstancesWithCOM( bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() { bool isVSInstanceExists = false; - if (chosenInstanceInfo.VSInstallLocation.compare("") != 0) { + if (!chosenInstanceInfo.VSInstallLocation.empty()) { return true; } if (this->IsEWDKEnabled()) { - std::string envWindowsSdkDir81, envVSVersion, envVsInstallDir; + std::string envWindowsSdkDir81; + std::string envVSVersion; + std::string envVsInstallDir; cmSystemTools::GetEnv("WindowsSdkDir_81", envWindowsSdkDir81); cmSystemTools::GetEnv("VisualStudioVersion", envVSVersion); cmSystemTools::GetEnv("VSINSTALLDIR", envVsInstallDir); - if (envVSVersion.empty() || envVsInstallDir.empty()) + if (envVSVersion.empty() || envVsInstallDir.empty()) { return false; + } chosenInstanceInfo.VSInstallLocation = envVsInstallDir; chosenInstanceInfo.Version = envVSVersion; @@ -499,7 +505,7 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() return this->LoadSpecifiedVSInstanceFromDisk(); } - if (vecVSInstances.size() > 0) { + if (!vecVSInstances.empty()) { isVSInstanceExists = true; int index = ChooseVSInstance(vecVSInstances); chosenInstanceInfo = vecVSInstances[index]; @@ -511,11 +517,13 @@ bool cmVSSetupAPIHelper::EnumerateAndChooseVSInstance() int cmVSSetupAPIHelper::ChooseVSInstance( const std::vector<VSInstanceInfo>& vecVSInstances) { - if (vecVSInstances.size() == 0) + if (vecVSInstances.empty()) { return -1; + } - if (vecVSInstances.size() == 1) + if (vecVSInstances.size() == 1) { return 0; + } unsigned int chosenIndex = 0; for (unsigned int i = 1; i < vecVSInstances.size(); i++) { @@ -589,32 +597,33 @@ bool cmVSSetupAPIHelper::LoadSpecifiedVSInstanceFromDisk() bool cmVSSetupAPIHelper::Initialize() { - if (initializationFailure) + if (initializationFailure) { return false; + } if (FAILED(comInitialized)) { initializationFailure = true; return false; } - if (FAILED(setupConfig.CoCreateInstance(CLSID_SetupConfiguration, NULL, + if (FAILED(setupConfig.CoCreateInstance(CLSID_SetupConfiguration, nullptr, IID_ISetupConfiguration, CLSCTX_INPROC_SERVER)) || - setupConfig == NULL) { + setupConfig == nullptr) { initializationFailure = true; return false; } if (FAILED(setupConfig.QueryInterface(IID_ISetupConfiguration2, (void**)&setupConfig2)) || - setupConfig2 == NULL) { + setupConfig2 == nullptr) { initializationFailure = true; return false; } if (FAILED( setupConfig.QueryInterface(IID_ISetupHelper, (void**)&setupHelper)) || - setupHelper == NULL) { + setupHelper == nullptr) { initializationFailure = true; return false; } diff --git a/Source/cmVSSetupHelper.h b/Source/cmVSSetupHelper.h index a16f00b..b8be9b9 100644 --- a/Source/cmVSSetupHelper.h +++ b/Source/cmVSSetupHelper.h @@ -17,18 +17,20 @@ template <class T> class SmartCOMPtr { public: - SmartCOMPtr() { ptr = NULL; } + SmartCOMPtr() = default; SmartCOMPtr(T* p) { ptr = p; - if (ptr != NULL) + if (ptr != nullptr) { ptr->AddRef(); + } } SmartCOMPtr(const SmartCOMPtr<T>& sptr) { ptr = sptr.ptr; - if (ptr != NULL) + if (ptr != nullptr) { ptr->AddRef(); + } } T** operator&() { return &ptr; } T* operator->() { return ptr; } @@ -36,8 +38,9 @@ public: { if (*this != p) { ptr = p; - if (ptr != NULL) + if (ptr != nullptr) { ptr->AddRef(); + } } return *this; } @@ -45,11 +48,10 @@ public: template <class I> HRESULT QueryInterface(REFCLSID rclsid, I** pp) { - if (pp != NULL) { + if (pp != nullptr) { return ptr->QueryInterface(rclsid, (void**)pp); - } else { - return E_FAIL; } + return E_FAIL; } HRESULT CoCreateInstance(REFCLSID clsid, IUnknown* pUnknown, REFIID interfaceId, DWORD dwClsContext = CLSCTX_ALL) @@ -60,18 +62,19 @@ public: } ~SmartCOMPtr() { - if (ptr != NULL) + if (ptr != nullptr) { ptr->Release(); + } } private: - T* ptr; + T* ptr = nullptr; }; class SmartBSTR { public: - SmartBSTR() { str = NULL; } + SmartBSTR() = default; SmartBSTR(const SmartBSTR& src) = delete; SmartBSTR& operator=(const SmartBSTR& src) = delete; operator BSTR() const { return str; } @@ -79,7 +82,7 @@ public: ~SmartBSTR() throw() { ::SysFreeString(str); } private: - BSTR str; + BSTR str = nullptr; }; struct VSInstanceInfo @@ -129,7 +132,7 @@ private: SmartCOMPtr<ISetupConfiguration2> setupConfig2; SmartCOMPtr<ISetupHelper> setupHelper; // used to indicate failure in Initialize(), so we don't have to call again - bool initializationFailure; + bool initializationFailure = false; // indicated if COM initialization is successful HRESULT comInitialized; // current best instance of VS selected diff --git a/Source/cmVersionConfig.h.in b/Source/cmVersionConfig.h.in index 06251f3..5d52950 100644 --- a/Source/cmVersionConfig.h.in +++ b/Source/cmVersionConfig.h.in @@ -1,5 +1,7 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + #define CMake_VERSION_MAJOR @CMake_VERSION_MAJOR@ #define CMake_VERSION_MINOR @CMake_VERSION_MINOR@ #define CMake_VERSION_PATCH @CMake_VERSION_PATCH@ diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 8882c45..1f45ce3 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -80,10 +80,10 @@ struct cmVisualStudio10TargetGenerator::Elem bool HasContent = false; std::string Tag; - Elem(std::ostream& s, const std::string& tag) + Elem(std::ostream& s, std::string tag) : S(s) , Indent(0) - , Tag(tag) + , Tag(std::move(tag)) { this->StartElement(); } @@ -200,7 +200,7 @@ struct cmVisualStudio10TargetGenerator::OptionsHelper } }; -static std::string cmVS10EscapeComment(std::string comment) +static std::string cmVS10EscapeComment(std::string const& comment) { // MSBuild takes the CDATA of a <Message></Message> element and just // does "echo $CDATA" with no escapes. We must encode the string. @@ -275,8 +275,8 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( this->Makefile->GetGeneratorConfigs(cmMakefile::ExcludeEmptyConfig); this->NsightTegra = gg->IsNsightTegra(); this->Android = gg->TargetsAndroid(); - for (int i = 0; i < 4; ++i) { - this->NsightTegraVersion[i] = 0; + for (unsigned int& version : this->NsightTegraVersion) { + version = 0; } sscanf(gg->GetNsightTegraVersion().c_str(), "%u.%u.%u.%u", &this->NsightTegraVersion[0], &this->NsightTegraVersion[1], @@ -293,9 +293,7 @@ cmVisualStudio10TargetGenerator::cmVisualStudio10TargetGenerator( this->ClassifyAllConfigSources(); } -cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator() -{ -} +cmVisualStudio10TargetGenerator::~cmVisualStudio10TargetGenerator() = default; std::string cmVisualStudio10TargetGenerator::CalcCondition( const std::string& config) const @@ -358,7 +356,8 @@ void cmVisualStudio10TargetGenerator::Generate() this->GeneratorTarget->CheckCxxModuleStatus(config); } - if (this->GeneratorTarget->HaveCxx20ModuleSources()) { + if (this->GeneratorTarget->HaveCxx20ModuleSources() && + !this->GlobalGenerator->SupportsCxxModuleDyndep()) { this->Makefile->IssueMessage( MessageType::FATAL_ERROR, cmStrCat("The \"", this->GeneratorTarget->GetName(), @@ -406,6 +405,9 @@ void cmVisualStudio10TargetGenerator::Generate() if (!this->ComputeCudaLinkOptions()) { return; } + if (!this->ComputeMarmasmOptions()) { + return; + } if (!this->ComputeMasmOptions()) { return; } @@ -423,7 +425,7 @@ void cmVisualStudio10TargetGenerator::Generate() cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), '/', this->Name, ProjectFileExtension); cmGeneratedFileStream BuildFileStream(path); - const std::string PathToProjectFile = path; + const std::string& PathToProjectFile = path; BuildFileStream.SetCopyIfDifferent(true); // Write the encoding header into the file @@ -453,7 +455,7 @@ void cmVisualStudio10TargetGenerator::Generate() void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile( cmGeneratedFileStream& BuildFileStream) { - BuildFileStream << "<?xml version=\"1.0\" encoding=\"" + BuildFileStream << R"(<?xml version="1.0" encoding=")" << this->GlobalGenerator->Encoding() << "\"?>"; { Elem e0(BuildFileStream, "Project"); @@ -725,13 +727,18 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile( : customDir + this->GlobalGenerator ->GetPlatformToolsetCudaVSIntegrationSubdirString() + - "extras\\visual_studio_integration\\MSBuildExtensions\\"; + R"(extras\visual_studio_integration\MSBuildExtensions\)"; Elem(e1, "Import") .Attribute("Project", std::move(cudaPath) + "CUDA " + this->GlobalGenerator->GetPlatformToolsetCuda() + ".props"); } + if (this->GlobalGenerator->IsMarmasmEnabled()) { + Elem(e1, "Import") + .Attribute("Project", + "$(VCTargetsPath)\\BuildCustomizations\\marmasm.props"); + } if (this->GlobalGenerator->IsMasmEnabled()) { Elem(e1, "Import") .Attribute("Project", @@ -823,13 +830,18 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile( : customDir + this->GlobalGenerator ->GetPlatformToolsetCudaVSIntegrationSubdirString() + - "extras\\visual_studio_integration\\MSBuildExtensions\\"; + R"(extras\visual_studio_integration\MSBuildExtensions\)"; Elem(e1, "Import") .Attribute("Project", std::move(cudaPath) + "CUDA " + this->GlobalGenerator->GetPlatformToolsetCuda() + ".targets"); } + if (this->GlobalGenerator->IsMarmasmEnabled()) { + Elem(e1, "Import") + .Attribute("Project", + "$(VCTargetsPath)\\BuildCustomizations\\marmasm.targets"); + } if (this->GlobalGenerator->IsMasmEnabled()) { Elem(e1, "Import") .Attribute("Project", @@ -979,6 +991,8 @@ void cmVisualStudio10TargetGenerator::WriteSdkStyleProjectFile( this->WriteDotNetDocumentationFile(e0); this->WriteAllSources(e0); + this->WriteEmbeddedResourceGroup(e0); + this->WriteXamlFilesGroup(e0); this->WriteDotNetReferences(e0); this->WritePackageReferences(e0); this->WriteProjectReferences(e0); @@ -1020,8 +1034,9 @@ void cmVisualStudio10TargetGenerator::WriteCommonPropertyGroupGlobals(Elem& e1) std::vector<std::string> keys = this->GeneratorTarget->GetPropertyKeys(); for (std::string const& keyIt : keys) { static const cm::string_view prefix = "VS_GLOBAL_"; - if (!cmHasPrefix(keyIt, prefix)) + if (!cmHasPrefix(keyIt, prefix)) { continue; + } cm::string_view globalKey = cm::string_view(keyIt).substr(prefix.length()); // Skip invalid or separately-handled properties. if (globalKey.empty() || globalKey == "PROJECT_TYPES" || @@ -1029,8 +1044,9 @@ void cmVisualStudio10TargetGenerator::WriteCommonPropertyGroupGlobals(Elem& e1) continue; } cmValue value = this->GeneratorTarget->GetProperty(keyIt); - if (!value) + if (!value) { continue; + } e1.Element(globalKey, *value); } } @@ -1043,14 +1059,11 @@ bool cmVisualStudio10TargetGenerator::HasCustomCommands() const return true; } - for (cmGeneratorTarget::AllConfigSource const& si : - this->GeneratorTarget->GetAllConfigSources()) { - if (si.Source->GetCustomCommand()) { - return true; - } - } - - return false; + auto const& config_sources = this->GeneratorTarget->GetAllConfigSources(); + return std::any_of(config_sources.begin(), config_sources.end(), + [](cmGeneratorTarget::AllConfigSource const& si) { + return si.Source->GetCustomCommand(); + }); } void cmVisualStudio10TargetGenerator::WritePackageReferences(Elem& e0) @@ -1220,7 +1233,7 @@ void cmVisualStudio10TargetGenerator::WriteEmbeddedResourceGroup(Elem& e0) e2.Attribute("Include", obj); if (this->ProjectType != VsProjectType::csproj) { - std::string hFileName = obj.substr(0, obj.find_last_of(".")) + ".h"; + std::string hFileName = obj.substr(0, obj.find_last_of('.')) + ".h"; e2.Element("DependentUpon", hFileName); for (std::string const& c : this->Configurations) { @@ -1912,7 +1925,7 @@ void cmVisualStudio10TargetGenerator::WriteGroups() char magic[] = { char(0xEF), char(0xBB), char(0xBF) }; fout.write(magic, 3); - fout << "<?xml version=\"1.0\" encoding=\"" + fout << R"(<?xml version="1.0" encoding=")" << this->GlobalGenerator->Encoding() << "\"?>"; { Elem e0(fout, "Project"); @@ -2068,7 +2081,7 @@ void cmVisualStudio10TargetGenerator::WriteHeaderSource( e2.Element("FileType", "CppForm"); } else if (this->IsXamlHeader(fileName)) { e2.Element("DependentUpon", - fileName.substr(0, fileName.find_last_of("."))); + fileName.substr(0, fileName.find_last_of('.'))); } this->FinishWritingSource(e2, toolSettings); } @@ -2077,7 +2090,7 @@ void cmVisualStudio10TargetGenerator::ParseSettingsProperty( const std::string& settingsPropertyValue, ConfigToSettings& toolSettings) { if (!settingsPropertyValue.empty()) { - cmGeneratorExpression ge; + cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance()); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(settingsPropertyValue); @@ -2104,7 +2117,7 @@ void cmVisualStudio10TargetGenerator::ParseSettingsProperty( bool cmVisualStudio10TargetGenerator::PropertyIsSameInAllConfigs( const ConfigToSettings& toolSettings, const std::string& propName) { - std::string firstPropValue = ""; + std::string firstPropValue; for (const auto& configToSettings : toolSettings) { const std::unordered_map<std::string, std::string>& settings = configToSettings.second; @@ -2177,7 +2190,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource( } // Figure out if there's any additional flags to use if (cmValue saf = sf->GetProperty("VS_SHADER_FLAGS")) { - cmGeneratorExpression ge; + cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance()); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*saf); for (const std::string& config : this->Configurations) { @@ -2190,7 +2203,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource( } // Figure out if debug information should be generated if (cmValue sed = sf->GetProperty("VS_SHADER_ENABLE_DEBUG")) { - cmGeneratorExpression ge; + cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance()); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*sed); for (const std::string& config : this->Configurations) { @@ -2204,7 +2217,7 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource( } // Figure out if optimizations should be disabled if (cmValue sdo = sf->GetProperty("VS_SHADER_DISABLE_OPTIMIZATIONS")) { - cmGeneratorExpression ge; + cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance()); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(*sdo); for (const std::string& config : this->Configurations) { @@ -2318,26 +2331,23 @@ void cmVisualStudio10TargetGenerator::WriteExtraSource( this->FinishWritingSource(e2, toolSettings); if (!deployContent.empty()) { - cmGeneratorExpression ge; + cmGeneratorExpression ge(*this->LocalGenerator->GetCMakeInstance()); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(deployContent); // Deployment location cannot be set on a configuration basis if (!deployLocation.empty()) { e2.Element("Link", deployLocation + "\\%(FileName)%(Extension)"); } - for (size_t i = 0; i != this->Configurations.size(); ++i) { - if (cge->Evaluate(this->LocalGenerator, this->Configurations[i]) == - "1") { + for (auto& config : this->Configurations) { + if (cge->Evaluate(this->LocalGenerator, config) == "1") { e2.WritePlatformConfigTag("DeploymentContent", "'$(Configuration)|$(Platform)'=='" + - this->Configurations[i] + "|" + - this->Platform + "'", + config + "|" + this->Platform + "'", "true"); } else { e2.WritePlatformConfigTag("ExcludedFromBuild", "'$(Configuration)|$(Platform)'=='" + - this->Configurations[i] + "|" + - this->Platform + "'", + config + "|" + this->Platform + "'", "true"); } } @@ -2388,8 +2398,9 @@ void cmVisualStudio10TargetGenerator::WriteSource(Elem& e2, // added with the plain filename without any path. This means the file will // show up at root-level of the csproj (where CMakeLists.txt etc. are). std::string link = this->GetCSharpSourceLink(sf); - if (link.empty()) + if (link.empty()) { link = cmsys::SystemTools::GetFilenameName(sf->GetFullPath()); + } e2.Element("Link", link); } @@ -2485,6 +2496,9 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) const std::string& lang = si.Source->GetLanguage(); if (lang == "C" || lang == "CXX") { tool = "ClCompile"; + } else if (lang == "ASM_MARMASM" && + this->GlobalGenerator->IsMarmasmEnabled()) { + tool = "MARMASM"; } else if (lang == "ASM_MASM" && this->GlobalGenerator->IsMasmEnabled()) { tool = "MASM"; @@ -2519,7 +2533,7 @@ void cmVisualStudio10TargetGenerator::WriteAllSources(Elem& e0) Elem e2(e1, tool); bool isCSharp = (si.Source->GetLanguage() == "CSharp"); - if (isCSharp && exclude_configs.size() > 0) { + if (isCSharp && !exclude_configs.empty()) { std::stringstream conditions; bool firstConditionSet{ false }; for (const auto& ci : include_configs) { @@ -2661,7 +2675,7 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( ? "C" : this->GlobalGenerator->GetLanguageFromExtension(ext.c_str()); std::string lang = this->LocalGenerator->GetSourceFileLanguage(sf); - const char* compileAs = 0; + const char* compileAs = nullptr; if (lang != extLang) { if (lang == "CXX") { // force a C++ file type @@ -2699,6 +2713,8 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( } for (std::string const& config : this->Configurations) { + this->GeneratorTarget->NeedCxxModuleSupport(lang, config); + std::string configUpper = cmSystemTools::UpperCase(config); std::string configDefines = defines; std::string defPropName = cmStrCat("COMPILE_DEFINITIONS_", configUpper); @@ -2711,6 +2727,31 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( configDefines += *ccdefs; } + bool const shouldScanForModules = lang == "CXX"_s && + this->GeneratorTarget->NeedDyndepForSource(lang, config, source); + auto const* fs = + this->GeneratorTarget->GetFileSetForSource(config, source); + const char* compileAsPerConfig = compileAs; + if (fs && + (fs->GetType() == "CXX_MODULES"_s || + fs->GetType() == "CXX_MODULE_HEADER_UNITS"_s)) { + if (lang == "CXX"_s) { + if (fs->GetType() == "CXX_MODULES"_s) { + compileAsPerConfig = "CompileAsCppModule"; + } else { + compileAsPerConfig = "CompileAsHeaderUnit"; + } + } else { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat( + "Target \"", this->GeneratorTarget->Target->GetName(), + "\" contains the source\n ", source->GetFullPath(), + "\nin a file set of type \"", fs->GetType(), + R"(" but the source is not classified as a "CXX" source.)")); + } + } + // We have pch state in the following situation: // 1. We have SKIP_PRECOMPILE_HEADERS == true // 2. We are creating the pre-compiled header @@ -2733,13 +2774,16 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( // if we have flags or defines for this config then // use them if (!flags.empty() || !options.empty() || !configDefines.empty() || - !includes.empty() || compileAs || noWinRT || !options.empty() || - needsPCHFlags) { + !includes.empty() || compileAsPerConfig || noWinRT || + !options.empty() || needsPCHFlags) { cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; cmIDEFlagTable const* flagtable = nullptr; const std::string& srclang = source->GetLanguage(); if (srclang == "C" || srclang == "CXX") { flagtable = gg->GetClFlagTable(); + } else if (srclang == "ASM_MARMASM" && + this->GlobalGenerator->IsMarmasmEnabled()) { + flagtable = gg->GetMarmasmFlagTable(); } else if (srclang == "ASM_MASM" && this->GlobalGenerator->IsMasmEnabled()) { flagtable = gg->GetMasmFlagTable(); @@ -2756,8 +2800,13 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( cmVS10GeneratorOptions clOptions( this->LocalGenerator, cmVisualStudioGeneratorOptions::Compiler, flagtable, this); - if (compileAs) { - clOptions.AddFlag("CompileAs", compileAs); + if (compileAsPerConfig) { + clOptions.AddFlag("CompileAs", compileAsPerConfig); + } + if (shouldScanForModules) { + clOptions.AddFlag("ScanSourceforModuleDependencies", "true"); + } else { + clOptions.AddFlag("ScanSourceforModuleDependencies", "false"); } if (noWinRT) { clOptions.AddFlag("CompileAsWinRT", "false"); @@ -2842,10 +2891,9 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( if (this->IsXamlSource(source->GetFullPath())) { const std::string& fileName = source->GetFullPath(); e2.Element("DependentUpon", - fileName.substr(0, fileName.find_last_of("."))); + fileName.substr(0, fileName.find_last_of('.'))); } if (this->ProjectType == VsProjectType::csproj) { - std::string f = source->GetFullPath(); using CsPropMap = std::map<std::string, std::string>; CsPropMap sourceFileTags; this->GetCSharpSourceProperties(&sf, sourceFileTags); @@ -2886,7 +2934,7 @@ void cmVisualStudio10TargetGenerator::WritePathAndIncrementalLinkOptions( if (ttype >= cmStateEnums::UTILITY) { e1.WritePlatformConfigTag( - "IntDir", cond, "$(Platform)\\$(Configuration)\\$(ProjectName)\\"); + "IntDir", cond, R"($(Platform)\$(Configuration)\$(ProjectName)\)"); } else { std::string intermediateDir = cmStrCat( this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), '/', @@ -3053,12 +3101,9 @@ std::vector<std::string> cmVisualStudio10TargetGenerator::GetIncludes( bool cmVisualStudio10TargetGenerator::ComputeClOptions() { - for (std::string const& c : this->Configurations) { - if (!this->ComputeClOptions(c)) { - return false; - } - } - return true; + return std::all_of( + this->Configurations.begin(), this->Configurations.end(), + [this](std::string const& c) { return this->ComputeClOptions(c); }); } bool cmVisualStudio10TargetGenerator::ComputeClOptions( @@ -3274,6 +3319,8 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( this->GeneratorTarget->GetLanguages(languages, configName); if (languages.count("C")) { std::string flagsC; + this->LocalGenerator->AddLanguageFlags( + flagsC, this->GeneratorTarget, cmBuildStep::Compile, "C", configName); this->LocalGenerator->AddCompileOptions(flagsC, this->GeneratorTarget, "C", configName); Options optC(this->LocalGenerator, Options::Compiler, @@ -3316,9 +3363,12 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( } } - if (this->ProjectType != VsProjectType::csproj && clOptions.IsManaged()) { + if (this->ProjectType != VsProjectType::csproj && + (clOptions.IsManaged() || clOptions.HasFlag("CLRSupport"))) { this->Managed = true; - std::string managedType = clOptions.GetFlag("CompileAsManaged"); + std::string managedType = clOptions.HasFlag("CompileAsManaged") + ? clOptions.GetFlag("CompileAsManaged") + : "Mixed"; if (managedType == "Safe" || managedType == "Pure") { // force empty calling convention if safe clr is used clOptions.AddFlag("CallingConvention", ""); @@ -3411,7 +3461,7 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( // add AdditionalUsingDirectories if (this->AdditionalUsingDirectories.count(configName) > 0) { std::string dirs; - for (auto u : this->AdditionalUsingDirectories[configName]) { + for (auto const& u : this->AdditionalUsingDirectories[configName]) { if (!dirs.empty()) { dirs.append(";"); } @@ -3424,12 +3474,9 @@ void cmVisualStudio10TargetGenerator::WriteClOptions( bool cmVisualStudio10TargetGenerator::ComputeRcOptions() { - for (std::string const& c : this->Configurations) { - if (!this->ComputeRcOptions(c)) { - return false; - } - } - return true; + return std::all_of( + this->Configurations.begin(), this->Configurations.end(), + [this](std::string const& c) { return this->ComputeRcOptions(c); }); } bool cmVisualStudio10TargetGenerator::ComputeRcOptions( @@ -3478,13 +3525,12 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions() if (!this->GlobalGenerator->IsCudaEnabled()) { return true; } - for (std::string const& c : this->Configurations) { - if (this->GeneratorTarget->IsLanguageUsed("CUDA", c) && - !this->ComputeCudaOptions(c)) { - return false; - } - } - return true; + return std::all_of(this->Configurations.begin(), this->Configurations.end(), + [this](std::string const& c) { + return !this->GeneratorTarget->IsLanguageUsed("CUDA", + c) || + this->ComputeCudaOptions(c); + }); } bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( @@ -3570,7 +3616,7 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( // limitation by creating the directory and passing the flag ourselves. pdb = this->ConvertPath(pdb, true); ConvertToWindowsSlash(pdb); - std::string const clFd = "-Xcompiler=\"-Fd\\\"" + pdb + "\\\"\""; + std::string const clFd = R"(-Xcompiler="-Fd\")" + pdb + R"(\"")"; cudaOptions.AppendFlagString("AdditionalOptions", clFd); } } @@ -3654,12 +3700,9 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions() if (!this->GlobalGenerator->IsCudaEnabled()) { return true; } - for (std::string const& c : this->Configurations) { - if (!this->ComputeCudaLinkOptions(c)) { - return false; - } - } - return true; + return std::all_of( + this->Configurations.begin(), this->Configurations.end(), + [this](std::string const& c) { return this->ComputeCudaLinkOptions(c); }); } bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions( @@ -3748,17 +3791,64 @@ void cmVisualStudio10TargetGenerator::WriteCudaLinkOptions( cudaLinkOptions.OutputFlagMap(); } +bool cmVisualStudio10TargetGenerator::ComputeMarmasmOptions() +{ + if (!this->GlobalGenerator->IsMarmasmEnabled()) { + return true; + } + return std::all_of( + this->Configurations.begin(), this->Configurations.end(), + [this](std::string const& c) { return this->ComputeMarmasmOptions(c); }); +} + +bool cmVisualStudio10TargetGenerator::ComputeMarmasmOptions( + std::string const& configName) +{ + cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; + auto pOptions = cm::make_unique<Options>( + this->LocalGenerator, Options::MarmasmCompiler, gg->GetMarmasmFlagTable()); + Options& marmasmOptions = *pOptions; + + std::string flags; + this->LocalGenerator->AddLanguageFlags(flags, this->GeneratorTarget, + cmBuildStep::Compile, "ASM_MARMASM", + configName); + + marmasmOptions.Parse(flags); + + // Get includes for this target + marmasmOptions.AddIncludes(this->GetIncludes(configName, "ASM_MARMASM")); + + this->MarmasmOptions[configName] = std::move(pOptions); + return true; +} + +void cmVisualStudio10TargetGenerator::WriteMarmasmOptions( + Elem& e1, std::string const& configName) +{ + if (!this->MSTools || !this->GlobalGenerator->IsMarmasmEnabled()) { + return; + } + Elem e2(e1, "MARMASM"); + + // Preprocessor definitions and includes are shared with clOptions. + OptionsHelper clOptions(*(this->ClOptions[configName]), e2); + clOptions.OutputPreprocessorDefinitions("ASM_MARMASM"); + + OptionsHelper marmasmOptions(*(this->MarmasmOptions[configName]), e2); + marmasmOptions.OutputAdditionalIncludeDirectories("ASM_MARMASM"); + marmasmOptions.PrependInheritedString("AdditionalOptions"); + marmasmOptions.OutputFlagMap(); +} + bool cmVisualStudio10TargetGenerator::ComputeMasmOptions() { if (!this->GlobalGenerator->IsMasmEnabled()) { return true; } - for (std::string const& c : this->Configurations) { - if (!this->ComputeMasmOptions(c)) { - return false; - } - } - return true; + return std::all_of( + this->Configurations.begin(), this->Configurations.end(), + [this](std::string const& c) { return this->ComputeMasmOptions(c); }); } bool cmVisualStudio10TargetGenerator::ComputeMasmOptions( @@ -3810,12 +3900,9 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions() if (!this->GlobalGenerator->IsNasmEnabled()) { return true; } - for (std::string const& c : this->Configurations) { - if (!this->ComputeNasmOptions(c)) { - return false; - } - } - return true; + return std::all_of( + this->Configurations.begin(), this->Configurations.end(), + [this](std::string const& c) { return this->ComputeNasmOptions(c); }); } bool cmVisualStudio10TargetGenerator::ComputeNasmOptions( @@ -4452,6 +4539,7 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups(Elem& e0) // output rc compile flags <ResourceCompile></ResourceCompile> this->WriteRCOptions(e1, c); this->WriteCudaOptions(e1, c); + this->WriteMarmasmOptions(e1, c); this->WriteMasmOptions(e1, c); this->WriteNasmOptions(e1, c); } diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 17dcecd..166cdf7 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -132,6 +132,9 @@ private: bool ComputeCudaLinkOptions(std::string const& config); void WriteCudaLinkOptions(Elem& e1, std::string const& config); + bool ComputeMarmasmOptions(); + bool ComputeMarmasmOptions(std::string const& config); + void WriteMarmasmOptions(Elem& e1, std::string const& config); bool ComputeMasmOptions(); bool ComputeMasmOptions(std::string const& config); void WriteMasmOptions(Elem& e1, std::string const& config); @@ -200,7 +203,6 @@ private: void WriteStdOutEncodingUtf8(Elem& e1); void UpdateCache(); -private: friend class cmVS10GeneratorOptions; using Options = cmVS10GeneratorOptions; using OptionsMap = std::map<std::string, std::unique_ptr<Options>>; @@ -208,6 +210,7 @@ private: OptionsMap RcOptions; OptionsMap CudaOptions; OptionsMap CudaLinkOptions; + OptionsMap MarmasmOptions; OptionsMap MasmOptions; OptionsMap NasmOptions; OptionsMap LinkOptions; diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index e6f5ece..6e98874 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -51,9 +51,9 @@ cmVisualStudioGeneratorOptions::cmVisualStudioGeneratorOptions( void cmVisualStudioGeneratorOptions::AddTable(cmVS7FlagTable const* table) { if (table) { - for (int i = 0; i < FlagTableCount; ++i) { - if (!this->FlagTable[i]) { - this->FlagTable[i] = table; + for (auto& flag : this->FlagTable) { + if (!flag) { + flag = table; break; } } @@ -62,8 +62,8 @@ void cmVisualStudioGeneratorOptions::AddTable(cmVS7FlagTable const* table) void cmVisualStudioGeneratorOptions::ClearTables() { - for (int i = 0; i < FlagTableCount; ++i) { - this->FlagTable[i] = nullptr; + for (auto& flag : this->FlagTable) { + flag = nullptr; } } @@ -115,8 +115,7 @@ bool cmVisualStudioGeneratorOptions::IsDebug() const if (this->CurrentTool != CSharpCompiler) { return this->FlagMap.find("DebugInformationFormat") != this->FlagMap.end(); } - std::map<std::string, FlagValue>::const_iterator i = - this->FlagMap.find("DebugType"); + auto i = this->FlagMap.find("DebugType"); if (i != this->FlagMap.end()) { if (i->second.size() == 1) { return i->second[0] != "none"; @@ -138,22 +137,14 @@ bool cmVisualStudioGeneratorOptions::IsManaged() const bool cmVisualStudioGeneratorOptions::UsingUnicode() const { // Look for a _UNICODE definition. - for (std::string const& di : this->Defines) { - if (di == "_UNICODE") { - return true; - } - } - return false; + return std::any_of(this->Defines.begin(), this->Defines.end(), + [](std::string const& di) { return di == "_UNICODE"; }); } bool cmVisualStudioGeneratorOptions::UsingSBCS() const { // Look for a _SBCS definition. - for (std::string const& di : this->Defines) { - if (di == "_SBCS") { - return true; - } - } - return false; + return std::any_of(this->Defines.begin(), this->Defines.end(), + [](std::string const& di) { return di == "_SBCS"; }); } void cmVisualStudioGeneratorOptions::FixCudaCodeGeneration() @@ -267,8 +258,7 @@ void cmVisualStudioGeneratorOptions::ParseFinish() } if (this->CurrentTool == CudaCompiler) { - std::map<std::string, FlagValue>::iterator i = - this->FlagMap.find("CudaRuntime"); + auto i = this->FlagMap.find("CudaRuntime"); if (i != this->FlagMap.end() && i->second.size() == 1) { std::string& cudaRuntime = i->second[0]; if (cudaRuntime == "static") { @@ -285,7 +275,7 @@ void cmVisualStudioGeneratorOptions::ParseFinish() void cmVisualStudioGeneratorOptions::PrependInheritedString( std::string const& key) { - std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(key); + auto i = this->FlagMap.find(key); if (i == this->FlagMap.end() || i->second.size() != 1) { return; } @@ -295,7 +285,7 @@ void cmVisualStudioGeneratorOptions::PrependInheritedString( void cmVisualStudioGeneratorOptions::Reparse(std::string const& key) { - std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(key); + auto i = this->FlagMap.find(key); if (i == this->FlagMap.end() || i->second.size() != 1) { return; } @@ -339,7 +329,7 @@ cmIDEOptions::FlagValue cmVisualStudioGeneratorOptions::TakeFlag( std::string const& key) { FlagValue value; - std::map<std::string, FlagValue>::iterator i = this->FlagMap.find(key); + auto i = this->FlagMap.find(key); if (i != this->FlagMap.end()) { value = i->second; this->FlagMap.erase(i); @@ -373,8 +363,7 @@ void cmVisualStudioGeneratorOptions::OutputPreprocessorDefinitions( if (this->Version != cmGlobalVisualStudioGenerator::VSVersion::VS9) { oss << "%(" << tag << ")"; } - std::vector<std::string>::const_iterator de = - cmRemoveDuplicates(this->Defines); + auto de = cmRemoveDuplicates(this->Defines); for (std::string const& di : cmMakeRange(this->Defines.cbegin(), de)) { // Escape the definition for the compiler. std::string define; diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index ed4ee1d..20e2d22 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -24,6 +24,7 @@ public: Compiler, ResourceCompiler, CudaCompiler, + MarmasmCompiler, MasmCompiler, NasmCompiler, Linker, diff --git a/Source/cmVisualStudioSlnData.cxx b/Source/cmVisualStudioSlnData.cxx index 2a6dfc4..4b6754e 100644 --- a/Source/cmVisualStudioSlnData.cxx +++ b/Source/cmVisualStudioSlnData.cxx @@ -20,33 +20,34 @@ std::string cmSlnProjectEntry::GetProjectConfiguration( return projectConfigurationMap[solutionConfiguration]; } -const cm::optional<cmSlnProjectEntry> cmSlnData::GetProjectByGUID( +cm::optional<cmSlnProjectEntry> cmSlnData::GetProjectByGUID( const std::string& projectGUID) const { - ProjectStorage::const_iterator it(ProjectsByGUID.find(projectGUID)); - if (it != ProjectsByGUID.end()) + auto it(ProjectsByGUID.find(projectGUID)); + if (it != ProjectsByGUID.end()) { return it->second; - else - return cm::nullopt; + } + return cm::nullopt; } -const cm::optional<cmSlnProjectEntry> cmSlnData::GetProjectByName( +cm::optional<cmSlnProjectEntry> cmSlnData::GetProjectByName( const std::string& projectName) const { - ProjectStringIndex::const_iterator it(ProjectNameIndex.find(projectName)); - if (it != ProjectNameIndex.end()) + auto it(ProjectNameIndex.find(projectName)); + if (it != ProjectNameIndex.end()) { return it->second->second; - else - return cm::nullopt; + } + return cm::nullopt; } std::vector<cmSlnProjectEntry> cmSlnData::GetProjects() const { - ProjectStringIndex::const_iterator it(this->ProjectNameIndex.begin()), - itEnd(this->ProjectNameIndex.end()); + auto it(this->ProjectNameIndex.begin()); + auto itEnd(this->ProjectNameIndex.end()); std::vector<cmSlnProjectEntry> result; - for (; it != itEnd; ++it) + for (; it != itEnd; ++it) { result.push_back(it->second->second); + } return result; } @@ -54,9 +55,10 @@ cmSlnProjectEntry* cmSlnData::AddProject( const std::string& projectGUID, const std::string& projectName, const std::string& projectRelativePath) { - ProjectStorage::iterator it(ProjectsByGUID.find(projectGUID)); - if (it != ProjectsByGUID.end()) - return NULL; + auto it(ProjectsByGUID.find(projectGUID)); + if (it != ProjectsByGUID.end()) { + return nullptr; + } it = ProjectsByGUID .insert(ProjectStorage::value_type( projectGUID, @@ -72,17 +74,20 @@ std::string cmSlnData::GetConfigurationTarget( { std::string solutionTarget = solutionConfiguration + "|" + platformName; cm::optional<cmSlnProjectEntry> project = GetProjectByName(projectName); - if (!project) + if (!project) { return platformName; + } std::string projectTarget = project->GetProjectConfiguration(solutionTarget); - if (projectTarget.empty()) + if (projectTarget.empty()) { return platformName; + } std::vector<std::string> targetElements = cmSystemTools::SplitString(projectTarget, '|'); - if (targetElements.size() != 2) + if (targetElements.size() != 2) { return platformName; + } return targetElements[1]; } diff --git a/Source/cmVisualStudioSlnData.h b/Source/cmVisualStudioSlnData.h index 100dd9b..5f03895 100644 --- a/Source/cmVisualStudioSlnData.h +++ b/Source/cmVisualStudioSlnData.h @@ -13,12 +13,12 @@ class cmSlnProjectEntry { public: - cmSlnProjectEntry() {} - cmSlnProjectEntry(const std::string& guid, const std::string& name, - const std::string& relativePath) - : Guid(guid) - , Name(name) - , RelativePath(relativePath) + cmSlnProjectEntry() = default; + cmSlnProjectEntry(std::string guid, std::string name, + std::string relativePath) + : Guid(std::move(guid)) + , Name(std::move(name)) + , RelativePath(std::move(relativePath)) { } @@ -56,10 +56,10 @@ public: minimumVisualStudioVersion = version; } - const cm::optional<cmSlnProjectEntry> GetProjectByGUID( + cm::optional<cmSlnProjectEntry> GetProjectByGUID( const std::string& projectGUID) const; - const cm::optional<cmSlnProjectEntry> GetProjectByName( + cm::optional<cmSlnProjectEntry> GetProjectByName( const std::string& projectName) const; std::vector<cmSlnProjectEntry> GetProjects() const; diff --git a/Source/cmVisualStudioSlnParser.cxx b/Source/cmVisualStudioSlnParser.cxx index feab895..71c758e 100644 --- a/Source/cmVisualStudioSlnParser.cxx +++ b/Source/cmVisualStudioSlnParser.cxx @@ -80,19 +80,19 @@ bool cmVisualStudioSlnParser::ParsedLine::IsKeyValuePair() const std::string cmVisualStudioSlnParser::ParsedLine::GetArgVerbatim() const { - if (this->Arg.second) + if (this->Arg.second) { return Quote + this->Arg.first + Quote; - else - return this->Arg.first; + } + return this->Arg.first; } const std::string& cmVisualStudioSlnParser::ParsedLine::GetValue( size_t idxValue) const { - if (idxValue < this->Values.size()) + if (idxValue < this->Values.size()) { return this->Values[idxValue].first; - else - return BadString; + } + return BadString; } std::string cmVisualStudioSlnParser::ParsedLine::GetValueVerbatim( @@ -100,12 +100,12 @@ std::string cmVisualStudioSlnParser::ParsedLine::GetValueVerbatim( { if (idxValue < this->Values.size()) { const StringData& data = this->Values[idxValue]; - if (data.second) + if (data.second) { return Quote + data.first + Quote; - else - return data.first; - } else - return BadString; + } + return data.first; + } + return BadString; } class cmVisualStudioSlnParser::State @@ -140,17 +140,17 @@ private: std::stack<FileState> Stack; std::string EndIgnoreTag; DataGroupSet RequestedData; - size_t CurrentLine; + size_t CurrentLine = 0; void IgnoreUntilTag(const std::string& endTag); }; cmVisualStudioSlnParser::State::State(DataGroupSet requestedData) : RequestedData(requestedData) - , CurrentLine(0) { - if (this->RequestedData.test(DataGroupProjectDependenciesBit)) + if (this->RequestedData.test(DataGroupProjectDependenciesBit)) { this->RequestedData.set(DataGroupProjectsBit); + } this->Stack.push(FileStateStart); } @@ -206,7 +206,7 @@ bool cmVisualStudioSlnParser::State::Process( this->Stack.push(FileStateTopLevel); break; case FileStateTopLevel: - if (line.GetTag().compare("Project") == 0) { + if (line.GetTag() == "Project") { if (line.GetValueCount() != 3) { result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); return false; @@ -218,14 +218,15 @@ bool cmVisualStudioSlnParser::State::Process( return false; } this->Stack.push(FileStateProject); - } else + } else { this->IgnoreUntilTag("EndProject"); - } else if (line.GetTag().compare("Global") == 0) { + } + } else if (line.GetTag() == "Global") { this->Stack.push(FileStateGlobal); - } else if (line.GetTag().compare("VisualStudioVersion") == 0) { + } else if (line.GetTag() == "VisualStudioVersion") { output.SetVisualStudioVersion(line.GetValue(0)); - } else if (line.GetTag().compare("MinimumVisualStudioVersion") == 0) { + } else if (line.GetTag() == "MinimumVisualStudioVersion") { output.SetMinimumVisualStudioVersion(line.GetValue(0)); } else { result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); @@ -233,69 +234,75 @@ bool cmVisualStudioSlnParser::State::Process( } break; case FileStateProject: - if (line.GetTag().compare("EndProject") == 0) + if (line.GetTag() == "EndProject") { this->Stack.pop(); - else if (line.GetTag().compare("ProjectSection") == 0) { - if (line.GetArg().compare("ProjectDependencies") == 0 && - line.GetValue(0).compare("postProject") == 0) { - if (this->RequestedData.test(DataGroupProjectDependenciesBit)) + } else if (line.GetTag() == "ProjectSection") { + if (line.GetArg() == "ProjectDependencies" && + line.GetValue(0) == "postProject") { + if (this->RequestedData.test(DataGroupProjectDependenciesBit)) { this->Stack.push(FileStateProjectDependencies); - else + } else { this->IgnoreUntilTag("EndProjectSection"); - } else + } + } else { this->IgnoreUntilTag("EndProjectSection"); + } } else { result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); return false; } break; case FileStateProjectDependencies: - if (line.GetTag().compare("EndProjectSection") == 0) + if (line.GetTag() == "EndProjectSection") { this->Stack.pop(); - else if (line.IsKeyValuePair()) + } else if (line.IsKeyValuePair()) { // implement dependency storing here, once needed ; - else { + } else { result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); return false; } break; case FileStateGlobal: - if (line.GetTag().compare("EndGlobal") == 0) + if (line.GetTag() == "EndGlobal") { this->Stack.pop(); - else if (line.GetTag().compare("GlobalSection") == 0) { - if (line.GetArg().compare("SolutionConfigurationPlatforms") == 0 && - line.GetValue(0).compare("preSolution") == 0) { - if (this->RequestedData.test(DataGroupSolutionConfigurationsBit)) + } else if (line.GetTag() == "GlobalSection") { + if (line.GetArg() == "SolutionConfigurationPlatforms" && + line.GetValue(0) == "preSolution") { + if (this->RequestedData.test(DataGroupSolutionConfigurationsBit)) { this->Stack.push(FileStateSolutionConfigurations); - else + } else { this->IgnoreUntilTag("EndGlobalSection"); - } else if (line.GetArg().compare("ProjectConfigurationPlatforms") == - 0 && - line.GetValue(0).compare("postSolution") == 0) { - if (this->RequestedData.test(DataGroupProjectConfigurationsBit)) + } + } else if (line.GetArg() == "ProjectConfigurationPlatforms" && + line.GetValue(0) == "postSolution") { + if (this->RequestedData.test(DataGroupProjectConfigurationsBit)) { this->Stack.push(FileStateProjectConfigurations); - else + } else { this->IgnoreUntilTag("EndGlobalSection"); - } else if (line.GetArg().compare("NestedProjects") == 0 && - line.GetValue(0).compare("preSolution") == 0) { - if (this->RequestedData.test(DataGroupSolutionFiltersBit)) + } + } else if (line.GetArg() == "NestedProjects" && + line.GetValue(0) == "preSolution") { + if (this->RequestedData.test(DataGroupSolutionFiltersBit)) { this->Stack.push(FileStateSolutionFilters); - else + } else { this->IgnoreUntilTag("EndGlobalSection"); - } else if (this->RequestedData.test(DataGroupGenericGlobalSectionsBit)) + } + } else if (this->RequestedData.test( + DataGroupGenericGlobalSectionsBit)) { this->Stack.push(FileStateGlobalSection); - else + } else { this->IgnoreUntilTag("EndGlobalSection"); + } } else { result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); return false; } break; case FileStateSolutionConfigurations: - if (line.GetTag().compare("EndGlobalSection") == 0) + if (line.GetTag() == "EndGlobalSection") { this->Stack.pop(); - else if (line.IsKeyValuePair()) { + } else if (line.IsKeyValuePair()) { output.AddConfiguration(line.GetValue(0)); } else { result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); @@ -303,9 +310,9 @@ bool cmVisualStudioSlnParser::State::Process( } break; case FileStateProjectConfigurations: - if (line.GetTag().compare("EndGlobalSection") == 0) + if (line.GetTag() == "EndGlobalSection") { this->Stack.pop(); - else if (line.IsKeyValuePair()) { + } else if (line.IsKeyValuePair()) { std::vector<std::string> tagElements = cmSystemTools::SplitString(line.GetTag(), '.'); if (tagElements.size() != 3 && tagElements.size() != 4) { @@ -324,7 +331,7 @@ bool cmVisualStudioSlnParser::State::Process( return false; } - if (activeBuild.compare("ActiveCfg") == 0) { + if (activeBuild == "ActiveCfg") { projectEntry->AddProjectConfiguration(solutionConfiguration, line.GetValue(0)); } @@ -334,23 +341,23 @@ bool cmVisualStudioSlnParser::State::Process( } break; case FileStateSolutionFilters: - if (line.GetTag().compare("EndGlobalSection") == 0) + if (line.GetTag() == "EndGlobalSection") { this->Stack.pop(); - else if (line.IsKeyValuePair()) + } else if (line.IsKeyValuePair()) { // implement filter storing here, once needed ; - else { + } else { result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); return false; } break; case FileStateGlobalSection: - if (line.GetTag().compare("EndGlobalSection") == 0) + if (line.GetTag() == "EndGlobalSection") { this->Stack.pop(); - else if (line.IsKeyValuePair()) + } else if (line.IsKeyValuePair()) { // implement section storing here, once needed ; - else { + } else { result.SetError(ResultErrorInputStructure, this->GetCurrentLine()); return false; } @@ -385,11 +392,7 @@ void cmVisualStudioSlnParser::State::IgnoreUntilTag(const std::string& endTag) this->EndIgnoreTag = endTag; } -cmVisualStudioSlnParser::ResultData::ResultData() - : Result(ResultOK) - , ResultLine(0) -{ -} +cmVisualStudioSlnParser::ResultData::ResultData() = default; void cmVisualStudioSlnParser::ResultData::Clear() { @@ -487,34 +490,41 @@ bool cmVisualStudioSlnParser::ParseImpl(std::istream& input, cmSlnData& output, { std::string line; // Does the .sln start with a Byte Order Mark? - if (!this->ParseBOM(input, line, state)) + if (!this->ParseBOM(input, line, state)) { return false; + } do { line = cmTrimWhitespace(line); - if (line.empty()) + if (line.empty()) { continue; + } ParsedLine parsedLine; switch (state.NextLineFormat()) { case LineMultiValueTag: - if (!this->ParseMultiValueTag(line, parsedLine, state)) + if (!this->ParseMultiValueTag(line, parsedLine, state)) { return false; + } break; case LineSingleValueTag: - if (!this->ParseSingleValueTag(line, parsedLine, state)) + if (!this->ParseSingleValueTag(line, parsedLine, state)) { return false; + } break; case LineKeyValuePair: - if (!this->ParseKeyValuePair(line, parsedLine, state)) + if (!this->ParseKeyValuePair(line, parsedLine, state)) { return false; + } break; case LineVerbatim: parsedLine.CopyVerbatim(line); break; } - if (parsedLine.IsComment()) + if (parsedLine.IsComment()) { continue; - if (!state.Process(parsedLine, output, this->LastResult)) + } + if (!state.Process(parsedLine, output, this->LastResult)) { return false; + } } while (state.ReadLine(input, line)); return state.Finished(this->LastResult); } @@ -533,8 +543,9 @@ bool cmVisualStudioSlnParser::ParseBOM(std::istream& input, std::string& line, this->LastResult.SetError(ResultErrorReadingInput, 1); return false; } - if (!this->LastResult.HadBOM) + if (!this->LastResult.HadBOM) { line = bom + line; // it wasn't a BOM, prepend it to first line + } return true; } @@ -544,9 +555,10 @@ bool cmVisualStudioSlnParser::ParseMultiValueTag(const std::string& line, { size_t idxEqualSign = line.find('='); auto fullTag = cm::string_view(line).substr(0, idxEqualSign); - if (!this->ParseTag(fullTag, parsedLine, state)) + if (!this->ParseTag(fullTag, parsedLine, state)) { return false; - if (idxEqualSign != line.npos) { + } + if (idxEqualSign != std::string::npos) { size_t idxFieldStart = idxEqualSign + 1; if (idxFieldStart < line.size()) { size_t idxParsing = idxFieldStart; @@ -554,24 +566,27 @@ bool cmVisualStudioSlnParser::ParseMultiValueTag(const std::string& line, for (;;) { idxParsing = line.find_first_of(",\"", idxParsing); bool fieldOver = false; - if (idxParsing == line.npos) { + if (idxParsing == std::string::npos) { fieldOver = true; if (inQuotes) { this->LastResult.SetError(ResultErrorInputStructure, state.GetCurrentLine()); return false; } - } else if (line[idxParsing] == ',' && !inQuotes) + } else if (line[idxParsing] == ',' && !inQuotes) { fieldOver = true; - else if (line[idxParsing] == '"') + } else if (line[idxParsing] == '"') { inQuotes = !inQuotes; + } if (fieldOver) { if (!this->ParseValue( line.substr(idxFieldStart, idxParsing - idxFieldStart), - parsedLine)) + parsedLine)) { return false; - if (idxParsing == line.npos) + } + if (idxParsing == std::string::npos) { break; // end of last field + } idxFieldStart = idxParsing + 1; } ++idxParsing; @@ -587,11 +602,13 @@ bool cmVisualStudioSlnParser::ParseSingleValueTag(const std::string& line, { size_t idxEqualSign = line.find('='); auto fullTag = cm::string_view(line).substr(0, idxEqualSign); - if (!this->ParseTag(fullTag, parsedLine, state)) + if (!this->ParseTag(fullTag, parsedLine, state)) { return false; - if (idxEqualSign != line.npos) { - if (!this->ParseValue(line.substr(idxEqualSign + 1), parsedLine)) + } + if (idxEqualSign != std::string::npos) { + if (!this->ParseValue(line.substr(idxEqualSign + 1), parsedLine)) { return false; + } } return true; } @@ -601,7 +618,7 @@ bool cmVisualStudioSlnParser::ParseKeyValuePair(const std::string& line, State& /*state*/) { size_t idxEqualSign = line.find('='); - if (idxEqualSign == line.npos) { + if (idxEqualSign == std::string::npos) { parsedLine.CopyVerbatim(line); return true; } @@ -636,8 +653,9 @@ bool cmVisualStudioSlnParser::ParseTag(cm::string_view fullTag, return false; } parsedLine.SetQuotedArg(arg.substr(1, arg.size() - 2)); - } else + } else { parsedLine.SetArg(arg); + } return true; } @@ -645,11 +663,12 @@ bool cmVisualStudioSlnParser::ParseValue(const std::string& value, ParsedLine& parsedLine) { const std::string& trimmed = cmTrimWhitespace(value); - if (trimmed.empty()) + if (trimmed.empty()) { parsedLine.AddValue(trimmed); - else if (trimmed.front() == '"' && trimmed.back() == '"') + } else if (trimmed.front() == '"' && trimmed.back() == '"') { parsedLine.AddQuotedValue(trimmed.substr(1, trimmed.size() - 2)); - else + } else { parsedLine.AddValue(trimmed); + } return true; } diff --git a/Source/cmVisualStudioSlnParser.h b/Source/cmVisualStudioSlnParser.h index 60be598..0cac140 100644 --- a/Source/cmVisualStudioSlnParser.h +++ b/Source/cmVisualStudioSlnParser.h @@ -73,8 +73,8 @@ protected: struct ResultData { - ParseResult Result; - size_t ResultLine; + ParseResult Result = ResultOK; + size_t ResultLine = 0; bool HadBOM; ResultData(); diff --git a/Source/cmVisualStudioWCEPlatformParser.cxx b/Source/cmVisualStudioWCEPlatformParser.cxx index 2f71cf5..d8d0da9 100644 --- a/Source/cmVisualStudioWCEPlatformParser.cxx +++ b/Source/cmVisualStudioWCEPlatformParser.cxx @@ -16,9 +16,9 @@ int cmVisualStudioWCEPlatformParser::ParseVersion(const char* version) const std::string vckey = registryBase + "\\Setup\\VC;ProductDir"; const std::string vskey = registryBase + "\\Setup\\VS;ProductDir"; - if (!cmSystemTools::ReadRegistryValue(vckey.c_str(), this->VcInstallDir, + if (!cmSystemTools::ReadRegistryValue(vckey, this->VcInstallDir, cmSystemTools::KeyWOW64_32) || - !cmSystemTools::ReadRegistryValue(vskey.c_str(), this->VsInstallDir, + !cmSystemTools::ReadRegistryValue(vskey, this->VsInstallDir, cmSystemTools::KeyWOW64_32)) { return 0; } @@ -44,13 +44,12 @@ std::string cmVisualStudioWCEPlatformParser::GetOSVersion() const const char* cmVisualStudioWCEPlatformParser::GetArchitectureFamily() const { - std::map<std::string, std::string>::const_iterator it = - this->Macros.find("ARCHFAM"); + auto it = this->Macros.find("ARCHFAM"); if (it != this->Macros.end()) { return it->second.c_str(); } - return 0; + return nullptr; } void cmVisualStudioWCEPlatformParser::StartElement(const std::string& name, diff --git a/Source/cmVisualStudioWCEPlatformParser.h b/Source/cmVisualStudioWCEPlatformParser.h index 2fff91c..895a90d 100644 --- a/Source/cmVisualStudioWCEPlatformParser.h +++ b/Source/cmVisualStudioWCEPlatformParser.h @@ -16,9 +16,8 @@ class cmVisualStudioWCEPlatformParser : public cmXMLParser { public: - cmVisualStudioWCEPlatformParser(const char* name = NULL) + cmVisualStudioWCEPlatformParser(const char* name = nullptr) : RequiredName(name) - , FoundRequiredName(false) { } @@ -42,9 +41,9 @@ public: } protected: - virtual void StartElement(const std::string& name, const char** attributes); - void EndElement(const std::string& name); - void CharacterDataHandler(const char* data, int length); + void StartElement(const std::string& name, const char** attributes) override; + void EndElement(const std::string& name) override; + void CharacterDataHandler(const char* data, int length) override; private: std::string FixPaths(const std::string& paths) const; @@ -61,7 +60,7 @@ private: std::vector<std::string> AvailablePlatforms; const char* RequiredName; - bool FoundRequiredName; + bool FoundRequiredName = false; std::string VcInstallDir; std::string VsInstallDir; }; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 013a87b..0d947a5 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -40,7 +40,6 @@ #include "cmCommands.h" #include "cmDocumentation.h" #include "cmDocumentationEntry.h" -#include "cmDocumentationFormatter.h" #include "cmDuration.h" #include "cmExternalMakefileProjectGenerator.h" #include "cmFileTimeCache.h" @@ -71,6 +70,7 @@ # include <cm3p/curl/curl.h> # include <cm3p/json/writer.h> +# include "cmConfigureLog.h" # include "cmFileAPI.h" # include "cmGraphVizWriter.h" # include "cmVariableWatch.h" @@ -150,21 +150,136 @@ auto IgnoreAndTrueLambda = [](std::string const&, cmake*) -> bool { using CommandArgument = cmCommandLineArgument<bool(std::string const& value, cmake* state)>; -} // namespace - -static bool cmakeCheckStampFile(const std::string& stampName); -static bool cmakeCheckStampList(const std::string& stampList); - #ifndef CMAKE_BOOTSTRAP -static void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/, - void* ctx, const char* /*unused*/, - const cmMakefile* /*unused*/) +void cmWarnUnusedCliWarning(const std::string& variable, int /*unused*/, + void* ctx, const char* /*unused*/, + const cmMakefile* /*unused*/) { cmake* cm = reinterpret_cast<cmake*>(ctx); cm->MarkCliAsUsed(variable); } #endif +bool cmakeCheckStampFile(const std::string& stampName) +{ + // The stamp file does not exist. Use the stamp dependencies to + // determine whether it is really out of date. This works in + // conjunction with cmLocalVisualStudio7Generator to avoid + // repeatedly re-running CMake when the user rebuilds the entire + // solution. + std::string stampDepends = cmStrCat(stampName, ".depend"); +#if defined(_WIN32) || defined(__CYGWIN__) + cmsys::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary); +#else + cmsys::ifstream fin(stampDepends.c_str()); +#endif + if (!fin) { + // The stamp dependencies file cannot be read. Just assume the + // build system is really out of date. + std::cout << "CMake is re-running because " << stampName + << " dependency file is missing.\n"; + return false; + } + + // Compare the stamp dependencies against the dependency file itself. + { + cmFileTimeCache ftc; + std::string dep; + while (cmSystemTools::GetLineFromStream(fin, dep)) { + int result; + if (!dep.empty() && dep[0] != '#' && + (!ftc.Compare(stampDepends, dep, &result) || result < 0)) { + // The stamp depends file is older than this dependency. The + // build system is really out of date. + /* clang-format off */ + std::cout << "CMake is re-running because " << stampName + << " is out-of-date.\n" + " the file '" << dep << "'\n" + " is newer than '" << stampDepends << "'\n" + " result='" << result << "'\n"; + /* clang-format on */ + return false; + } + } + } + + // The build system is up to date. The stamp file has been removed + // by the VS IDE due to a "rebuild" request. Restore it atomically. + std::ostringstream stampTempStream; + stampTempStream << stampName << ".tmp" << cmSystemTools::RandomSeed(); + std::string stampTemp = stampTempStream.str(); + { + // TODO: Teach cmGeneratedFileStream to use a random temp file (with + // multiple tries in unlikely case of conflict) and use that here. + cmsys::ofstream stamp(stampTemp.c_str()); + stamp << "# CMake generation timestamp file for this directory.\n"; + } + std::string err; + if (cmSystemTools::RenameFile(stampTemp, stampName, + cmSystemTools::Replace::Yes, &err) == + cmSystemTools::RenameResult::Success) { + // CMake does not need to re-run because the stamp file is up-to-date. + return true; + } + cmSystemTools::RemoveFile(stampTemp); + cmSystemTools::Error( + cmStrCat("Cannot restore timestamp \"", stampName, "\": ", err)); + return false; +} + +bool cmakeCheckStampList(const std::string& stampList) +{ + // If the stamp list does not exist CMake must rerun to generate it. + if (!cmSystemTools::FileExists(stampList)) { + std::cout << "CMake is re-running because generate.stamp.list " + "is missing.\n"; + return false; + } + cmsys::ifstream fin(stampList.c_str()); + if (!fin) { + std::cout << "CMake is re-running because generate.stamp.list " + "could not be read.\n"; + return false; + } + + // Check each stamp. + std::string stampName; + while (cmSystemTools::GetLineFromStream(fin, stampName)) { + if (!cmakeCheckStampFile(stampName)) { + return false; + } + } + return true; +} + +} // namespace + +cmDocumentationEntry cmake::CMAKE_STANDARD_OPTIONS_TABLE[18] = { + { "-S <path-to-source>", "Explicitly specify a source directory." }, + { "-B <path-to-build>", "Explicitly specify a build directory." }, + { "-C <initial-cache>", "Pre-load a script to populate the cache." }, + { "-D <var>[:<type>]=<value>", "Create or update a cmake cache entry." }, + { "-U <globbing_expr>", "Remove matching entries from CMake cache." }, + { "-G <generator-name>", "Specify a build system generator." }, + { "-T <toolset-name>", "Specify toolset name if supported by generator." }, + { "-A <platform-name>", "Specify platform name if supported by generator." }, + { "--toolchain <file>", "Specify toolchain file [CMAKE_TOOLCHAIN_FILE]." }, + { "--install-prefix <directory>", + "Specify install directory [CMAKE_INSTALL_PREFIX]." }, + { "-Wdev", "Enable developer warnings." }, + { "-Wno-dev", "Suppress developer warnings." }, + { "-Werror=dev", "Make developer warnings errors." }, + { "-Wno-error=dev", "Make developer warnings not errors." }, + { "-Wdeprecated", "Enable deprecation warnings." }, + { "-Wno-deprecated", "Suppress deprecation warnings." }, + { "-Werror=deprecated", + "Make deprecated macro and function warnings " + "errors." }, + { "-Wno-error=deprecated", + "Make deprecated macro and function warnings " + "not errors." } +}; + cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind) : CMakeWorkingDirectory(cmSystemTools::GetCurrentWorkingDirectory()) , FileTimeCache(cm::make_unique<cmFileTimeCache>()) @@ -196,7 +311,7 @@ cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind) this->AddProjectCommands(); } - if (mode == cmState::Project) { + if (mode == cmState::Project || mode == cmState::Help) { this->LoadEnvironmentPresets(); } @@ -1008,7 +1123,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) std::cout << "Running with debug output on for the 'find' commands " "for package(s)"; for (auto const& v : find_pkgs) { - std::cout << " " << v; + std::cout << ' ' << v; state->SetDebugFindOutputPkgs(v); } std::cout << ".\n"; @@ -1021,7 +1136,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) std::vector<std::string> find_vars(cmTokenize(value, ",")); std::cout << "Running with debug output on for the variable(s)"; for (auto const& v : find_vars) { - std::cout << " " << v; + std::cout << ' ' << v; state->SetDebugFindOutputVars(v); } std::cout << ".\n"; @@ -1082,7 +1197,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) [](std::string const&, cmake* state) -> bool { std::cout << "Not searching for unused variables given on the " - << "command line.\n"; + "command line.\n"; state->SetWarnUnusedCli(false); return true; } }, @@ -1090,7 +1205,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) "--check-system-vars", CommandArgument::Values::Zero, [](std::string const&, cmake* state) -> bool { std::cout << "Also check system files when warning about unused and " - << "uninitialized variables.\n"; + "uninitialized variables.\n"; state->SetCheckSystemVars(true); return true; } }, @@ -1098,7 +1213,7 @@ void cmake::SetArgs(const std::vector<std::string>& args) "--compile-no-warning-as-error", CommandArgument::Values::Zero, [](std::string const&, cmake* state) -> bool { std::cout << "Ignoring COMPILE_WARNING_AS_ERROR target property and " - << "CMAKE_COMPILE_WARNING_AS_ERROR variable.\n"; + "CMAKE_COMPILE_WARNING_AS_ERROR variable.\n"; state->SetIgnoreWarningAsError(true); return true; } } @@ -1497,7 +1612,7 @@ void cmake::SetTraceFile(const std::string& file) cmSystemTools::Error(ss.str()); return; } - std::cout << "Trace will be written to " << file << "\n"; + std::cout << "Trace will be written to " << file << '\n'; } void cmake::PrintTraceFormatVersion() @@ -1542,6 +1657,16 @@ void cmake::PrintTraceFormatVersion() } } +void cmake::SetTraceRedirect(cmake* other) +{ + this->Trace = other->Trace; + this->TraceExpand = other->TraceExpand; + this->TraceFormatVar = other->TraceFormatVar; + this->TraceOnlyThisSources = other->TraceOnlyThisSources; + + this->TraceRedirect = other; +} + bool cmake::SetDirectoriesFromFile(const std::string& arg) { // Check if the argument refers to a CMakeCache.txt or @@ -2010,12 +2135,10 @@ int cmake::HandleDeleteCacheVariables(const std::string& var) } std::vector<SaveCacheEntry> saved; std::ostringstream warning; - /* clang-format off */ warning << "You have changed variables that require your cache to be deleted.\n" - << "Configure will be re-run and you may have to reset some variables.\n" - << "The following variables have changed:\n"; - /* clang-format on */ + "Configure will be re-run and you may have to reset some variables.\n" + "The following variables have changed:\n"; for (auto i = argsSplit.begin(); i != argsSplit.end(); ++i) { SaveCacheEntry save; save.key = *i; @@ -2023,9 +2146,9 @@ int cmake::HandleDeleteCacheVariables(const std::string& var) i++; if (i != argsSplit.end()) { save.value = *i; - warning << *i << "\n"; + warning << *i << '\n'; } else { - warning << "\n"; + warning << '\n'; i -= 1; } cmValue existingValue = this->State->GetCacheEntryValue(save.key); @@ -2060,6 +2183,10 @@ int cmake::HandleDeleteCacheVariables(const std::string& var) int cmake::Configure() { +#if !defined(CMAKE_BOOTSTRAP) + auto profilingRAII = this->CreateProfilingEntry("project", "configure"); +#endif + DiagLevel diagLevel; if (this->DiagLevels.count("deprecated") == 1) { @@ -2297,10 +2424,22 @@ int cmake::ActualConfigure() #if !defined(CMAKE_BOOTSTRAP) this->FileAPI = cm::make_unique<cmFileAPI>(this); this->FileAPI->ReadQueries(); + + if (!this->GetIsInTryCompile()) { + this->TruncateOutputLog("CMakeConfigureLog.yaml"); + this->ConfigureLog = cm::make_unique<cmConfigureLog>( + cmStrCat(this->GetHomeOutputDirectory(), "/CMakeFiles"_s), + this->FileAPI->GetConfigureLogVersions()); + } #endif // actually do the configure this->GlobalGenerator->Configure(); + +#if !defined(CMAKE_BOOTSTRAP) + this->ConfigureLog.reset(); +#endif + // Before saving the cache // if the project did not define one of the entries below, add them now // so users can edit the values in the cache: @@ -2423,7 +2562,7 @@ void cmake::CreateDefaultGlobalGenerator() auto gen = this->EvaluateDefaultGlobalGenerator(); #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(CMAKE_BOOT_MINGW) // This print could be unified for all platforms - std::cout << "-- Building for: " << gen->GetName() << "\n"; + std::cout << "-- Building for: " << gen->GetName() << '\n'; #endif this->SetGlobalGenerator(std::move(gen)); } @@ -2572,12 +2711,17 @@ int cmake::Generate() if (!this->GlobalGenerator) { return -1; } + +#if !defined(CMAKE_BOOTSTRAP) + auto profilingRAII = this->CreateProfilingEntry("project", "generate"); +#endif + if (!this->GlobalGenerator->Compute()) { return -1; } this->GlobalGenerator->Generate(); if (!this->GraphVizFile.empty()) { - std::cout << "Generate graphviz: " << this->GraphVizFile << std::endl; + std::cout << "Generate graphviz: " << this->GraphVizFile << '\n'; this->GenerateGraphViz(this->GraphVizFile); } if (this->WarnUnusedCli) { @@ -2818,17 +2962,15 @@ void cmake::AppendGlobalGeneratorsDocumentation( std::vector<cmDocumentationEntry>& v) { const auto defaultGenerator = this->EvaluateDefaultGlobalGenerator(); - const std::string defaultName = defaultGenerator->GetName(); - bool foundDefaultOne = false; + const auto defaultName = defaultGenerator->GetName(); + auto foundDefaultOne = false; for (const auto& g : this->Generators) { - cmDocumentationEntry e; - g->GetDocumentation(e); - if (!foundDefaultOne && cmHasPrefix(e.Name, defaultName)) { - e.CustomNamePrefix = '*'; + v.emplace_back(g->GetDocumentation()); + if (!foundDefaultOne && cmHasPrefix(v.back().Name, defaultName)) { + v.back().CustomNamePrefix = '*'; foundDefaultOne = true; } - v.push_back(std::move(e)); } } @@ -2841,21 +2983,14 @@ void cmake::AppendExtraGeneratorsDocumentation( // Aliases: for (std::string const& a : eg->Aliases) { - cmDocumentationEntry e; - e.Name = a; - e.Brief = doc; - v.push_back(std::move(e)); + v.emplace_back(cmDocumentationEntry{ a, doc }); } // Full names: - const std::vector<std::string> generators = - eg->GetSupportedGlobalGenerators(); - for (std::string const& g : generators) { - cmDocumentationEntry e; - e.Name = - cmExternalMakefileProjectGenerator::CreateFullGeneratorName(g, name); - e.Brief = doc; - v.push_back(std::move(e)); + for (std::string const& g : eg->GetSupportedGlobalGenerators()) { + v.emplace_back(cmDocumentationEntry{ + cmExternalMakefileProjectGenerator::CreateFullGeneratorName(g, name), + doc }); } } } @@ -2874,7 +3009,7 @@ void cmake::PrintGeneratorList() cmDocumentation doc; auto generators = this->GetGeneratorsDocumentation(); doc.AppendSection("Generators", generators); - std::cerr << "\n"; + std::cerr << '\n'; doc.PrintDocumentation(cmDocumentation::ListGenerators, std::cerr); #endif } @@ -2926,7 +3061,7 @@ int cmake::CheckBuildSystem() if (verbose) { std::ostringstream msg; msg << "Re-run cmake missing file: " << this->CheckBuildSystemArgument - << "\n"; + << '\n'; cmSystemTools::Stdout(msg.str()); } return 1; @@ -2946,7 +3081,7 @@ int cmake::CheckBuildSystem() if (verbose) { std::ostringstream msg; msg << "Re-run cmake error reading : " << this->CheckBuildSystemArgument - << "\n"; + << '\n'; cmSystemTools::Stdout(msg.str()); } // There was an error reading the file. Just rerun. @@ -2977,9 +3112,8 @@ int cmake::CheckBuildSystem() for (std::string const& p : products) { if (!(cmSystemTools::FileExists(p) || cmSystemTools::FileIsSymlink(p))) { if (verbose) { - std::ostringstream msg; - msg << "Re-run cmake, missing byproduct: " << p << "\n"; - cmSystemTools::Stdout(msg.str()); + cmSystemTools::Stdout( + cmStrCat("Re-run cmake, missing byproduct: ", p, '\n')); } return 1; } @@ -3044,7 +3178,7 @@ int cmake::CheckBuildSystem() if (verbose) { std::ostringstream msg; msg << "Re-run cmake file: " << out_oldest - << " older than: " << dep_newest << "\n"; + << " older than: " << dep_newest << '\n'; cmSystemTools::Stdout(msg.str()); } return 1; @@ -3220,7 +3354,7 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) // permissions are questionable or some other process has deleted the // directory std::cerr << "Failed to change to directory " << destPath << " : " - << std::strerror(workdir.GetLastResult()) << std::endl; + << std::strerror(workdir.GetLastResult()) << '\n'; return 1; } std::vector<std::string> args2; @@ -3257,96 +3391,6 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) return 0; } -static bool cmakeCheckStampFile(const std::string& stampName) -{ - // The stamp file does not exist. Use the stamp dependencies to - // determine whether it is really out of date. This works in - // conjunction with cmLocalVisualStudio7Generator to avoid - // repeatedly re-running CMake when the user rebuilds the entire - // solution. - std::string stampDepends = cmStrCat(stampName, ".depend"); -#if defined(_WIN32) || defined(__CYGWIN__) - cmsys::ifstream fin(stampDepends.c_str(), std::ios::in | std::ios::binary); -#else - cmsys::ifstream fin(stampDepends.c_str()); -#endif - if (!fin) { - // The stamp dependencies file cannot be read. Just assume the - // build system is really out of date. - std::cout << "CMake is re-running because " << stampName - << " dependency file is missing.\n"; - return false; - } - - // Compare the stamp dependencies against the dependency file itself. - { - cmFileTimeCache ftc; - std::string dep; - while (cmSystemTools::GetLineFromStream(fin, dep)) { - int result; - if (!dep.empty() && dep[0] != '#' && - (!ftc.Compare(stampDepends, dep, &result) || result < 0)) { - // The stamp depends file is older than this dependency. The - // build system is really out of date. - std::cout << "CMake is re-running because " << stampName - << " is out-of-date.\n"; - std::cout << " the file '" << dep << "'\n"; - std::cout << " is newer than '" << stampDepends << "'\n"; - std::cout << " result='" << result << "'\n"; - return false; - } - } - } - - // The build system is up to date. The stamp file has been removed - // by the VS IDE due to a "rebuild" request. Restore it atomically. - std::ostringstream stampTempStream; - stampTempStream << stampName << ".tmp" << cmSystemTools::RandomSeed(); - std::string stampTemp = stampTempStream.str(); - { - // TODO: Teach cmGeneratedFileStream to use a random temp file (with - // multiple tries in unlikely case of conflict) and use that here. - cmsys::ofstream stamp(stampTemp.c_str()); - stamp << "# CMake generation timestamp file for this directory.\n"; - } - std::string err; - if (cmSystemTools::RenameFile(stampTemp, stampName, - cmSystemTools::Replace::Yes, &err) == - cmSystemTools::RenameResult::Success) { - // CMake does not need to re-run because the stamp file is up-to-date. - return true; - } - cmSystemTools::RemoveFile(stampTemp); - cmSystemTools::Error( - cmStrCat("Cannot restore timestamp \"", stampName, "\": ", err)); - return false; -} - -static bool cmakeCheckStampList(const std::string& stampList) -{ - // If the stamp list does not exist CMake must rerun to generate it. - if (!cmSystemTools::FileExists(stampList)) { - std::cout << "CMake is re-running because generate.stamp.list " - << "is missing.\n"; - return false; - } - cmsys::ifstream fin(stampList.c_str()); - if (!fin) { - std::cout << "CMake is re-running because generate.stamp.list " - << "could not be read.\n"; - return false; - } - - // Check each stamp. - std::string stampName; - while (cmSystemTools::GetLineFromStream(fin, stampName)) { - if (!cmakeCheckStampFile(stampName)) { - return false; - } - } - return true; -} - void cmake::IssueMessage(MessageType t, std::string const& text, cmListFileBacktrace const& backtrace) const { diff --git a/Source/cmake.h b/Source/cmake.h index 3183577..10db87d 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -18,6 +18,7 @@ #include <cm/string_view> #include <cmext/string_view> +#include "cmDocumentationEntry.h" #include "cmGeneratedFileStream.h" #include "cmInstalledFile.h" #include "cmListFileCache.h" @@ -33,21 +34,19 @@ # include <cm3p/json/value.h> # include "cmCMakePresetsGraph.h" +# include "cmMakefileProfilingData.h" #endif +class cmConfigureLog; class cmExternalMakefileProjectGeneratorFactory; class cmFileAPI; class cmFileTimeCache; class cmGlobalGenerator; class cmGlobalGeneratorFactory; class cmMakefile; -#if !defined(CMAKE_BOOTSTRAP) -class cmMakefileProfilingData; -#endif class cmMessenger; class cmVariableWatch; struct cmBuildOptions; -struct cmDocumentationEntry; /** \brief Represents a cmake invocation. * @@ -513,10 +512,23 @@ public: { return this->TraceOnlyThisSources; } - cmGeneratedFileStream& GetTraceFile() { return this->TraceFile; } + cmGeneratedFileStream& GetTraceFile() + { + if (this->TraceRedirect) { + return this->TraceRedirect->GetTraceFile(); + } + return this->TraceFile; + } void SetTraceFile(std::string const& file); void PrintTraceFormatVersion(); +#ifndef CMAKE_BOOTSTRAP + cmConfigureLog* GetConfigureLog() const { return this->ConfigureLog.get(); } +#endif + + //! Use trace from another ::cmake instance. + void SetTraceRedirect(cmake* other); + bool GetWarnUninitialized() const { return this->WarnUninitialized; } void SetWarnUninitialized(bool b) { this->WarnUninitialized = b; } bool GetWarnUnusedCli() const { return this->WarnUnusedCli; } @@ -630,6 +642,24 @@ public: #if !defined(CMAKE_BOOTSTRAP) cmMakefileProfilingData& GetProfilingOutput(); bool IsProfilingEnabled() const; + + cm::optional<cmMakefileProfilingData::RAII> CreateProfilingEntry( + const std::string& category, const std::string& name) + { + return this->CreateProfilingEntry( + category, name, []() -> cm::nullopt_t { return cm::nullopt; }); + } + + template <typename ArgsFunc> + cm::optional<cmMakefileProfilingData::RAII> CreateProfilingEntry( + const std::string& category, const std::string& name, ArgsFunc&& argsFunc) + { + if (this->IsProfilingEnabled()) { + return cm::make_optional<cmMakefileProfilingData::RAII>( + this->GetProfilingOutput(), category, name, argsFunc()); + } + return cm::nullopt; + } #endif protected: @@ -688,6 +718,10 @@ private: bool TraceExpand = false; TraceFormat TraceFormatVar = TRACE_HUMAN; cmGeneratedFileStream TraceFile; + cmake* TraceRedirect = nullptr; +#ifndef CMAKE_BOOTSTRAP + std::unique_ptr<cmConfigureLog> ConfigureLog; +#endif bool WarnUninitialized = false; bool WarnUnusedCli = true; bool CheckSystemVars = false; @@ -767,37 +801,10 @@ private: #if !defined(CMAKE_BOOTSTRAP) std::unique_ptr<cmMakefileProfilingData> ProfilingOutput; #endif -}; -#define CMAKE_STANDARD_OPTIONS_TABLE \ - { "-S <path-to-source>", "Explicitly specify a source directory." }, \ - { "-B <path-to-build>", "Explicitly specify a build directory." }, \ - { "-C <initial-cache>", "Pre-load a script to populate the cache." }, \ - { "-D <var>[:<type>]=<value>", "Create or update a cmake cache entry." }, \ - { "-U <globbing_expr>", "Remove matching entries from CMake cache." }, \ - { "-G <generator-name>", "Specify a build system generator." }, \ - { "-T <toolset-name>", \ - "Specify toolset name if supported by generator." }, \ - { "-A <platform-name>", \ - "Specify platform name if supported by generator." }, \ - { "--toolchain <file>", \ - "Specify toolchain file [CMAKE_TOOLCHAIN_FILE]." }, \ - { "--install-prefix <directory>", \ - "Specify install directory [CMAKE_INSTALL_PREFIX]." }, \ - { "-Wdev", "Enable developer warnings." }, \ - { "-Wno-dev", "Suppress developer warnings." }, \ - { "-Werror=dev", "Make developer warnings errors." }, \ - { "-Wno-error=dev", "Make developer warnings not errors." }, \ - { "-Wdeprecated", "Enable deprecation warnings." }, \ - { "-Wno-deprecated", "Suppress deprecation warnings." }, \ - { "-Werror=deprecated", \ - "Make deprecated macro and function warnings " \ - "errors." }, \ - { \ - "-Wno-error=deprecated", \ - "Make deprecated macro and function warnings " \ - "not errors." \ - } +public: + static cmDocumentationEntry CMAKE_STANDARD_OPTIONS_TABLE[18]; +}; #define FOR_EACH_C90_FEATURE(F) F(c_function_prototypes) diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index 723932e..1e02412 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -24,7 +24,7 @@ #include "cmBuildOptions.h" #include "cmCommandLineArgument.h" #include "cmConsoleBuf.h" -#include "cmDocumentationEntry.h" // IWYU pragma: keep +#include "cmDocumentationEntry.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmMessageMetadata.h" @@ -46,30 +46,28 @@ namespace { #ifndef CMAKE_BOOTSTRAP -const char* cmDocumentationName[][2] = { - { nullptr, " cmake - Cross-Platform Makefile Generator." }, - { nullptr, nullptr } +const cmDocumentationEntry cmDocumentationName = { + {}, + " cmake - Cross-Platform Makefile Generator." }; -const char* cmDocumentationUsage[][2] = { - { nullptr, +const cmDocumentationEntry cmDocumentationUsage[2] = { + { {}, " cmake [options] <path-to-source>\n" " cmake [options] <path-to-existing-build>\n" " cmake [options] -S <path-to-source> -B <path-to-build>" }, - { nullptr, + { {}, "Specify a source directory to (re-)generate a build system for " "it in the current working directory. Specify an existing build " - "directory to re-generate its build system." }, - { nullptr, nullptr } + "directory to re-generate its build system." } }; -const char* cmDocumentationUsageNote[][2] = { - { nullptr, "Run 'cmake --help' for more information." }, - { nullptr, nullptr } +const cmDocumentationEntry cmDocumentationUsageNote = { + {}, + "Run 'cmake --help' for more information." }; -const char* cmDocumentationOptions[][2] = { - CMAKE_STANDARD_OPTIONS_TABLE, +const cmDocumentationEntry cmDocumentationOptions[31] = { { "--preset <preset>,--preset=<preset>", "Specify a configure preset." }, { "--list-presets[=<type>]", "List available presets." }, { "-E", "CMake command mode." }, @@ -113,15 +111,12 @@ const char* cmDocumentationOptions[][2] = { { "--compile-no-warning-as-error", "Ignore COMPILE_WARNING_AS_ERROR property and " "CMAKE_COMPILE_WARNING_AS_ERROR variable." }, -# if !defined(CMAKE_BOOTSTRAP) { "--profiling-format=<fmt>", "Output data for profiling CMake scripts. Supported formats: " "google-trace" }, { "--profiling-output=<file>", "Select an output path for the profiling data enabled through " - "--profiling-format." }, -# endif - { nullptr, nullptr } + "--profiling-format." } }; #endif @@ -208,7 +203,7 @@ int do_cmake(int ac, char const* const* av) doc.addCMakeStandardDocSections(); if (doc.CheckOptions(ac, av, "--")) { // Construct and print requested documentation. - cmake hcm(cmake::RoleInternal, cmState::Unknown); + cmake hcm(cmake::RoleInternal, cmState::Help); hcm.SetHomeDirectory(""); hcm.SetHomeOutputDirectory(""); hcm.AddCMakePaths(); @@ -228,8 +223,9 @@ int do_cmake(int ac, char const* const* av) } doc.AppendSection("Generators", generators); doc.PrependSection("Options", cmDocumentationOptions); + doc.PrependSection("Options", cmake::CMAKE_STANDARD_OPTIONS_TABLE); - return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1; + return !doc.PrintRequestedDocumentation(std::cout); } #else if (ac == 1) { @@ -315,6 +311,11 @@ int do_cmake(int ac, char const* const* av) } return 1; // failed to parse } + // Only in script mode do we stop parsing instead + // of preferring the last mode flag provided + if (arg == "--" && workingMode == cmake::SCRIPT_MODE) { + break; + } } if (!matched) { parsedArgs.emplace_back(av[i]); @@ -522,25 +523,8 @@ int do_build(int ac, char const* const* av) if (ac >= 3) { std::vector<std::string> inputArgs; - bool hasPreset = false; - for (int i = 2; i < ac; ++i) { - if (strcmp(av[i], "--list-presets") == 0 || - cmHasLiteralPrefix(av[i], "--preset=") || - strcmp(av[i], "--preset") == 0) { - hasPreset = true; - break; - } - } - - if (hasPreset) { - inputArgs.reserve(ac - 2); - cm::append(inputArgs, av + 2, av + ac); - } else { - dir = cmSystemTools::CollapseFullPath(av[2]); - - inputArgs.reserve(ac - 3); - cm::append(inputArgs, av + 3, av + ac); - } + inputArgs.reserve(ac - 2); + cm::append(inputArgs, av + 2, av + ac); decltype(inputArgs.size()) i = 0; for (; i < inputArgs.size() && !nativeOptionsPassed; ++i) { @@ -555,6 +539,11 @@ int do_build(int ac, char const* const* av) break; } } + if (!matched && i == 0) { + dir = cmSystemTools::CollapseFullPath(arg); + matched = true; + parsed = true; + } if (!(matched && parsed)) { dir.clear(); if (!matched) { diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 67394f9..4303f96 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -2,11 +2,15 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmcmd.h" +#include <functional> + +#include <cm/optional> #include <cmext/algorithm> #include <cm3p/uv.h> #include <fcntl.h> +#include "cmCommandLineArgument.h" #include "cmConsoleBuf.h" #include "cmDuration.h" #include "cmGlobalGenerator.h" @@ -363,6 +367,12 @@ int HandleTidy(const std::string& runCmd, const std::string& sourceFile, std::vector<std::string> tidy_cmd = cmExpandedList(runCmd, true); tidy_cmd.push_back(sourceFile); + for (auto const& arg : tidy_cmd) { + if (cmHasLiteralPrefix(arg, "--export-fixes=")) { + cmSystemTools::RemoveFile(arg.substr(cmStrLen("--export-fixes="))); + } + } + // clang-tidy supports working out the compile commands from a // compile_commands.json file in a directory given by a "-p" option, or by // passing the compiler command line arguments after --. When the latter @@ -640,20 +650,59 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, if (args.size() > 1) { // Copy file if (args[1] == "copy" && args.size() > 3) { + using CommandArgument = + cmCommandLineArgument<bool(const std::string& value)>; + + cm::optional<std::string> targetArg; + std::vector<CommandArgument> argParsers{ + { "-t", CommandArgument::Values::One, + CommandArgument::setToValue(targetArg) }, + }; + + std::vector<std::string> files; + for (decltype(args.size()) i = 2; i < args.size(); i++) { + const std::string& arg = args[i]; + bool matched = false; + for (auto const& m : argParsers) { + if (m.matches(arg)) { + matched = true; + if (m.parse(arg, i, args)) { + break; + } + return 1; // failed to parse + } + } + if (!matched) { + files.push_back(arg); + } + } + // If multiple source files specified, // then destination must be directory - if ((args.size() > 4) && - (!cmSystemTools::FileIsDirectory(args.back()))) { - std::cerr << "Error: Target (for copy command) \"" << args.back() + if (files.size() > 2 && !targetArg) { + targetArg = files.back(); + files.pop_back(); + } + if (targetArg && (!cmSystemTools::FileIsDirectory(*targetArg))) { + std::cerr << "Error: Target (for copy command) \"" << *targetArg << "\" is not a directory.\n"; return 1; } + if (!targetArg) { + if (files.size() < 2) { + std::cerr + << "Error: No files or target specified (for copy command).\n"; + return 1; + } + targetArg = files.back(); + files.pop_back(); + } // If error occurs we want to continue copying next files. bool return_value = false; - for (auto const& arg : cmMakeRange(args).advance(2).retreat(1)) { - if (!cmsys::SystemTools::CopyFileAlways(arg, args.back())) { - std::cerr << "Error copying file \"" << arg << "\" to \"" - << args.back() << "\".\n"; + for (auto const& file : files) { + if (!cmsys::SystemTools::CopyFileAlways(file, *targetArg)) { + std::cerr << "Error copying file \"" << file << "\" to \"" + << *targetArg << "\".\n"; return_value = true; } } diff --git a/Source/ctest.cxx b/Source/ctest.cxx index 363f473..fa38a65 100644 --- a/Source/ctest.cxx +++ b/Source/ctest.cxx @@ -11,21 +11,21 @@ #include "cmCTest.h" #include "cmConsoleBuf.h" #include "cmDocumentation.h" +#include "cmDocumentationEntry.h" #include "cmSystemTools.h" #include "CTest/cmCTestLaunch.h" #include "CTest/cmCTestScriptHandler.h" -static const char* cmDocumentationName[][2] = { - { nullptr, " ctest - Testing driver provided by CMake." }, - { nullptr, nullptr } +namespace { +const cmDocumentationEntry cmDocumentationName = { + {}, + " ctest - Testing driver provided by CMake." }; -static const char* cmDocumentationUsage[][2] = { { nullptr, - " ctest [options]" }, - { nullptr, nullptr } }; +const cmDocumentationEntry cmDocumentationUsage = { {}, " ctest [options]" }; -static const char* cmDocumentationOptions[][2] = { +const cmDocumentationEntry cmDocumentationOptions[74] = { { "--preset <preset>, --preset=<preset>", "Read arguments from a test preset." }, { "--list-presets", "List available test presets." }, @@ -155,9 +155,9 @@ static const char* cmDocumentationOptions[][2] = { { "--no-compress-output", "Do not compress test output when submitting." }, { "--print-labels", "Print all available test labels." }, { "--no-tests=<[error|ignore]>", - "Regard no tests found either as 'error' or 'ignore' it." }, - { nullptr, nullptr } + "Regard no tests found either as 'error' or 'ignore' it." } }; +} // anonymous namespace // this is a test driver program for cmCTest. int main(int argc, char const* const* argv) @@ -186,8 +186,7 @@ int main(int argc, char const* const* argv) if (cmSystemTools::GetCurrentWorkingDirectory().empty()) { cmCTestLog(&inst, ERROR_MESSAGE, - "Current working directory cannot be established." - << std::endl); + "Current working directory cannot be established.\n"); return 1; } @@ -199,10 +198,9 @@ int main(int argc, char const* const* argv) cmSystemTools::FileExists("DartTestfile.txt"))) { if (argc == 1) { cmCTestLog(&inst, ERROR_MESSAGE, - "*********************************" - << std::endl - << "No test configuration file found!" << std::endl - << "*********************************" << std::endl); + "*********************************\n" + "No test configuration file found!\n" + "*********************************\n"); } cmDocumentation doc; doc.addCTestStandardDocSections(); @@ -216,7 +214,7 @@ int main(int argc, char const* const* argv) doc.SetSection("Name", cmDocumentationName); doc.SetSection("Usage", cmDocumentationUsage); doc.PrependSection("Options", cmDocumentationOptions); - return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1; + return !doc.PrintRequestedDocumentation(std::cout); } } diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index 45a9e6f..b25b258 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -2011,6 +2011,14 @@ static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, return 0; } +#if defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wshorten-64-to-32") +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wshorten-64-to-32" +# define KWSYSPE_CLANG_DIAG_WSHORTEN +# endif +#endif + /* Get the length of time before the given timeout time arrives. Returns 1 if the time has already arrived, and 0 otherwise. */ static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime, @@ -2061,6 +2069,11 @@ static kwsysProcessTime kwsysProcessTimeGetCurrent(void) return current; } +#if defined(KWSYSPE_CLANG_DIAG_WSHORTEN) +# undef KWSYSPE_CLANG_DIAG_WSHORTEN +# pragma clang diagnostic pop +#endif + static double kwsysProcessTimeToDouble(kwsysProcessTime t) { return (double)t.tv_sec + (double)(t.tv_usec) * 0.000001; diff --git a/Source/kwsys/Status.hxx.in b/Source/kwsys/Status.hxx.in index 16efaef..7cef029 100644 --- a/Source/kwsys/Status.hxx.in +++ b/Source/kwsys/Status.hxx.in @@ -7,6 +7,16 @@ #include <string> +/* + * Detect a symbol collision with the name of this class. X11 headers use + * `#define Status int` instead of using `typedef` which poisons any other + * usage of this name. + */ +#if defined(Status) && defined(_X11_XLIB_H_) +# error \ + "Status.hxx must be included *before* any X11 headers to avoid a collision with the `Status` define that is made in its API." +#endif + namespace @KWSYS_NAMESPACE@ { /** \class Status diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx index e6cc48f..20e2edb 100644 --- a/Source/kwsys/SystemInformation.cxx +++ b/Source/kwsys/SystemInformation.cxx @@ -482,7 +482,7 @@ protected: unsigned int); // For windows // For Linux and Cygwin, /proc/cpuinfo formats are slightly different - bool RetreiveInformationFromCpuInfoFile(); + bool RetrieveInformationFromCpuInfoFile(); std::string ExtractValueFromCpuInfoFile(std::string buffer, const char* word, size_t init = 0); @@ -1520,7 +1520,7 @@ void SystemInformationImplementation::RunCPUCheck() #elif defined(__hpux) this->QueryHPUXProcessor(); #elif defined(__linux) || defined(__CYGWIN__) - this->RetreiveInformationFromCpuInfoFile(); + this->RetrieveInformationFromCpuInfoFile(); #else this->QueryProcessor(); #endif @@ -3435,7 +3435,7 @@ std::string SystemInformationImplementation::ExtractValueFromCpuInfoFile( } /** Query for the cpu status */ -bool SystemInformationImplementation::RetreiveInformationFromCpuInfoFile() +bool SystemInformationImplementation::RetrieveInformationFromCpuInfoFile() { this->NumberOfLogicalCPU = 0; this->NumberOfPhysicalCPU = 0; diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index a20901c..a3ab51a 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -36,6 +36,7 @@ #ifdef _WIN32 # include <cwchar> +# include <unordered_map> #endif // Work-around CMake dependency scanning limitation. This must @@ -506,16 +507,39 @@ public: }; #ifdef _WIN32 -struct SystemToolsPathCaseCmp +# if defined(_WIN64) +static constexpr size_t FNV_OFFSET_BASIS = 14695981039346656037ULL; +static constexpr size_t FNV_PRIME = 1099511628211ULL; +# else +static constexpr size_t FNV_OFFSET_BASIS = 2166136261U; +static constexpr size_t FNV_PRIME = 16777619U; +# endif + +// Case insensitive Fnv1a hash +struct SystemToolsPathCaseHash +{ + size_t operator()(std::string const& path) const + { + size_t hash = FNV_OFFSET_BASIS; + for (auto c : path) { + hash ^= static_cast<size_t>(std::tolower(c)); + hash *= FNV_PRIME; + } + + return hash; + } +}; + +struct SystemToolsPathCaseEqual { bool operator()(std::string const& l, std::string const& r) const { # ifdef _MSC_VER - return _stricmp(l.c_str(), r.c_str()) < 0; + return _stricmp(l.c_str(), r.c_str()) == 0; # elif defined(__GNUC__) - return strcasecmp(l.c_str(), r.c_str()) < 0; + return strcasecmp(l.c_str(), r.c_str()) == 0; # else - return SystemTools::Strucmp(l.c_str(), r.c_str()) < 0; + return SystemTools::Strucmp(l.c_str(), r.c_str()) == 0; # endif } }; @@ -540,8 +564,12 @@ public: bool const cache); static std::string GetActualCaseForPathCached(std::string const& path); static const char* GetEnvBuffered(const char* key); - std::map<std::string, std::string, SystemToolsPathCaseCmp> FindFileMap; - std::map<std::string, std::string, SystemToolsPathCaseCmp> PathCaseMap; + std::unordered_map<std::string, std::string, SystemToolsPathCaseHash, + SystemToolsPathCaseEqual> + FindFileMap; + std::unordered_map<std::string, std::string, SystemToolsPathCaseHash, + SystemToolsPathCaseEqual> + PathCaseMap; std::map<std::string, std::string> EnvMap; #endif #ifdef __CYGWIN__ @@ -2262,8 +2290,8 @@ static std::string FileInDir(const std::string& source, const std::string& dir) return new_destination + '/' + SystemTools::GetFilenameName(source); } -Status SystemTools::CopyFileIfDifferent(std::string const& source, - std::string const& destination) +SystemTools::CopyStatus SystemTools::CopyFileIfDifferent( + std::string const& source, std::string const& destination) { // special check for a destination that is a directory // FilesDiffer does not handle file to directory compare @@ -2280,7 +2308,7 @@ Status SystemTools::CopyFileIfDifferent(std::string const& source, } } // at this point the files must be the same so return true - return Status::Success(); + return CopyStatus{ Status::Success(), CopyStatus::NoPath }; } #define KWSYS_ST_BUFFER 4096 @@ -2406,13 +2434,13 @@ bool SystemTools::TextFilesDiffer(const std::string& path1, return false; } -Status SystemTools::CopyFileContentBlockwise(std::string const& source, - std::string const& destination) +SystemTools::CopyStatus SystemTools::CopyFileContentBlockwise( + std::string const& source, std::string const& destination) { // Open files kwsys::ifstream fin(source.c_str(), std::ios::in | std::ios::binary); if (!fin) { - return Status::POSIX_errno(); + return CopyStatus{ Status::POSIX_errno(), CopyStatus::SourcePath }; } // try and remove the destination file so that read only destination files @@ -2424,7 +2452,7 @@ Status SystemTools::CopyFileContentBlockwise(std::string const& source, kwsys::ofstream fout(destination.c_str(), std::ios::out | std::ios::trunc | std::ios::binary); if (!fout) { - return Status::POSIX_errno(); + return CopyStatus{ Status::POSIX_errno(), CopyStatus::DestPath }; } // This copy loop is very sensitive on certain platforms with @@ -2453,10 +2481,10 @@ Status SystemTools::CopyFileContentBlockwise(std::string const& source, fout.close(); if (!fout) { - return Status::POSIX_errno(); + return CopyStatus{ Status::POSIX_errno(), CopyStatus::DestPath }; } - return Status::Success(); + return CopyStatus{ Status::Success(), CopyStatus::NoPath }; } /** @@ -2471,13 +2499,13 @@ Status SystemTools::CopyFileContentBlockwise(std::string const& source, * - The underlying filesystem does not support file cloning * - An unspecified error occurred */ -Status SystemTools::CloneFileContent(std::string const& source, - std::string const& destination) +SystemTools::CopyStatus SystemTools::CloneFileContent( + std::string const& source, std::string const& destination) { #if defined(__linux) && defined(FICLONE) int in = open(source.c_str(), O_RDONLY); if (in < 0) { - return Status::POSIX_errno(); + return CopyStatus{ Status::POSIX_errno(), CopyStatus::SourcePath }; } SystemTools::RemoveFile(destination); @@ -2485,14 +2513,14 @@ Status SystemTools::CloneFileContent(std::string const& source, int out = open(destination.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (out < 0) { - Status status = Status::POSIX_errno(); + CopyStatus status{ Status::POSIX_errno(), CopyStatus::DestPath }; close(in); return status; } - Status status = Status::Success(); + CopyStatus status{ Status::Success(), CopyStatus::NoPath }; if (ioctl(out, FICLONE, in) < 0) { - status = Status::POSIX_errno(); + status = CopyStatus{ Status::POSIX_errno(), CopyStatus::NoPath }; } close(in); close(out); @@ -2504,40 +2532,41 @@ Status SystemTools::CloneFileContent(std::string const& source, // be updated by `copy_file_if_different` and `copy_file`. if (copyfile(source.c_str(), destination.c_str(), nullptr, COPYFILE_METADATA | COPYFILE_CLONE) < 0) { - return Status::POSIX_errno(); + return CopyStatus{ Status::POSIX_errno(), CopyStatus::NoPath }; } # if KWSYS_CXX_HAS_UTIMENSAT // utimensat is only available on newer Unixes and macOS 10.13+ if (utimensat(AT_FDCWD, destination.c_str(), nullptr, 0) < 0) { - return Status::POSIX_errno(); + return CopyStatus{ Status::POSIX_errno(), CopyStatus::DestPath }; } # else // fall back to utimes if (utimes(destination.c_str(), nullptr) < 0) { - return Status::POSIX_errno(); + return CopyStatus{ Status::POSIX_errno(), CopyStatus::DestPath }; } # endif - return Status::Success(); + return CopyStatus{ Status::Success(), CopyStatus::NoPath }; #else (void)source; (void)destination; - return Status::POSIX(ENOSYS); + return CopyStatus{ Status::POSIX(ENOSYS), CopyStatus::NoPath }; #endif } /** * Copy a file named by "source" to the file named by "destination". */ -Status SystemTools::CopyFileAlways(std::string const& source, - std::string const& destination) +SystemTools::CopyStatus SystemTools::CopyFileAlways( + std::string const& source, std::string const& destination) { - Status status; + CopyStatus status; mode_t perm = 0; Status perms = SystemTools::GetPermissions(source, perm); std::string real_destination = destination; if (SystemTools::FileIsDirectory(source)) { - status = SystemTools::MakeDirectory(destination); + status = CopyStatus{ SystemTools::MakeDirectory(destination), + CopyStatus::DestPath }; if (!status.IsSuccess()) { return status; } @@ -2562,7 +2591,8 @@ Status SystemTools::CopyFileAlways(std::string const& source, // Create destination directory if (!destination_dir.empty()) { - status = SystemTools::MakeDirectory(destination_dir); + status = CopyStatus{ SystemTools::MakeDirectory(destination_dir), + CopyStatus::DestPath }; if (!status.IsSuccess()) { return status; } @@ -2578,13 +2608,15 @@ Status SystemTools::CopyFileAlways(std::string const& source, } } if (perms) { - status = SystemTools::SetPermissions(real_destination, perm); + status = CopyStatus{ SystemTools::SetPermissions(real_destination, perm), + CopyStatus::DestPath }; } return status; } -Status SystemTools::CopyAFile(std::string const& source, - std::string const& destination, bool always) +SystemTools::CopyStatus SystemTools::CopyAFile(std::string const& source, + std::string const& destination, + bool always) { if (always) { return SystemTools::CopyFileAlways(source, destination); diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index acce015..56b65fd 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -566,11 +566,34 @@ public: const mode_t* mode = nullptr); /** + * Represent the result of a file copy operation. + * This is the result 'Status' and, if the operation failed, + * an indication of whether the error occurred on the source + * or destination path. + */ + struct CopyStatus : public Status + { + enum WhichPath + { + NoPath, + SourcePath, + DestPath, + }; + CopyStatus() = default; + CopyStatus(Status s, WhichPath p) + : Status(s) + , Path(p) + { + } + WhichPath Path = NoPath; + }; + + /** * Copy the source file to the destination file only * if the two files differ. */ - static Status CopyFileIfDifferent(std::string const& source, - std::string const& destination); + static CopyStatus CopyFileIfDifferent(std::string const& source, + std::string const& destination); /** * Compare the contents of two files. Return true if different @@ -588,13 +611,13 @@ public: /** * Blockwise copy source to destination file */ - static Status CopyFileContentBlockwise(std::string const& source, - std::string const& destination); + static CopyStatus CopyFileContentBlockwise(std::string const& source, + std::string const& destination); /** * Clone the source file to the destination file */ - static Status CloneFileContent(std::string const& source, - std::string const& destination); + static CopyStatus CloneFileContent(std::string const& source, + std::string const& destination); /** * Return true if the two files are the same file @@ -604,16 +627,17 @@ public: /** * Copy a file. */ - static Status CopyFileAlways(std::string const& source, - std::string const& destination); + static CopyStatus CopyFileAlways(std::string const& source, + std::string const& destination); /** * Copy a file. If the "always" argument is true the file is always * copied. If it is false, the file is copied only if it is new or * has changed. */ - static Status CopyAFile(std::string const& source, - std::string const& destination, bool always = true); + static CopyStatus CopyAFile(std::string const& source, + std::string const& destination, + bool always = true); /** * Copy content directory to another directory with all files and |